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

Support LCDOT for XCM #2316

Merged
merged 2 commits into from
Aug 9, 2022
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
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);
});
}