Cross-chain scenarios
What we've seen so far
- What XCM is and its main concepts
- How XCM programs are written and executed
- The interface between FRAME and XCM
What we'll look into now
- Cross-chain examples
- Cross-chain composability
- Attack scenarios
At the end of this lecture, you will be able to:
- Build existing or new cross-chain use-cases
- Leverage services offered by the broader Polkadot ecosystem for your apps
- Mitigate risk during cross-chain interactions
Cross-chain DEX
Requirements
- Accounts on other chains can transfer tokens to our chain
- They can do swaps without an account on our chain
- They can add/remove liquidity without an account on our chain
Diagram
Configuring XCM
The XCM configuration translates the XCVM instructions into actual native runtime functionality of our chain.
AssetTransactor
type AssetTransactor = FungiblesAdapter<
Assets,
Matcher,
LocationToAccountId,
...
>;
Teleports or reserve asset transfers?
type IsReserve = ();
type IsTeleporter = ();
Reserve asset transfers
Xcm(vec![
WithdrawAsset(withdraw_amount),
DepositReserveAsset {
assets: All.into(),
dest: (Parent, Parachain(dex_para_id)).into(),
xcm: Xcm(vec![
DepositAsset { assets, beneficiary },
]),
},
])
Sovereign account
XCM Location -> AccountId
type LocationToAccountId = (
AccountId32Aliases<Network, AccountId>,
HashedDescription<
AccountId,
DescribeFamily<DescribeAccountId32Terminal>
>,
);
Swaps
enum Instruction<Call> {
// ...snip...
ExchangeAsset {
give: AssetFilter,
want: Assets,
maximal: bool,
},
// ...snip...
}
Make the swap
Xcm(vec![
WithdrawAsset(withdraw_amount),
BuyExecution { fees, weight_limit },
ExchangeAsset { give, want, maximal },
DepositAsset { assets, beneficiary },
])
Denial of Service attack
Imagine a million of these:
Xcm(vec![
WithdrawAsset(assets),
DepositAsset { assets, beneficiary },
])
Barriers to the rescue
type Barrier: ShouldExecute;
Requiring fees to be paid
type Barrier = AllowTopLevelPaidExecutionFrom<Everything>;
Up until now
Xcm(vec![
WithdrawAsset(withdraw_amount),
DepositReserveAsset {
assets: All.into(),
dest: (Parent, Parachain(dex_para_id)).into(),
xcm: Xcm(vec![
BuyExecution { fees, weight_limit },
ExchangeAsset { give, want, maximal },
DepositAsset { assets, beneficiary },
]),
},
])
Getting the tokens back
- We've sent the tokens
- We made a swap
- Now how do we get them back into our chain?
Message to get them back
InitiateReserveWithdraw {
assets: All.into(),
reserve: (Parent, Parachain(a_para_id)).into(),
xcm: Xcm(vec![
BuyExecution { fees, weight_limit },
DepositAsset { assets, beneficiary },
]),
}
Putting it all together
Xcm(vec![
WithdrawAsset(withdraw_amount),
BuyExecution { fees, weight_limit },
DepositReserveAsset {
assets: All.into(),
dest: (Parent, Parachain(dex_para_id)).into(),
xcm: Xcm(vec![
BuyExecution { fees, weight_limit },
ExchangeAsset { give, want, maximal },
InitiateReserveWithdraw {
assets: All.into(),
reserve: (Parent, Parachain(a_para_id)).into(),
xcm: Xcm(vec![
BuyExecution { fees, weight_limit },
DepositAsset { assets, beneficiary },
]),
}
]),
},
])
Summary
In this lecture, we learnt:
- How chains interpret locations and turn them to accounts and FRAME origins
- How to set a barrier to protect our chain from attacks
- What adapters are available to translate XCM
Assets
to FRAME assets