Skip to content

Commit

Permalink
Support LCDOT for XCM (#2316)
Browse files Browse the repository at this point in the history
* Support LCDOT for XCM

* Apply review suggestions
  • Loading branch information
zjb0807 authored Aug 9, 2022
1 parent 02bd690 commit 2b8b053
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 7 deletions.
27 changes: 27 additions & 0 deletions modules/asset-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,33 @@ where
}
}

pub struct BuyWeightRateOfLiquidCrowdloan<T>(sp_std::marker::PhantomData<T>);

impl<T: Config> BuyWeightRate for BuyWeightRateOfLiquidCrowdloan<T>
where
BalanceOf<T>: Into<u128>,
{
fn calculate_rate(location: MultiLocation) -> Option<Ratio> {
let currency = key_to_currency(location);
match currency {
Some(CurrencyId::LiquidCrowdloan(lease)) => {
if let Some(asset_metadata) =
Pallet::<T>::asset_metadatas(AssetIds::NativeAssetId(CurrencyId::LiquidCrowdloan(lease)))
{
let minimum_balance = asset_metadata.minimal_balance.into();
let rate =
FixedU128::saturating_from_rational(minimum_balance, T::Currency::minimum_balance().into());
log::debug!(target: "asset-registry::weight", "LiquidCrowdloan: {}, MinimumBalance: {}, rate:{:?}", lease, minimum_balance, rate);
Some(rate)
} else {
None
}
}
_ => None,
}
}
}

pub struct BuyWeightRateOfStableAsset<T>(sp_std::marker::PhantomData<T>);

