diff --git a/xtokens/src/lib.rs b/xtokens/src/lib.rs index 1248f0f79..64f3e1977 100644 --- a/xtokens/src/lib.rs +++ b/xtokens/src/lib.rs @@ -506,10 +506,17 @@ pub mod module { // Push contains saturated addition, so we should be able to use it safely let mut assets = MultiAssets::new(); - assets.push(asset); + assets.push(asset.clone()); assets.push(fee.clone()); - Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight, false)?; + Self::do_transfer_multiassets(who.clone(), assets, fee.clone(), dest.clone(), dest_weight, false)?; + + Self::deposit_event(Event::::TransferredMultiAssetWithFee { + sender: who, + asset, + fee, + dest, + }); Ok(()) } @@ -522,6 +529,12 @@ pub mod module { dest_weight: Weight, ) -> DispatchResult { let mut assets = MultiAssets::new(); + + // Lets grab the fee amount and location first + let (fee_currency_id, fee_amount) = currencies + .get(fee_item as usize) + .ok_or(Error::::AssetIndexNonExistent)?; + for (currency_id, amount) in ¤cies { let location: MultiLocation = T::CurrencyIdConvert::convert(currency_id.clone()) .ok_or(Error::::NotCrossChainTransferableCurrency)?; @@ -529,11 +542,12 @@ pub mod module { assets.push((location, (*amount).into()).into()) } - // We first grab the fee - let fee = assets - .get(fee_item as usize) - .ok_or(Error::::AssetIndexNonExistent)? - .clone(); + // We construct the fee now, since getting it from assets wont work as assets + // sorts it + let fee_location: MultiLocation = T::CurrencyIdConvert::convert(fee_currency_id.clone()) + .ok_or(Error::::NotCrossChainTransferableCurrency)?; + + let fee: MultiAsset = (fee_location, (*fee_amount).into()).into(); Self::do_transfer_multiassets(who.clone(), assets, fee, dest.clone(), dest_weight, false)?; diff --git a/xtokens/src/tests.rs b/xtokens/src/tests.rs index 5b83a48e9..4e835d225 100644 --- a/xtokens/src/tests.rs +++ b/xtokens/src/tests.rs @@ -351,6 +351,52 @@ fn send_sibling_asset_to_reserve_sibling_with_distinc_fee() { assert_ok!(ParaTokens::deposit(CurrencyId::B1, &sibling_a_account(), 1_000)); }); + ParaA::execute_with(|| { + assert_ok!(ParaXTokens::transfer_multicurrencies( + Some(ALICE).into(), + vec![(CurrencyId::B1, 50), (CurrencyId::B, 450)], + 0, + Box::new( + ( + Parent, + Parachain(2), + Junction::AccountId32 { + network: NetworkId::Any, + id: BOB.into(), + }, + ) + .into() + ), + 40, + )); + + assert_eq!(ParaTokens::free_balance(CurrencyId::B, &ALICE), 550); + assert_eq!(ParaTokens::free_balance(CurrencyId::B1, &ALICE), 950); + }); + + // It should use 40 for weight, so 450 B and 10 B1 should reach destination + ParaB::execute_with(|| { + assert_eq!(ParaTokens::free_balance(CurrencyId::B, &sibling_a_account()), 550); + assert_eq!(ParaTokens::free_balance(CurrencyId::B1, &sibling_a_account()), 950); + assert_eq!(ParaTokens::free_balance(CurrencyId::B, &BOB), 450); + assert_eq!(ParaTokens::free_balance(CurrencyId::B1, &BOB), 10); + }); +} + +#[test] +fn send_sibling_asset_to_reserve_sibling_with_distinc_fee_index_works() { + TestNet::reset(); + + ParaA::execute_with(|| { + assert_ok!(ParaTokens::deposit(CurrencyId::B, &ALICE, 1_000)); + assert_ok!(ParaTokens::deposit(CurrencyId::B1, &ALICE, 1_000)); + }); + + ParaB::execute_with(|| { + assert_ok!(ParaTokens::deposit(CurrencyId::B, &sibling_a_account(), 1_000)); + assert_ok!(ParaTokens::deposit(CurrencyId::B1, &sibling_a_account(), 1_000)); + }); + ParaA::execute_with(|| { assert_ok!(ParaXTokens::transfer_multicurrencies( Some(ALICE).into(),