From 02e3ee6479e104a072973b268f448b98da2f376a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 3 Sep 2024 15:02:16 +0300 Subject: [PATCH] snowbridge: improve destination fee handling to avoid trapping fees dust --- .../primitives/router/src/inbound/mod.rs | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index 54e47a7a8b6af..345531392ad0f 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -128,7 +128,8 @@ impl where + > +where CreateAssetCall: Get, CreateAssetDeposit: Get, InboundQueuePalletInstance: Get, @@ -167,7 +168,7 @@ where let total_amount = fee + CreateAssetDeposit::get(); let total: Asset = (Location::parent(), total_amount).into(); - let bridge_location: Location = (Parent, Parent, GlobalConsensus(network)).into(); + let bridge_location = Location::new(2, GlobalConsensus(network)); let owner = GlobalConsensusEthereumConvertsFor::<[u8; 32]>::from_chain_id(&chain_id); let asset_id = Self::convert_token_address(network, token); @@ -180,8 +181,15 @@ where // Pay for execution. BuyExecution { fees: xcm_fee, weight_limit: Unlimited }, // Fund the snowbridge sovereign with the required deposit for creation. - DepositAsset { assets: Definite(deposit.into()), beneficiary: bridge_location }, - // Only our inbound-queue pallet is allowed to invoke `UniversalOrigin` + DepositAsset { assets: Definite(deposit.into()), beneficiary: bridge_location.clone() }, + // This `SetAppendix` ensures that `xcm_fee` not spent by `Transact` will be + // deposited to snowbridge sovereign, instead of being trapped, regardless of + // `Transact` success or not. + SetAppendix(Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: bridge_location, + }])), + // Only our inbound-queue pallet is allowed to invoke `UniversalOrigin`. DescendOrigin(PalletInstance(inbound_queue_pallet_index).into()), // Change origin to the bridge. UniversalOrigin(GlobalConsensus(network)), @@ -199,9 +207,8 @@ where .into(), }, RefundSurplus, - // Clear the origin so that remaining assets in holding - // are claimable by the physical origin (BridgeHub) - ClearOrigin, + // Once the program ends here, appendix program will run, which will deposit any + // leftover fee to snowbridge sovereign. ] .into(); @@ -255,20 +262,23 @@ where match dest_para_id { Some(dest_para_id) => { let dest_para_fee_asset: Asset = (Location::parent(), dest_para_fee).into(); + let bridge_location = Location::new(2, GlobalConsensus(network)); instructions.extend(vec![ // Perform a deposit reserve to send to destination chain. DepositReserveAsset { - assets: Definite(vec![dest_para_fee_asset.clone(), asset.clone()].into()), + assets: Definite(vec![dest_para_fee_asset.clone(), asset].into()), dest: Location::new(1, [Parachain(dest_para_id)]), xcm: vec![ // Buy execution on target. BuyExecution { fees: dest_para_fee_asset, weight_limit: Unlimited }, - // Deposit asset to beneficiary. - DepositAsset { assets: Definite(asset.into()), beneficiary }, + // Deposit assets to beneficiary. + DepositAsset { assets: Wild(AllCounted(2)), beneficiary }, ] .into(), }, + // Deposit any leftover unspent AH fees to the snowbridge sovereign. + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: bridge_location }, ]); }, None => { @@ -281,6 +291,8 @@ where }, } + // The `instructions` to forward to AssetHub, and the `total_fees` to locally burn (since + // they are teleported within `instructions`). (instructions.into(), total_fees.into()) }