Skip to content

Commit 2b8b053

Browse files
authored
Support LCDOT for XCM (#2316)
* Support LCDOT for XCM * Apply review suggestions
1 parent 02bd690 commit 2b8b053

File tree

4 files changed

+148
-7
lines changed

4 files changed

+148
-7
lines changed

modules/asset-registry/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,33 @@ where
582582
}
583583
}
584584

585+
pub struct BuyWeightRateOfLiquidCrowdloan<T>(sp_std::marker::PhantomData<T>);
586+
587+
impl<T: Config> BuyWeightRate for BuyWeightRateOfLiquidCrowdloan<T>
588+
where
589+
BalanceOf<T>: Into<u128>,
590+
{
591+
fn calculate_rate(location: MultiLocation) -> Option<Ratio> {
592+
let currency = key_to_currency(location);
593+
match currency {
594+
Some(CurrencyId::LiquidCrowdloan(lease)) => {
595+
if let Some(asset_metadata) =
596+
Pallet::<T>::asset_metadatas(AssetIds::NativeAssetId(CurrencyId::LiquidCrowdloan(lease)))
597+
{
598+
let minimum_balance = asset_metadata.minimal_balance.into();
599+
let rate =
600+
FixedU128::saturating_from_rational(minimum_balance, T::Currency::minimum_balance().into());
601+
log::debug!(target: "asset-registry::weight", "LiquidCrowdloan: {}, MinimumBalance: {}, rate:{:?}", lease, minimum_balance, rate);
602+
Some(rate)
603+
} else {
604+
None
605+
}
606+
}
607+
_ => None,
608+
}
609+
}
610+
}
611+
585612
pub struct BuyWeightRateOfStableAsset<T>(sp_std::marker::PhantomData<T>);
586613

587614
impl<T: Config> BuyWeightRate for BuyWeightRateOfStableAsset<T>

