git.delta.rocks / unique-network / refs/commits / 5bd4b32eaeba

difftreelog

Merge pull request #285 from UniqueNetwork/xcm-token-transfer-karura

kozyrevdev2022-02-10parents: #de5ac2f #5b17553.patch.diff
in: master
Xcm token transfer with Karura

5 files changed

modifiedREADME.mddiffbeforeafterboth
333*/333*/
334334
335```335```
336336
337
338## Karura token transfer
339
340To get started, you need to open inbound and outbound hrmp channels.
341Next, we need to register our asset at Karura.
342
343```
344assetRegistry -> registerForeignAsset(location, metadata)
345location:
346 V0(X2(Parent, Parachain(PARA_ID)))
347metadata:
348 name OPL
349 symbol OPL
350 decimals 18
351minimalBalance 1
352```
353
354Next, we can send tokens from Opal to Karura:
355```
356polkadotXcm -> reserveTransferAssets
357dest:
358 V0(X2(Parent, Parachain(<KARURA_PARA_ID>)))
359beneficiary:
360 X1(AccountId(Any, <ACCOUNT>))
361assets:
362 V1(Concrete(0,Here), Fungible(<AMOUNT>))
363feeAssetItem:
364 0
365weightLimit:
366 <LIMIT>
367```
368
369The result will be displayed in ChainState
370tokens -> accounts
371
372
373To send tokens from Karura to Opal:
374
375```
376xtokens -> transfer
377
378currencyId:
379 ForeingAsset
380 <TOKEN_ID>
381
382amount:
383 <AMOUNT>
384dest:
385 V1
386 (
387 Parents:1,
388 X2(Parachain(<KARURA_PARA_ID>), AccountId(Any, <ACCOUNT>)
389 )
390destWeight:
391 <WEIGHT>
392
393
394```
modifiedlaunch-config.jsondiffbeforeafterboth
9 "rpcPort": 9843,9 "rpcPort": 9843,
10 "port": 30444,10 "port": 30444,
11 "flags": [11 "flags": [
12 "-lparachain::candidate_validation=debug"12 "-lparachain::candidate_validation=debug",
13 "-lxcm=trace"
13 ]14 ]
14 },15 },
15 {16 {
18 "rpcPort": 9854,19 "rpcPort": 9854,
19 "port": 30555,20 "port": 30555,
20 "flags": [21 "flags": [
21 "-lparachain::candidate_validation=debug"22 "-lparachain::candidate_validation=debug",
23 "-lxcm=trace"
22 ]24 ]
23 },25 },
24 {26 {
38 "flags": [40 "flags": [
39 "-lparachain::candidate_validation=debug"41 "-lparachain::candidate_validation=debug"
40 ]42 ]
41 }43 },
44 {
45 "name": "eve",
46 "wsPort": 9888,
47 "rpcPort": 9887,
48 "port": 30888,
49 "flags": [
50 "-lparachain::candidate_validation=debug"
51 ]
52 }
42 ],53 ],
43 "genesis": {54 "genesis": {
44 "runtime": {55 "runtime": {
67 "flags": [78 "flags": [
68 "--rpc-cors=all",79 "--rpc-cors=all",
69 "--unsafe-rpc-external",80 "--unsafe-rpc-external",
70 "--unsafe-ws-external"81 "--unsafe-ws-external",
82 "-lxcm=trace"
71 ]83 ]
72 },84 },
73 {85 {
78 "flags": [90 "flags": [
79 "--rpc-cors=all",91 "--rpc-cors=all",
80 "--unsafe-rpc-external",92 "--unsafe-rpc-external",
81 "--unsafe-ws-external"93 "--unsafe-ws-external",
94 "-lxcm=trace"
82 ]95 ]
83 }96 }
84 ]97 ]
85 }98 },
99 {
100 "bin": "../Acala/target/release/acala",
101 "id": "2000",
102 "chain": "karura-dev",
103 "balance": "1000000000000000000000",
104 "nodes": [
105 {
106 "wsPort": 9946,
107 "port": 31202,
108 "name": "alice",
109 "flags": [
110 "--rpc-cors=all",
111 "--unsafe-rpc-external",
112 "--unsafe-ws-external",
113 "-lxcm=trace"
114 ]
115 }
116 ]
117 }
86 ],118 ],
87 "simpleParachains": [],119 "simpleParachains": [],
88 "hrmpChannels": [],120 "hrmpChannels": [
121 {
122 "sender": 2000,
123 "recipient": 1000,
124 "maxCapacity": 8,
125 "maxMessageSize": 512
126 },
127 {
128 "sender": 1000,
129 "recipient": 2000,
130 "maxCapacity": 8,
131 "maxMessageSize": 512
132 }
133 ],
89 "finalization": false134 "finalization": false
90}135}
modifiedruntime/src/lib.rsdiffbeforeafterboth
24 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,24 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
25 traits::{25 traits::{
26 AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify, AccountIdConversion,26 AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify,
27 AccountIdConversion, Zero,
27 },28 },
28 transaction_validity::{TransactionSource, TransactionValidity},29 transaction_validity::{TransactionSource, TransactionValidity},
29 ApplyExtrinsicResult, MultiSignature, RuntimeAppPublic,30 ApplyExtrinsicResult, MultiSignature, RuntimeAppPublic,
45 dispatch::DispatchResult,46 dispatch::DispatchResult,
46 PalletId, parameter_types, StorageValue, ConsensusEngineId,47 PalletId, parameter_types, StorageValue, ConsensusEngineId,
47 traits::{48 traits::{
48 Everything, Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem,49 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
49 LockIdentifier, OnUnbalanced, Randomness, FindAuthor,50 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
51 OnUnbalanced, Randomness, FindAuthor,
50 },52 },
69use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};71use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};
70use fp_rpc::TransactionStatus;72use fp_rpc::TransactionStatus;
71use sp_runtime::{73use sp_runtime::{
72 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf},74 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},
73 transaction_validity::TransactionValidityError,75 transaction_validity::TransactionValidityError,
76 SaturatedConversion,
74};77};
7578
76// pub use pallet_timestamp::Call as TimestampCall;79// pub use pallet_timestamp::Call as TimestampCall;
82use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};85use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
83use xcm_builder::{86use xcm_builder::{
84 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,87 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
85 EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset,88 EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
86 ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,89 ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
87 SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,90 SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
88 SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
89};91};
90use xcm_executor::{Config, XcmExecutor};92use xcm_executor::{Config, XcmExecutor, Assets};
93use sp_std::{marker::PhantomData};
94
95use xcm::latest::{
96 // Xcm,
97 AssetId::{Concrete},
98 Fungibility::Fungible as XcmFungible,
99 MultiAsset,
100 Error as XcmError,
101};
102use xcm_executor::traits::{MatchesFungible, WeightTrader};
103//use xcm_executor::traits::MatchesFungible;
104use sp_runtime::traits::CheckedConversion;
91105
92// mod chain_extension;106// mod chain_extension;
93// use crate::chain_extension::{NFTExtension, Imbalance};107// use crate::chain_extension::{NFTExtension, Imbalance};
616 AccountId32Aliases<RelayNetwork, AccountId>,630 AccountId32Aliases<RelayNetwork, AccountId>,
617);631);
632
633pub struct OnlySelfCurrency;
634impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
635 fn matches_fungible(a: &MultiAsset) -> Option<B> {
636 match (&a.id, &a.fun) {
637 (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
638 _ => None,
639 }
640 }
641}
618642
619/// Means for transacting assets on this chain.643/// Means for transacting assets on this chain.
620pub type LocalAssetTransactor = CurrencyAdapter<644pub type LocalAssetTransactor = CurrencyAdapter<
621 // Use this currency:645 // Use this currency:
622 Balances,646 Balances,
623 // Use this currency when it is a fungible asset matching the given location or name:647 // Use this currency when it is a fungible asset matching the given location or name:
624 IsConcrete<RelayLocation>,648 OnlySelfCurrency,
625 // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:649 // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
626 LocationToAccountId,650 LocationToAccountId,
627 // Our chain's account ID type (we can't get away without mentioning it explicitly):651 // Our chain's account ID type (we can't get away without mentioning it explicitly):
677 // ^^^ Parent & its unit plurality gets free execution701 // ^^^ Parent & its unit plurality gets free execution
678);702);
703
704pub struct UsingOnlySelfCurrencyComponents<
705 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
706 AssetId: Get<MultiLocation>,
707 AccountId,
708 Currency: CurrencyT<AccountId>,
709 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
710>(
711 Weight,
712 Currency::Balance,
713 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
714);
715impl<
716 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
717 AssetId: Get<MultiLocation>,
718 AccountId,
719 Currency: CurrencyT<AccountId>,
720 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
721 > WeightTrader
722 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
723{
724 fn new() -> Self {
725 Self(0, Zero::zero(), PhantomData)
726 }
727
728 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
729 let amount = WeightToFee::calc(&weight);
730 let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
731
732 // location to this parachain through relay chain
733 let option1: xcm::v1::AssetId = Concrete(MultiLocation {
734 parents: 1,
735 interior: X1(Parachain(ParachainInfo::parachain_id().into())),
736 });
737 // direct location
738 let option2: xcm::v1::AssetId = Concrete(MultiLocation {
739 parents: 0,
740 interior: Here,
741 });
742
743 let required = if payment.fungible.contains_key(&option1) {
744 (option1, u128_amount).into()
745 } else if payment.fungible.contains_key(&option2) {
746 (option2, u128_amount).into()
747 } else {
748 (Concrete(MultiLocation::default()), u128_amount).into()
749 };
750
751 let unused = payment
752 .checked_sub(required)
753 .map_err(|_| XcmError::TooExpensive)?;
754 self.0 = self.0.saturating_add(weight);
755 self.1 = self.1.saturating_add(amount);
756 Ok(unused)
757 }
758
759 fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
760 let weight = weight.min(self.0);
761 let amount = WeightToFee::calc(&weight);
762 self.0 -= weight;
763 self.1 = self.1.saturating_sub(amount);
764 let amount: u128 = amount.saturated_into();
765 if amount > 0 {
766 Some((AssetId::get(), amount).into())
767 } else {
768 None
769 }
770 }
771}
772impl<
773 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
774 AssetId: Get<MultiLocation>,
775 AccountId,
776 Currency: CurrencyT<AccountId>,
777 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
778 > Drop
779 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
780{
781 fn drop(&mut self) {
782 OnUnbalanced::on_unbalanced(Currency::issue(self.1));
783 }
784}
679785
680pub struct XcmConfig;786pub struct XcmConfig;
681impl Config for XcmConfig {787impl Config for XcmConfig {
689 type LocationInverter = LocationInverter<Ancestry>;795 type LocationInverter = LocationInverter<Ancestry>;
690 type Barrier = Barrier;796 type Barrier = Barrier;
691 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;797 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
692 type Trader = UsingComponents<IdentityFee<Balance>, RelayLocation, AccountId, Balances, ()>;798 type Trader = UsingOnlySelfCurrencyComponents<
799 IdentityFee<Balance>,
800 RelayLocation,
801 AccountId,
802 Balances,
803 (),
804 >;
693 type ResponseHandler = (); // Don't handle responses for now.805 type ResponseHandler = (); // Don't handle responses for now.
694 type SubscriptionService = PolkadotXcm;806 type SubscriptionService = PolkadotXcm;
modifiedtests/package.jsondiffbeforeafterboth
64 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",64 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
65 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",65 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
66 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",66 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
67 "testXcmTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/xcmTransfer.test.ts",
67 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",68 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
68 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",69 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
69 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",70 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
addedtests/src/xcmTransfer.test.tsdiffbeforeafterboth

no changes