In this example, we will do a transfer on the relay chain initiated by a parachain.
Of course we could always call the transfer function of the balances pallet, but here we can
observe how the holding register is used.
What we want to see in this example is that through the process of transferring funds via XCM, we
execute the instructions WithdrawAsset and DepositAsset. By doing this, assets are taken out of
the sender account, placed into the holding register, and then deposited into the receiver account.
So for a moment, the assets exist only within the context of the holding registrar, and has been completely removed from within the runtime state. This is a key point when thinking about cross chain teleports.
Test: fn withdraw_and_deposit()
/// Scenario:
/// A parachain transfers funds on the relay chain to another parachain account.
///
/// Asserts that the parachain accounts are updated as expected.
#[test]
fn withdraw_and_deposit() {
MockNet::reset();
let send_amount = 10;
ParaA::execute_with(|| {
let message = Xcm(vec![
WithdrawAsset((Here, send_amount).into()),
buy_execution((Here, send_amount)),
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Parachain(2).into() },
]);
// Send withdraw and deposit
assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
});
Relay::execute_with(|| {
assert_eq!(
relay_chain::Balances::free_balance(para_account_id(1)),
INITIAL_BALANCE - send_amount
);
assert_eq!(relay_chain::Balances::free_balance(para_account_id(2)), send_amount);
});
}To run the test, execute:
cargo test --package xcm-simulator-example --lib -- tests::withdraw_and_deposit --exact --nocapturerunning 1 test
instruction: WithdrawAsset(MultiAssets([MultiAsset { id: Concrete(MultiLocation { parents: 0, interior: Here }), fun: Fungible(10) }]))
holding before: Assets { fungible: {}, non_fungible: {} }
holding after: Assets { fungible: {Concrete(MultiLocation { parents: 0, interior: Here }): 10}, non_fungible: {} }
instruction: BuyExecution { fees: MultiAsset { id: Concrete(MultiLocation { parents: 0, interior: Here }), fun: Fungible(10) }, weight_limit: Unlimited }
holding before: Assets { fungible: {Concrete(MultiLocation { parents: 0, interior: Here }): 10}, non_fungible: {} }
holding after: Assets { fungible: {Concrete(MultiLocation { parents: 0, interior: Here }): 10}, non_fungible: {} }
instruction: DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: MultiLocation { parents: 0, interior: X1(Parachain(2)) } }
holding before: Assets { fungible: {Concrete(MultiLocation { parents: 0, interior: Here }): 10}, non_fungible: {} }
holding after: Assets { fungible: {}, non_fungible: {} }
test tests::withdraw_and_deposit ... ok