runtime/acala/src/xcm_config.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ pub use frame_support::{
2929
traits::{Everything, Get, Nothing},
3030
weights::Weight,
3131
};
32-
use module_asset_registry::{BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset, BuyWeightRateOfStableAsset};
32+
use module_asset_registry::{
33+
BuyWeightRateOfErc20, BuyWeightRateOfForeignAsset, BuyWeightRateOfLiquidCrowdloan, BuyWeightRateOfStableAsset,
34+
};
3335
use module_support::HomaSubAccountXcm;
3436
use module_transaction_payment::BuyWeightRateOfTransactionFeePool;
3537
use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency};
@@ -147,6 +149,7 @@ pub type Trader = (
147149
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfForeignAsset<Runtime>>,
148150
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfErc20<Runtime>>,
149151
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfStableAsset<Runtime>>,
152+
FixedRateOfAsset<BaseRate, ToTreasury, BuyWeightRateOfLiquidCrowdloan<Runtime>>,
150153
FixedRateOfFungible<DotPerSecond, ToTreasury>,
151154
FixedRateOfFungible<AusdPerSecond, ToTreasury>,
152155
FixedRateOfFungible<TapPerSecond, ToTreasury>,
@@ -244,7 +247,7 @@ pub struct CurrencyIdConvert;
244247
impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
245248
fn convert(id: CurrencyId) -> Option<MultiLocation> {
246249
use primitives::TokenSymbol::*;
247-
use CurrencyId::{Erc20, ForeignAsset, StableAssetPoolToken, Token};
250+
use CurrencyId::{Erc20, ForeignAsset, LiquidCrowdloan, StableAssetPoolToken, Token};
248251
match id {
249252
Token(DOT) => Some(MultiLocation::parent()),
250253
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => {
@@ -253,6 +256,7 @@ impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
253256
Erc20(address) if !is_system_contract(address) => {
254257
Some(native_currency_location(ParachainInfo::get().into(), id.encode()))
255258
}
259+
LiquidCrowdloan(_lease) => Some(native_currency_location(ParachainInfo::get().into(), id.encode())),
256260
StableAssetPoolToken(_pool_id) => Some(native_currency_location(ParachainInfo::get().into(), id.encode())),
257261
ForeignAsset(foreign_asset_id) => AssetIdMaps::<Runtime>::get_multi_location(foreign_asset_id),
258262
_ => None,
@@ -262,7 +266,7 @@ impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
262266
impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
263267
fn convert(location: MultiLocation) -> Option<CurrencyId> {
264268
use primitives::TokenSymbol::*;
265-
use CurrencyId::{Erc20, StableAssetPoolToken, Token};
269+
use CurrencyId::{Erc20, LiquidCrowdloan, StableAssetPoolToken, Token};
266270

267271
if location == MultiLocation::parent() {
268272
return Some(Token(DOT));
@@ -285,6 +289,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
285289
match currency_id {
286290
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => Some(currency_id),
287291
Erc20(address) if !is_system_contract(address) => Some(currency_id),
292+
LiquidCrowdloan(_lease) => Some(currency_id),
288293
StableAssetPoolToken(_pool_id) => Some(currency_id),
289294
_ => None,
290295
}
@@ -306,6 +311,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
306311
match currency_id {
307312
Token(ACA) | Token(AUSD) | Token(LDOT) | Token(TAP) => Some(currency_id),
308313
Erc20(address) if !is_system_contract(address) => Some(currency_id),
314+
LiquidCrowdloan(_lease) => Some(currency_id),
309315
StableAssetPoolToken(_pool_id) => Some(currency_id),
310316
_ => None,
311317
}

runtime/integration-tests/src/relaychain/kusama_cross_chain_transfer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ fn subscribe_version_notify_works() {
845845

846846
#[test]
847847
fn unspent_xcm_fee_is_returned_correctly() {
848-
let parachain_account: AccountId = polkadot_parachain::primitives::Id::from(2000).into_account_truncating();
848+
let parachain_account: AccountId = polkadot_parachain::primitives::Id::from(KARURA_ID).into_account_truncating();
849849
let homa_lite_sub_account: AccountId =
850850
hex_literal::hex!["d7b8926b326dd349355a9a7cca6606c1e0eb6fd2b506066b518c7155ff0d8297"].into();
851851
let dollar_r = dollar(RELAY_CHAIN_CURRENCY);
@@ -993,7 +993,7 @@ fn trapped_asset() -> MultiAsset {
993993
};
994994

995995
KusamaNet::execute_with(|| {
996-
let location = MultiLocation::new(0, X1(Parachain(2000)));
996+
let location = MultiLocation::new(0, X1(Parachain(KARURA_ID)));
997997
let versioned = xcm::VersionedMultiAssets::from(MultiAssets::from(vec![asset.clone()]));
998998
let hash = BlakeTwo256::hash_of(&(&location, &versioned));
999999
kusama_runtime::System::assert_has_event(kusama_runtime::Event::XcmPallet(pallet_xcm::Event::AssetsTrapped(

runtime/integration-tests/src/relaychain/polkadot_cross_chain_transfer.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,21 @@
1818

1919
//! Cross-chain transfer tests within Polkadot network.
2020
21+
use crate::relaychain::fee_test::*;
2122
use crate::relaychain::polkadot_test_net::*;
2223
use crate::setup::*;
2324

2425
use frame_support::assert_ok;
2526
use orml_traits::MultiCurrency;
2627
use xcm_emulator::TestExt;
2728

29+
pub const ACALA_ID: u32 = 2000;
30+
pub const MOCK_BIFROST_ID: u32 = 2001;
31+
32+
fn bifrost_reserve_account() -> AccountId {
33+
polkadot_parachain::primitives::Sibling::from(MOCK_BIFROST_ID).into_account_truncating()
34+
}
35+
2836
#[test]
2937
fn token_per_second_works() {
3038
let aca_per_second = acala_runtime::aca_per_second();
@@ -39,7 +47,7 @@ fn transfer_from_relay_chain() {
3947
PolkadotNet::execute_with(|| {
4048
assert_ok!(polkadot_runtime::XcmPallet::reserve_transfer_assets(
4149
polkadot_runtime::Origin::signed(ALICE.into()),
42-
Box::new(Parachain(2000).into().into()),
50+
Box::new(Parachain(ACALA_ID).into().into()),
4351
Box::new(
4452
Junction::AccountId32 {
4553
id: BOB,
@@ -88,7 +96,107 @@ fn transfer_to_relay_chain() {
8896
);
8997
assert_eq!(
9098
5 * dollar(DOT),
91-
polkadot_runtime::Balances::free_balance(&ParaId::from(2000).into_account_truncating())
99+
polkadot_runtime::Balances::free_balance(&ParaId::from(ACALA_ID).into_account_truncating())
100+
);
101+
});
102+
}
103+
104+
#[test]
105+
fn liquid_crowdloan_xtokens_works() {
106+
TestNet::reset();
107+
let foreign_asset = CurrencyId::ForeignAsset(0);
108+
let dollar = dollar(KAR);
109+
let minimal_balance = Balances::minimum_balance() / 10; // 10%
110+
let foreign_fee = foreign_per_second_as_fee(4, minimal_balance);
111+
112+
MockBifrost::execute_with(|| {
113+
assert_ok!(AssetRegistry::register_foreign_asset(
114+
Origin::root(),
115+
Box::new(
116+
MultiLocation::new(
117+
1,
118+
X2(Parachain(ACALA_ID), GeneralKey(LCDOT.encode().try_into().unwrap()))
119+
)
120+
.into()
121+
),
122+
Box::new(AssetMetadata {
123+
name: b"Liquid Crowdloan Token".to_vec(),
124+
symbol: b"LCDOT".to_vec(),
125+
decimals: 12,
126+
minimal_balance
127+
})
128+
));
129+
});
130+
131+
Acala::execute_with(|| {
132+
assert_ok!(AssetRegistry::register_native_asset(
133+
Origin::root(),
134+
LCDOT,
135+
Box::new(AssetMetadata {
136+
name: b"Liquid Crowdloan Token".to_vec(),
137+
symbol: b"LCDOT".to_vec(),
138+
decimals: 12,
139+
minimal_balance
140+
})
141+
));
142+
assert_ok!(Tokens::deposit(LCDOT, &AccountId::from(BOB), 10 * dollar));
143+
144+
assert_ok!(XTokens::transfer(
145+
Origin::signed(BOB.into()),
146+
LCDOT,
147+
5 * dollar,
148+
Box::new(
149+
MultiLocation::new(
150+
1,
151+
X2(
152+
Parachain(MOCK_BIFROST_ID),
153+
Junction::AccountId32 {
154+
network: NetworkId::Any,
155+
id: ALICE.into(),
156+
}
157+
)
158+
)
159+
.into()
160+
),
161+
8_000_000_000,
162+
));
163+
164+
assert_eq!(Tokens::free_balance(LCDOT, &AccountId::from(BOB)), 5 * dollar);
165+
assert_eq!(Tokens::free_balance(LCDOT, &bifrost_reserve_account()), 5 * dollar);
166+
});
167+
168+
MockBifrost::execute_with(|| {
169+
assert_eq!(
170+
Tokens::free_balance(foreign_asset, &AccountId::from(ALICE)),
171+
5 * dollar - foreign_fee
172+
);
173+
174+
assert_ok!(XTokens::transfer(
175+
Origin::signed(ALICE.into()),
176+
foreign_asset,
177+
dollar,
178+
Box::new(
179+
MultiLocation::new(
180+
1,
181+
X2(
182+
Parachain(ACALA_ID),
183+
Junction::AccountId32 {
184+
network: NetworkId::Any,
185+
id: BOB.into(),
186+
}
187+
)
188+
)
189+
.into()
190+
),
191+
8_000_000_000,
192+
));
193+
});
194+
195+
Acala::execute_with(|| {
196+
assert_eq!(
197+
Tokens::free_balance(LCDOT, &AccountId::from(BOB)),
198+
6 * dollar - foreign_fee
92199
);
200+
assert_eq!(Tokens::free_balance(LCDOT, &bifrost_reserve_account()), 4 * dollar);
93201
});
94202
}

0 commit comments

Comments
 (0)