# xcm demonstration
## CrossIn
Participant salp require user transfer ksm asset from relaychain to Bifrost Parachain with `DepositReserveAsset`
```
Xcm::WithdrawAsset {
assets:vec![MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: amount }],
effects: vec![Order::DepositReserveAsset {
assets:{vec![MultiAsset::All]},
dest:MultiLocation::X1(Junction::Parachain(para_id)),
effects: vec![
BuyExecution {
fees:All,
weight: 0,
debt: dest_weight,
halt_on_error: false,
xcm: vec![],
},
Order::DepositAsset {
assets: vec![MultiAsset::All],
dest: MultiLocation::X1(account_32.clone()),
},
] }]
};
```
## CrossOut
User can transfer the ksm asset balance back to relaychain any time they want
```
Xcm::WithdrawAsset {
assets:vec![MultiAsset::ConcreteFungible { id: X1(Parent), amount: amount }],
effects: vec![Order::InitiateReserveWithdraw {
assets:{vec![MultiAsset::All]},
reserver:X1(Parent),
effects: vec![
BuyExecution {
fees:All,
weight: 0,
debt: 3000000000,
halt_on_error: false,
xcm: vec![],
},
Order::DepositAsset {
assets: vec![MultiAsset::All],
dest: MultiLocation::X1(account_32.clone()),
},
] }]
};
```
```
const theAmount = new BigNumber(amount).multipliedBy(new BigNumber(1000000000000)).toString();
const paras = [
{
WithdrawAsset: {
assets: [
{
ConcreteFungible: {
id: {
X1: {
Parent: null,
},
},
amount: theAmount,
},
},
],
effects: [
{
InitiateReserveWithdraw: {
assets: [
{
All: null,
},
],
reserve: {
X1: {
Parent: null,
},
},
effects: [
{
BuyExecution: {
fees: {
All: null,
},
weight: 0,
debt: 3000000000,
haltOnError: false,
xcm: [],
},
},
{
DepositAsset: {
assets: [
{
All: null,
},
],
dest: {
X1: {
AccountId32: {
network: {
Any: null,
},
id: receiver,
},
},
},
},
},
],
},
},
],
},
},
3000000000,
];
const transferHandle = await api.tx.polkadotXcm.execute(...paras);
const info = await api.tx.polkadotXcm.execute(...paras).paymentInfo(sender);
```
## Transact
Crowdloan contribution is proxy called by Bifrost Parachain account with UMP Transact
### Encode Call
- pallet&call index should match runtime definition in dest chain
https://github.com/paritytech/polkadot/blob/c406f7b7193709a4aa6f1003d2e6c2c8aa7ce220/runtime/kusama/src/lib.rs#L1517
```
#[derive(Encode, Decode)]
pub enum CrowdloanContributeCall<BalanceOf> {
#[codec(index = 73)]
CrowdloanContribute(ContributeCall<BalanceOf>),
}
#[derive(Encode, Decode)]
pub enum ContributeCall<BalanceOf> {
#[codec(index = 1)]
Contribute(Contribution<BalanceOf>),
}
#[derive(Debug, PartialEq, Encode, Decode)]
pub struct Contribution<BalanceOf> {
#[codec(compact)]
pub index: ParaId,
#[codec(compact)]
pub value: BalanceOf,
pub signature: Option<MultiSignature>,
}
```
```
let call = CrowdloanContributeCall::CrowdloanContribute(
ContributeCall::Contribute(Contribution { index, value, signature: None }),
)
.encode()
.into();
```
### Construct Transact
```
let message = Xcm::WithdrawAsset {
assets: vec![MultiAsset::ConcreteFungible {
id: MultiLocation::Null,
amount: WeightToFee::calc(transact_weight+transact_debt)),
}],
effects: vec![Order::BuyExecution {
fees: MultiAsset::All,
weight: transact_weight,
debt: transact_debt,
halt_on_error: true,
xcm: vec![Xcm::Transact {
origin_type: OriginKind::SovereignAccount,
require_weight_at_most: Unlimited,
call:call,
}],
}],
};
```
### Weight Calculation
- Shallow weight & Deep weight
https://github.com/paritytech/polkadot/blob/7a9f624777ad2d2adb3a1e6797a31f9d653c9587/xcm/xcm-builder/src/weight.rs#L30-L83
- Debt(cover shallow weight)
https://github.com/paritytech/polkadot/blob/release-v0.9.9/xcm/xcm-builder/src/barriers.rs#L59
- Inner weight(cover deep weight)
https://github.com/paritytech/polkadot/blob/7a9f624777ad2d2adb3a1e6797a31f9d653c9587/xcm/xcm-builder/src/barriers.rs#L35
### Fee Calculation&Compensation
- use weightToFee from relaychain
(https://github.com/paritytech/polkadot/blob/7a9f624777ad2d2adb3a1e6797a31f9d653c9587/runtime/kusama/src/constants.rs#L71-L86)
- extend pallet_transaction_payment with OnChargeTransaction
```
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = FlexibleFee;
...
}
T::MiscFeeHandler::deduct_fee(who, &T::TreasuryAccount::get(), call).map_err(
|_| TransactionValidityError::Invalid(InvalidTransaction::Custom(77u8)),
)?;
```
### XCM Confirmation
XCM essentially is asynchronous&asymetric and in current XCM version you can not tell if the remote call is successful or not in relaychain. To achieve it we deply `salp-confirm-service` to confirm the contribution with multisig mechanism
- generate xcm messageId
https://github.com/bifrost-finance/bifrost/blob/bc11527ff2a35f275b41815803b149cff37f345c/xcm-support/src/lib.rs#L133-L135
- confirm service
https://github1s.com/bifrost-finance/salp-confirm-service
- events
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fbifrost-parachain.api.onfinality.io%2Fpublic-ws#/explorer/query/426657
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-rpc.polkadot.io#/explorer/query/9345308
https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fbifrost-parachain.api.onfinality.io%2Fpublic-ws#/explorer/query/426668
## Challenges&Issues
https://github.com/paritytech/polkadot/issues/3500
https://github.com/paritytech/polkadot/blob/65313050a8416ea358005a0f0905a0db87f9290f/node/service/src/chain_spec.rs#L185
https://github.com/paritytech/cumulus/issues/598
## ToDo
- Migrate to V2 and remove confirm-service with fully decentralized Xcm notify&query
https://github.com/paritytech/polkadot/blob/65313050a8416ea358005a0f0905a0db87f9290f/xcm/pallet-xcm/src/lib.rs#L979
https://github.com/paritytech/xcm-format/pull/22