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

Xcm trap assets ed #1654

Merged
merged 9 commits into from
Dec 1, 2021
Merged
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
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion runtime/acala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub use primitives::{
AuctionId, AuthoritysOriginId, Balance, BlockNumber, CurrencyId, DataProviderId, EraIndex, Hash, Moment, Nonce,
ReserveIdentifier, Share, Signature, TokenSymbol, TradingPair,
};
use runtime_common::AcalaDropAssets;
pub use runtime_common::{
cent, dollar, microcent, millicent, EnsureRootOrAllGeneralCouncil, EnsureRootOrAllTechnicalCommittee,
EnsureRootOrHalfFinancialCouncil, EnsureRootOrHalfGeneralCouncil, EnsureRootOrHalfHomaCouncil,
Expand Down Expand Up @@ -1450,7 +1451,14 @@ impl xcm_executor::Config for XcmConfig {
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
type Trader = Trader;
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetTrap = AcalaDropAssets<
PolkadotXcm,
ToTreasury,
CurrencyIdConvert,
GetNativeCurrencyId,
NativeTokenExistentialDeposit,
ExistentialDeposits,
>;
type AssetClaims = PolkadotXcm;
type SubscriptionService = PolkadotXcm;
}
Expand Down
8 changes: 8 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ module-transaction-payment = { path = "../../modules/transaction-payment", defau
module-nft = { path = "../../modules/nft", default-features = false }
module-dex = { path = "../../modules/dex", default-features = false }

xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.12", default-features = false }
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.12", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.12", default-features = false }

[dev-dependencies]
serde_json = "1.0.64"
hex-literal = "0.3.1"
Expand Down Expand Up @@ -87,6 +91,10 @@ std = [
"module-transaction-payment/std",
"module-nft/std",
"module-dex/std",

"xcm/std",
"xcm-executor/std",
"xcm-builder/std",
]
with-ethereum-compatibility = [
"module-evm/with-ethereum-compatibility",
Expand Down
73 changes: 73 additions & 0 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#![cfg_attr(not(feature = "std"), no_std)]

use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::traits::Get;
use frame_support::{
parameter_types,
traits::Contains,
Expand Down Expand Up @@ -49,6 +50,7 @@ mod homa;
pub use homa::*;

pub mod precompile;
use orml_traits::GetByKey;
pub use precompile::{
AllPrecompiles, DexPrecompile, MultiCurrencyPrecompile, NFTPrecompile, OraclePrecompile, ScheduleCallPrecompile,
StateRentPrecompile,
Expand All @@ -57,6 +59,10 @@ pub use primitives::{
currency::{TokenInfo, ACA, AUSD, BNC, DOT, KAR, KSM, KUSD, LDOT, LKSM, PHA, RENBTC, VSKSM},
AccountId,
};
use sp_std::{marker::PhantomData, prelude::*};
pub use xcm::latest::prelude::*;
pub use xcm_builder::TakeRevenue;
pub use xcm_executor::{traits::DropAssets, Assets};

pub type TimeStampedPrice = orml_oracle::TimestampedValue<Price, primitives::Moment>;

Expand Down Expand Up @@ -331,6 +337,73 @@ pub enum RelayChainSubAccountId {
HomaLite = 0,
}

/// `DropAssets` implementation support asset amount lower thant ED handled by `TakeRevenue`.
///
/// parameters type:
/// - `NC`: native currency_id type.
/// - `NB`: the ExistentialDeposit amount of native currency_id.
/// - `GK`: the ExistentialDeposit amount of tokens.
pub struct AcalaDropAssets<X, T, C, NC, NB, GK>(PhantomData<(X, T, C, NC, NB, GK)>);
zqhxuyuan marked this conversation as resolved.
Show resolved Hide resolved
impl<X, T, C, NC, NB, GK> DropAssets for AcalaDropAssets<X, T, C, NC, NB, GK>
where
X: DropAssets,
T: TakeRevenue,
C: Convert<MultiLocation, Option<CurrencyId>>,
NC: Get<CurrencyId>,
NB: Get<Balance>,
GK: GetByKey<CurrencyId, Balance>,
{
fn drop_assets(origin: &MultiLocation, assets: Assets) -> Weight {
let multi_assets: Vec<MultiAsset> = assets.into();
let mut asset_traps: Vec<MultiAsset> = vec![];
for asset in multi_assets {
if let MultiAsset {
id: Concrete(location),
fun: Fungible(amount),
} = asset.clone()
{
let currency_id = C::convert(location);
// burn asset(do nothing here) if convert result is None
if let Some(currency_id) = currency_id {
let ed = ExistentialDepositsForDropAssets::<NC, NB, GK>::get(&currency_id);
if amount < ed {
T::take_revenue(asset);
} else {
asset_traps.push(asset);
}
}
}
}
if !asset_traps.is_empty() {
X::drop_assets(origin, asset_traps.into());
}
0
}
}

/// `ExistentialDeposit` for tokens, give priority to match native token, then handled by
/// `ExistentialDeposits`.
///
/// parameters type:
/// - `NC`: native currency_id type.
/// - `NB`: the ExistentialDeposit amount of native currency_id.
/// - `GK`: the ExistentialDeposit amount of tokens.
pub struct ExistentialDepositsForDropAssets<NC, NB, GK>(PhantomData<(NC, NB, GK)>);
impl<NC, NB, GK> ExistentialDepositsForDropAssets<NC, NB, GK>
where
NC: Get<CurrencyId>,
NB: Get<Balance>,
GK: GetByKey<CurrencyId, Balance>,
{
fn get(currency_id: &CurrencyId) -> Balance {
if currency_id == &NC::get() {
NB::get()
} else {
GK::get(currency_id)
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::setup::*;

use frame_support::assert_ok;

use karura_runtime::AssetRegistry;
use karura_runtime::{AssetRegistry, KaruraTreasuryAccount};
use module_asset_registry::AssetMetadata;
use orml_traits::MultiCurrency;
use xcm_emulator::TestExt;
Expand Down Expand Up @@ -475,3 +475,178 @@ fn test_asset_registry_module() {
);
});
}

#[test]
fn trap_assets_larger_than_ed_works() {
TestNet::reset();

let mut kar_treasury_amount = 0;
let (ksm_asset_amount, kar_asset_amount) = (dollar(KSM), dollar(KAR));
let trader_weight_to_treasury: u128 = 96_000_000;

Karura::execute_with(|| {
assert_ok!(Tokens::deposit(KSM, &AccountId::from(DEFAULT), 100 * dollar(KSM)));
let _ = pallet_balances::Pallet::<Runtime>::deposit_creating(&AccountId::from(DEFAULT), 100 * dollar(KAR));

kar_treasury_amount = Currencies::free_balance(KAR, &KaruraTreasuryAccount::get());
});

let assets: MultiAsset = (Parent, ksm_asset_amount).into();
KusamaNet::execute_with(|| {
let xcm = vec![
WithdrawAsset(assets.clone().into()),
BuyExecution {
fees: assets,
weight_limit: Limited(dollar(KSM) as u64),
},
WithdrawAsset(
(
(Parent, X2(Parachain(2000), GeneralKey(KAR.encode()))),
kar_asset_amount,
)
.into(),
),
];
assert_ok!(pallet_xcm::Pallet::<kusama_runtime::Runtime>::send_xcm(
Here,
Parachain(2000).into(),
Xcm(xcm),
));
});
Karura::execute_with(|| {
assert!(System::events()
.iter()
.any(|r| matches!(r.event, Event::PolkadotXcm(pallet_xcm::Event::AssetsTrapped(_, _, _)))));

assert_eq!(
trader_weight_to_treasury,
Currencies::free_balance(KSM, &KaruraTreasuryAccount::get())
);
assert_eq!(
kar_treasury_amount,
Currencies::free_balance(KAR, &KaruraTreasuryAccount::get())
);
});
}

#[test]
fn trap_assets_lower_than_ed_works() {
TestNet::reset();

let mut kar_treasury_amount = 0;
let (ksm_asset_amount, kar_asset_amount) = (cent(KSM) / 100, cent(KAR));

Karura::execute_with(|| {
assert_ok!(Tokens::deposit(KSM, &AccountId::from(DEFAULT), dollar(KSM)));
let _ = pallet_balances::Pallet::<Runtime>::deposit_creating(&AccountId::from(DEFAULT), dollar(KAR));
kar_treasury_amount = Currencies::free_balance(KAR, &KaruraTreasuryAccount::get());
});

let assets: MultiAsset = (Parent, ksm_asset_amount).into();
KusamaNet::execute_with(|| {
let xcm = vec![
WithdrawAsset(assets.clone().into()),
BuyExecution {
fees: assets,
weight_limit: Limited(dollar(KSM) as u64),
},
WithdrawAsset(
(
(Parent, X2(Parachain(2000), GeneralKey(KAR.encode()))),
kar_asset_amount,
)
.into(),
),
// two asset left in holding register, they both lower than ED, so goes to treasury.
];
assert_ok!(pallet_xcm::Pallet::<kusama_runtime::Runtime>::send_xcm(
Here,
Parachain(2000).into(),
Xcm(xcm),
));
});

Karura::execute_with(|| {
assert_eq!(
System::events()
.iter()
.find(|r| matches!(r.event, Event::PolkadotXcm(pallet_xcm::Event::AssetsTrapped(_, _, _)))),
None
);

assert_eq!(
ksm_asset_amount,
Currencies::free_balance(KSM, &KaruraTreasuryAccount::get())
);
assert_eq!(
kar_asset_amount,
Currencies::free_balance(KAR, &KaruraTreasuryAccount::get()) - kar_treasury_amount
);
});
}

#[test]
fn sibling_trap_assets_works() {
TestNet::reset();

let mut kar_treasury_amount = 0;
let (bnc_asset_amount, kar_asset_amount) = (cent(BNC) / 10, cent(KAR));

fn sibling_account() -> AccountId {
use sp_runtime::traits::AccountIdConversion;
polkadot_parachain::primitives::Sibling::from(2001).into_account()
}

Karura::execute_with(|| {
assert_ok!(Tokens::deposit(BNC, &sibling_account(), dollar(BNC)));
let _ = pallet_balances::Pallet::<Runtime>::deposit_creating(&sibling_account(), dollar(KAR));
kar_treasury_amount = Currencies::free_balance(KAR, &KaruraTreasuryAccount::get());
});

Sibling::execute_with(|| {
let assets: MultiAsset = (
(Parent, X2(Parachain(2000), GeneralKey(KAR.encode()))),
kar_asset_amount,
)
.into();
let xcm = vec![
WithdrawAsset(assets.clone().into()),
BuyExecution {
fees: assets,
weight_limit: Unlimited,
},
WithdrawAsset(
(
(
Parent,
X2(Parachain(2001), GeneralKey(parachains::bifrost::BNC_KEY.to_vec())),
),
bnc_asset_amount,
)
.into(),
),
];
assert_ok!(pallet_xcm::Pallet::<Runtime>::send_xcm(
Here,
(Parent, Parachain(2000)),
Xcm(xcm),
));
});

Karura::execute_with(|| {
assert_eq!(
System::events()
.iter()
.find(|r| matches!(r.event, Event::PolkadotXcm(pallet_xcm::Event::AssetsTrapped(_, _, _)))),
None
);
assert_eq!(
Currencies::free_balance(KAR, &KaruraTreasuryAccount::get()) - kar_treasury_amount,
kar_asset_amount
);
assert_eq!(
Currencies::free_balance(BNC, &KaruraTreasuryAccount::get()),
bnc_asset_amount
);
});
}
1 change: 1 addition & 0 deletions runtime/integration-tests/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const ORACLE3: [u8; 32] = [2u8; 32];
const ORACLE4: [u8; 32] = [3u8; 32];
const ORACLE5: [u8; 32] = [4u8; 32];

pub const DEFAULT: [u8; 32] = [0u8; 32];
pub const ALICE: [u8; 32] = [4u8; 32];
pub const BOB: [u8; 32] = [5u8; 32];
pub const CHARLIE: [u8; 32] = [6u8; 32];
Expand Down
10 changes: 9 additions & 1 deletion runtime/karura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub use primitives::{
AuctionId, AuthoritysOriginId, Balance, BlockNumber, CurrencyId, DataProviderId, EraIndex, Hash, Moment, Nonce,
ReserveIdentifier, Share, Signature, TokenSymbol, TradingPair,
};
use runtime_common::AcalaDropAssets;
pub use runtime_common::{
cent, dollar, microcent, millicent, EnsureRootOrAllGeneralCouncil, EnsureRootOrAllTechnicalCommittee,
EnsureRootOrHalfFinancialCouncil, EnsureRootOrHalfGeneralCouncil, EnsureRootOrHalfHomaCouncil,
Expand Down Expand Up @@ -1513,7 +1514,14 @@ impl xcm_executor::Config for XcmConfig {
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
type Trader = Trader;
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetTrap = AcalaDropAssets<
PolkadotXcm,
ToTreasury,
CurrencyIdConvert,
GetNativeCurrencyId,
NativeTokenExistentialDeposit,
ExistentialDeposits,
>;
type AssetClaims = PolkadotXcm;
type SubscriptionService = PolkadotXcm;
}
Expand Down
Loading