diff --git a/pallets/asset-handler/src/lib.rs b/pallets/asset-handler/src/lib.rs index 25c725d1d..5afdafa06 100644 --- a/pallets/asset-handler/src/lib.rs +++ b/pallets/asset-handler/src/lib.rs @@ -130,6 +130,13 @@ pub mod pallet { /// Parachain Network Id #[pallet::constant] type ParachainNetworkId: Get; + + /// Polkadex Asset + #[pallet::constant] + type PolkadexAssetId: Get; + + /// PDEX Token Holder Account + type PDEXHolderAccount: Get; } #[pallet::pallet] @@ -660,6 +667,40 @@ pub mod pallet { Ok(()) } + /// Asset Handler for Withdraw Extrinsic + /// # Parameters + /// + /// * `asset_id`: Asset Id. + /// * `who`: Asset Holder. + /// * `amount`: Amount to be burned/locked. + pub fn handle_asset( + asset_id: u128, + who: T::AccountId, + amount: u128, + ) -> Result<(), DispatchError> { + let polkadex_asset_id = T::PolkadexAssetId::get(); + if polkadex_asset_id == asset_id { + Self::lock_pdex_asset(amount, who) + } else { + Self::burn_thea_asset(asset_id, who, amount) + } + } + + /// Asset Locker + /// # Parameters + /// + /// * `amount`: Amount to be locked. + /// * `who`: Asset Holder. + pub fn lock_pdex_asset(amount: u128, who: T::AccountId) -> DispatchResult { + let polkadex_holder_account = T::PDEXHolderAccount::get(); + T::Currency::transfer( + &who, + &polkadex_holder_account, + amount.saturated_into(), + ExistenceRequirement::AllowDeath, + ) + } + pub fn burn_thea_asset( asset_id: u128, who: T::AccountId, diff --git a/pallets/asset-handler/src/mock.rs b/pallets/asset-handler/src/mock.rs index 48f0b0577..7e2aecbb2 100644 --- a/pallets/asset-handler/src/mock.rs +++ b/pallets/asset-handler/src/mock.rs @@ -145,6 +145,11 @@ impl chainbridge::Config for Test { //type PalletId = ChainbridgePalletId; } +parameter_types! { + pub const PolkadexAssetId: u128 = 1000; + pub const PDEXHolderAccount: u64 = 10u64; +} + impl asset_handler::Config for Test { type Event = Event; type Currency = Balances; @@ -153,6 +158,8 @@ impl asset_handler::Config for Test { type TreasuryPalletId = ChainbridgePalletId; type WeightInfo = crate::weights::WeightInfo; type ParachainNetworkId = ParachainNetworkId; + type PolkadexAssetId = PolkadexAssetId; + type PDEXHolderAccount = PDEXHolderAccount; } // Build genesis storage according to the mock runtime. diff --git a/pallets/thea-staking/src/mock.rs b/pallets/thea-staking/src/mock.rs index ac37f3d80..ccb4e824d 100644 --- a/pallets/thea-staking/src/mock.rs +++ b/pallets/thea-staking/src/mock.rs @@ -113,6 +113,11 @@ impl chainbridge::Config for Test { type ProposalLifetime = ProposalLifetime; } +parameter_types! { + pub const PolkadexAssetId: u128 = 1000; + pub const PDEXHolderAccount: u64 = 10u64; +} + impl asset_handler::pallet::Config for Test { type Event = Event; type Currency = Balances; @@ -121,11 +126,14 @@ impl asset_handler::pallet::Config for Test { type TreasuryPalletId = ChainbridgePalletId; type WeightInfo = asset_handler::weights::WeightInfo; type ParachainNetworkId = ParachainNetworkId; + type PolkadexAssetId = PolkadexAssetId; + type PDEXHolderAccount = PDEXHolderAccount; } parameter_types! { pub const TheaPalletId: PalletId = PalletId(*b"THBRIDGE"); pub const WithdrawalSize: u32 = 10; + pub const ParaId: u32 = 2040; } impl thea::pallet::Config for Test { @@ -134,6 +142,7 @@ impl thea::pallet::Config for Test { type AssetCreateUpdateOrigin = frame_system::EnsureSigned; type TheaPalletId = TheaPalletId; type WithdrawalSize = WithdrawalSize; + type ParaId = ParaId; } //defined trait for Session Change diff --git a/pallets/thea/src/lib.rs b/pallets/thea/src/lib.rs index fb3dca94d..28c5c993c 100644 --- a/pallets/thea/src/lib.rs +++ b/pallets/thea/src/lib.rs @@ -43,7 +43,7 @@ pub mod pallet { }; use thea_primitives::{ normal_deposit::Deposit, - parachain_primitives::{ParachainAsset, ParachainDeposit, ParachainWithdraw}, + parachain_primitives::{AssetType, ParachainAsset, ParachainDeposit, ParachainWithdraw}, thea_types::OnSessionChange, ApprovedWithdraw, AssetIdConverter, BLSPublicKey, TokenType, }; @@ -101,6 +101,8 @@ pub mod pallet { /// Total Withdrawals #[pallet::constant] type WithdrawalSize: Get; + /// Para Id + type ParaId: Get; } #[pallet::pallet] @@ -502,14 +504,16 @@ pub mod pallet { pay_for_remaining: bool, ) -> Result<(), DispatchError> { ensure!(beneficiary.len() <= 100, Error::::BeneficiaryTooLong); - // TODO: This will be refactored when work on withdrawal so not fixing clippy suggestion - let (network, ..) = asset_handler::pallet::Pallet::::get_thea_assets(asset_id); + let network = if asset_id == T::PolkadexAssetId::get() { + 1 + } else { + let (network, ..) = asset_handler::pallet::Pallet::::get_thea_assets(asset_id); + network + }; ensure!(network != 0, Error::::UnableFindNetworkForAssetId); let payload = Self::withdrawal_router(network, asset_id, amount, beneficiary.clone())?; let withdrawal_nonce = >::get(network); - let mut pending_withdrawals = >::get(network); - // Ensure pending withdrawals have space for a new withdrawal ensure!(!pending_withdrawals.is_full(), Error::::WithdrawalNotAllowed); @@ -536,10 +540,8 @@ pub mod pallet { )?; // TODO[#610]: Update Thea Staking pallet about fees collected - - // Burn assets - asset_handler::pallet::Pallet::::burn_thea_asset(asset_id, user.clone(), amount)?; - + // Handle assets + asset_handler::pallet::Pallet::::handle_asset(asset_id, user.clone(), amount)?; let withdrawal = ApprovedWithdraw { asset_id, amount: amount.saturated_into(), @@ -593,10 +595,21 @@ pub mod pallet { amount: u128, beneficiary: Vec, ) -> Result, DispatchError> { - let (_, _, asset_identifier) = asset_handler::pallet::TheaAssets::::get(asset_id); - let asset_identifier: ParachainAsset = - Decode::decode(&mut &asset_identifier.to_vec()[..]) - .map_err(|_| Error::::FailedToDecode)?; + let asset_identifier = if asset_id != T::PolkadexAssetId::get() { + let (_, _, asset_identifier) = + asset_handler::pallet::TheaAssets::::get(asset_id); + let asset_identifier: ParachainAsset = + Decode::decode(&mut &asset_identifier.to_vec()[..]) + .map_err(|_| Error::::FailedToDecode)?; + asset_identifier + } else { + let para_id = T::ParaId::get(); + let asset_location = MultiLocation { + parents: 1, + interior: Junctions::X1(Junction::Parachain(para_id)), + }; + ParachainAsset { location: asset_location, asset_type: AssetType::Fungible } + }; let asset_id = AssetId::Concrete(asset_identifier.location); let asset_and_amount = MultiAsset { id: asset_id, fun: Fungible(amount) }; let recipient: MultiLocation = Self::get_recipient(beneficiary)?; diff --git a/pallets/thea/src/mock.rs b/pallets/thea/src/mock.rs index 03c8413f7..b7b1ae575 100644 --- a/pallets/thea/src/mock.rs +++ b/pallets/thea/src/mock.rs @@ -28,6 +28,7 @@ use crate::pallet as thea; use asset_handler::pallet::WithdrawalLimit; use frame_support::PalletId; +use sp_core::crypto::AccountId32; use sp_runtime::traits::AccountIdConversion; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -148,6 +149,11 @@ impl chainbridge::Config for Test { //type PalletId = ChainbridgePalletId; } +parameter_types! { + pub const PolkadexAssetId: u128 = 1000; + pub const PDEXHolderAccount: u64 = 10u64; +} + impl asset_handler::pallet::Config for Test { type Event = Event; type Currency = Balances; @@ -156,11 +162,14 @@ impl asset_handler::pallet::Config for Test { type TreasuryPalletId = ChainbridgePalletId; type WeightInfo = asset_handler::weights::WeightInfo; type ParachainNetworkId = ParachainNetworkId; + type PolkadexAssetId = PolkadexAssetId; + type PDEXHolderAccount = PDEXHolderAccount; } parameter_types! { pub const TheaPalletId: PalletId = PalletId(*b"THBRIDGE"); pub const WithdrawalSize: u32 = 10; + pub const ParaId: u32 = 2040; } impl thea::Config for Test { @@ -169,6 +178,7 @@ impl thea::Config for Test { type AssetCreateUpdateOrigin = frame_system::EnsureSigned; type TheaPalletId = TheaPalletId; type WithdrawalSize = WithdrawalSize; + type ParaId = ParaId; } // Build genesis storage according to the mock runtime. diff --git a/pallets/thea/src/tests.rs b/pallets/thea/src/tests.rs index a7534a39b..768d94cfa 100644 --- a/pallets/thea/src/tests.rs +++ b/pallets/thea/src/tests.rs @@ -510,6 +510,50 @@ fn test_withdraw_with_no_fee_config() { }) } +#[test] +fn transfer_native_asset() { + new_test_ext().execute_with(|| { + let asset_id = 1000; + let para_id = 2040; + let multi_location = MultiLocation { + parents: 1, + interior: X1(Junction::AccountId32 { network: NetworkId::Any, id: [1; 32] }), + }; + let asset_location = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(para_id)) }; + let asset = MultiAsset { + id: AssetId::Concrete(asset_location), + fun: 10_000_000_000_000u128.into(), + }; + assert_ok!(Thea::set_withdrawal_fee(Origin::root(), 1, 0)); + let beneficiary: [u8; 32] = [1; 32]; + // Mint Asset to Alice + assert_ok!(pallet_balances::pallet::Pallet::::set_balance( + Origin::root(), + 1, + 1_000_000_000_000_000_000, + 0 + )); + assert_ok!(Thea::withdraw( + Origin::signed(1), + asset_id.clone(), + 10_000_000_000_000u128, + beneficiary.to_vec(), + false + )); + let pending_withdrawal = >::get(1); + let payload = ParachainWithdraw::get_parachain_withdraw(asset, multi_location); + let approved_withdraw = ApprovedWithdraw { + asset_id, + amount: 10_000_000_000_000u128, + network: 1, + beneficiary: vec![1; 32], + payload: payload.encode(), + }; + assert_eq!(pending_withdrawal.to_vec().pop().unwrap(), approved_withdraw); + }) +} + pub type PrivateKeys = Vec; pub type PublicKeys = Vec; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index d1035121a..579fb96f7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -252,6 +252,7 @@ parameter_types! { pub const MaxPending: u16 = 32; } use scale_info::TypeInfo; +use sp_core::crypto::AccountId32; use sp_npos_elections::ExtendedBalance; /// The type used to represent the kinds of proxying allowed. @@ -1288,6 +1289,12 @@ impl chainbridge::Config for Runtime { type ProposalLifetime = ProposalLifetime; } +parameter_types! { + pub const PolkadexAssetId: u128 = 1000; //TODO: Chnage Polkddex Asset ID + pub const PDEXHolderAccount: AccountId32 = AccountId32::new([1u8;32]); //TODO Chnage Holder Account + pub const ParaId: u32 = 2040; +} + impl asset_handler::pallet::Config for Runtime { type Event = Event; type Currency = Balances; @@ -1296,6 +1303,8 @@ impl asset_handler::pallet::Config for Runtime { type TreasuryPalletId = TreasuryPalletId; type WeightInfo = asset_handler::WeightInfo; type ParachainNetworkId = ParachainNetworkId; + type PolkadexAssetId = PolkadexAssetId; + type PDEXHolderAccount = PDEXHolderAccount; } impl thea::pallet::Config for Runtime { @@ -1304,6 +1313,7 @@ impl thea::pallet::Config for Runtime { type AssetCreateUpdateOrigin = EnsureRootOrHalfCouncil; type TheaPalletId = TheaPalletId; type WithdrawalSize = WithdrawalSize; + type ParaId = ParaId; } //Install Staking Pallet