impl<T: Config> BuyWeightRate for BuyWeightRateOfStableAsset<T>
Expand Down
12 changes: 9 additions & 3 deletions runtime/acala/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ pub use frame_support::{
traits::{Everything, Get, Nothing},
weights::Weight,
};
use module_asset_registry::{BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset, BuyWeightRateOfStableAsset};
use module_asset_registry::{
BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset, BuyWeightRateOfLiquidCrowdloan, BuyWeightRateOfStableAsset,
};
use module_support::HomaSubAccountXcm;
use module_transaction_payment::BuyWeightRateOfTransactionFeePool;
use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency};
Expand Down Expand Up @@ -147,6 +149,7 @@ pub type Trader = (
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfForeignAsset<Runtime>>,
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfErc20<Runtime>>,
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfStableAsset<Runtime>>,
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfLiquidCrowdloan<Runtime>>,
FixedRateOfFungible<DotPerSecond, ToTreasury>,
FixedRateOfFungible<AusdPerSecond, ToTreasury>,
FixedRateOfFungible<TapPerSecond, ToTreasury>,
Expand Down Expand Up @@ -244,7 +247,7 @@ pub struct CurrencyIdConvert;
impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
fn convert(id: CurrencyId) -> Option<MultiLocation> {
use primitives::TokenSymbol::*;
use CurrencyId::{Erc20, ForeignAsset, StableAssetPoolToken, Token};
use CurrencyId::{Erc20, ForeignAsset, LiquidCrowdloan, StableAssetPoolToken, Token};
match id {
Token(DOT) => Some(MultiLocation::parent()),
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => {
Expand All @@ -253,6 +256,7 @@ impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
Erc20(address) if !is_system_contract(address) => {
Some(native_currency_location(ParachainInfo::get().into(), id.encode()))
}
LiquidCrowdloan(_lease) => Some(native_currency_location(ParachainInfo::get().into(), id.encode())),
StableAssetPoolToken(_pool_id) => Some(native_currency_location(ParachainInfo::get().into(), id.encode())),
ForeignAsset(foreign_asset_id) => AssetIdMaps::<Runtime>::get_multi_location(foreign_asset_id),
_ => None,
Expand All @@ -262,7 +266,7 @@ impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
fn convert(location: MultiLocation) -> Option<CurrencyId> {
use primitives::TokenSymbol::*;
use CurrencyId::{Erc20, StableAssetPoolToken, Token};
use CurrencyId::{Erc20, LiquidCrowdloan, StableAssetPoolToken, Token};

if location == MultiLocation::parent() {
return Some(Token(DOT));
Expand All @@ -285,6 +289,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
match currency_id {
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => Some(currency_id),
Erc20(address) if !is_system_contract(address) => Some(currency_id),
LiquidCrowdloan(_lease) => Some(currency_id),
StableAssetPoolToken(_pool_id) => Some(currency_id),
_ => None,
}
Expand All @@ -306,6 +311,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
match currency_id {
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => Some(currency_id),
Erc20(address) if !is_system_contract(address) => Some(currency_id),
LiquidCrowdloan(_lease) => Some(currency_id),
StableAssetPoolToken(_pool_id) => Some(currency_id),
_ => None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ fn subscribe_version_notify_works() {

#[test]
fn unspent_xcm_fee_is_returned_correctly() {
let parachain_account: AccountId = polkadot_parachain::primitives::Id::from(2000).into_account_truncating();
let parachain_account: AccountId = polkadot_parachain::primitives::Id::from(KARURA_ID).into_account_truncating();
let homa_lite_sub_account: AccountId =
hex_literal::hex!["d7b8926b326dd349355a9a7cca6606c1e0eb6fd2b506066b518c7155ff0d8297"].into();
let dollar_r = dollar(RELAY_CHAIN_CURRENCY);
Expand Down Expand Up @@ -993,7 +993,7 @@ fn trapped_asset() -> MultiAsset {
};

KusamaNet::execute_with(|| {
let location = MultiLocation::new(0, X1(Parachain(2000)));
let location = MultiLocation::new(0, X1(Parachain(KARURA_ID)));
let versioned = xcm::VersionedMultiAssets::from(MultiAssets::from(vec![asset.clone()]));
let hash = BlakeTwo256::hash_of(&(&location, &versioned));
kusama_runtime::System::assert_has_event(kusama_runtime::Event::XcmPallet(pallet_xcm::Event::AssetsTrapped(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@

//! Cross-chain transfer tests within Polkadot network.
use crate::relaychain::fee_test::*;
use crate::relaychain::polkadot_test_net::*;
use crate::setup::*;

use frame_support::assert_ok;
use orml_traits::MultiCurrency;
use xcm_emulator::TestExt;

pub const ACALA_ID: u32 = 2000;
pub const MOCK_BIFROST_ID: u32 = 2001;

fn bifrost_reserve_account() -> AccountId {
polkadot_parachain::primitives::Sibling::from(MOCK_BIFROST_ID).into_account_truncating()
}

#[test]
fn token_per_second_works() {
let aca_per_second = acala_runtime::aca_per_second();
Expand All @@ -39,7 +47,7 @@ fn transfer_from_relay_chain() {
PolkadotNet::execute_with(|| {
assert_ok!(polkadot_runtime::XcmPallet::reserve_transfer_assets(
polkadot_runtime::Origin::signed(ALICE.into()),
Box::new(Parachain(2000).into().into()),
Box::new(Parachain(ACALA_ID).into().into()),
Box::new(
Junction::AccountId32 {
id: BOB,
Expand Down Expand Up @@ -88,7 +96,107 @@ fn transfer_to_relay_chain() {
);
assert_eq!(
5 * dollar(DOT),
polkadot_runtime::Balances::free_balance(&ParaId::from(2000).into_account_truncating())
polkadot_runtime::Balances::free_balance(&ParaId::from(ACALA_ID).into_account_truncating())
);
});
}

#[test]
fn liquid_crowdloan_xtokens_works() {
TestNet::reset();
let foreign_asset = CurrencyId::ForeignAsset(0);
let dollar = dollar(KAR);
let minimal_balance = Balances::minimum_balance() / 10; // 10%
let foreign_fee = foreign_per_second_as_fee(4, minimal_balance);

MockBifrost::execute_with(|| {
assert_ok!(AssetRegistry::register_foreign_asset(
Origin::root(),
Box::new(
MultiLocation::new(
1,
X2(Parachain(ACALA_ID), GeneralKey(LCDOT.encode().try_into().unwrap()))
)
.into()
),
Box::new(AssetMetadata {
name: b"Liquid Crowdloan Token".to_vec(),
symbol: b"LCDOT".to_vec(),
decimals: 12,
minimal_balance
})
));
});

Acala::execute_with(|| {
assert_ok!(AssetRegistry::register_native_asset(
Origin::root(),
LCDOT,
Box::new(AssetMetadata {
name: b"Liquid Crowdloan Token".to_vec(),
symbol: b"LCDOT".to_vec(),
decimals: 12,
minimal_balance
})
));
assert_ok!(Tokens::deposit(LCDOT, &AccountId::from(BOB), 10 * dollar));

assert_ok!(XTokens::transfer(
Origin::signed(BOB.into()),
LCDOT,
5 * dollar,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(MOCK_BIFROST_ID),
Junction::AccountId32 {
network: NetworkId::Any,
id: ALICE.into(),
}
)
)
.into()
),
8_000_000_000,
));

assert_eq!(Tokens::free_balance(LCDOT, &AccountId::from(BOB)), 5 * dollar);
assert_eq!(Tokens::free_balance(LCDOT, &bifrost_reserve_account()), 5 * dollar);
});

MockBifrost::execute_with(|| {
assert_eq!(
Tokens::free_balance(foreign_asset, &AccountId::from(ALICE)),
5 * dollar - foreign_fee
);

assert_ok!(XTokens::transfer(
Origin::signed(ALICE.into()),
foreign_asset,
dollar,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(ACALA_ID),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
)
)
.into()
),
8_000_000_000,
));
});

Acala::execute_with(|| {
assert_eq!(
Tokens::free_balance(LCDOT, &AccountId::from(BOB)),
6 * dollar - foreign_fee
);
assert_eq!(Tokens::free_balance(LCDOT, &bifrost_reserve_account()), 4 * dollar);
});
}

0 comments on commit 2b8b053

Please sign in to comment.