Skip to content

Commit 5b46c89

Browse files
authored
XTokens refactor (#706)
* refactor * merge check * clippy
1 parent f8f6f82 commit 5b46c89

File tree

2 files changed

+103
-148
lines changed

2 files changed

+103
-148
lines changed

xtokens/src/lib.rs

+51-147
Original file line numberDiff line numberDiff line change
@@ -107,44 +107,11 @@ pub mod module {
107107
#[pallet::event]
108108
#[pallet::generate_deposit(fn deposit_event)]
109109
pub enum Event<T: Config> {
110-
/// Transferred.
111-
Transferred {
112-
sender: T::AccountId,
113-
currency_id: T::CurrencyId,
114-
amount: T::Balance,
115-
dest: MultiLocation,
116-
},
117-
/// Transferred with fee.
118-
TransferredWithFee {
119-
sender: T::AccountId,
120-
currency_id: T::CurrencyId,
121-
amount: T::Balance,
122-
fee: T::Balance,
123-
dest: MultiLocation,
124-
},
125-
/// Transferred `MultiAsset`.
126-
TransferredMultiAsset {
127-
sender: T::AccountId,
128-
asset: MultiAsset,
129-
dest: MultiLocation,
130-
},
131-
/// Transferred `MultiAsset` with fee.
132-
TransferredMultiAssetWithFee {
133-
sender: T::AccountId,
134-
asset: MultiAsset,
135-
fee: MultiAsset,
136-
dest: MultiLocation,
137-
},
138-
/// Transferred `MultiAsset` with fee.
139-
TransferredMultiCurrencies {
140-
sender: T::AccountId,
141-
currencies: Vec<(T::CurrencyId, T::Balance)>,
142-
dest: MultiLocation,
143-
},
144110
/// Transferred `MultiAsset` with fee.
145111
TransferredMultiAssets {
146112
sender: T::AccountId,
147113
assets: MultiAssets,
114+
fee: MultiAsset,
148115
dest: MultiLocation,
149116
},
150117
}
@@ -169,8 +136,8 @@ pub mod module {
169136
CannotReanchor,
170137
/// Could not get ancestry of asset reserve location.
171138
InvalidAncestry,
172-
/// Not fungible asset.
173-
NotFungible,
139+
/// The MultiAsset is invalid.
140+
InvalidAsset,
174141
/// The destination `MultiLocation` provided cannot be inverted.
175142
DestinationNotInvertible,
176143
/// The version of the `Versioned` value used is not able to be
@@ -179,9 +146,10 @@ pub mod module {
179146
/// We tried sending distinct asset and fee but they have different
180147
/// reserve chains
181148
DistinctReserveForAssetAndFee,
182-
/// The fee amount was zero when the fee specification extrinsic is
183-
/// being used.
184-
FeeCannotBeZero,
149+
/// The fee is zero.
150+
ZeroFee,
151+
/// The transfering asset amount is zero.
152+
ZeroAmount,
185153
/// The number of assets to be sent is over the maximum
186154
TooManyAssetsBeingSent,
187155
/// The specified index does not exist in a MultiAssets struct
@@ -281,10 +249,6 @@ pub mod module {
281249
) -> DispatchResult {
282250
let who = ensure_signed(origin)?;
283251
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
284-
// Zero fee is an error
285-
if fee.is_zero() {
286-
return Err(Error::<T>::FeeCannotBeZero.into());
287-
}
288252

289253
Self::do_transfer_with_fee(who, currency_id, amount, fee, dest, dest_weight)
290254
}
@@ -323,10 +287,6 @@ pub mod module {
323287
let asset: MultiAsset = (*asset).try_into().map_err(|()| Error::<T>::BadVersion)?;
324288
let fee: MultiAsset = (*fee).try_into().map_err(|()| Error::<T>::BadVersion)?;
325289
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
326-
// Zero fee is an error
327-
if fungible_amount(&fee).is_zero() {
328-
return Err(Error::<T>::FeeCannotBeZero.into());
329-
}
330290

331291
Self::do_transfer_multiasset_with_fee(who, asset, fee, dest, dest_weight)
332292
}
@@ -392,7 +352,7 @@ pub mod module {
392352
// We first grab the fee
393353
let fee: &MultiAsset = assets.get(fee_item as usize).ok_or(Error::<T>::AssetIndexNonExistent)?;
394354

395-
Self::do_transfer_multiassets(who, assets.clone(), fee.clone(), dest, dest_weight, true)
355+
Self::do_transfer_multiassets(who, assets.clone(), fee.clone(), dest, dest_weight)
396356
}
397357
}
398358

@@ -404,26 +364,13 @@ pub mod module {
404364
dest: MultiLocation,
405365
dest_weight: Weight,
406366
) -> DispatchResult {
407-
let location: MultiLocation = T::CurrencyIdConvert::convert(currency_id.clone())
408-
.ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
367+
let location: MultiLocation =
368+
T::CurrencyIdConvert::convert(currency_id).ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
369+
370+
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
409371

410372
let asset: MultiAsset = (location, amount.into()).into();
411-
Self::do_transfer_multiassets(
412-
who.clone(),
413-
vec![asset.clone()].into(),
414-
asset,
415-
dest.clone(),
416-
dest_weight,
417-
false,
418-
)?;
419-
420-
Self::deposit_event(Event::<T>::Transferred {
421-
sender: who,
422-
currency_id,
423-
amount,
424-
dest,
425-
});
426-
Ok(())
373+
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight)
427374
}
428375

429376
fn do_transfer_with_fee(
@@ -434,8 +381,11 @@ pub mod module {
434381
dest: MultiLocation,
435382
dest_weight: Weight,
436383
) -> DispatchResult {
437-
let location: MultiLocation = T::CurrencyIdConvert::convert(currency_id.clone())
438-
.ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
384+
let location: MultiLocation =
385+
T::CurrencyIdConvert::convert(currency_id).ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
386+
387+
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
388+
ensure!(!fee.is_zero(), Error::<T>::ZeroFee);
439389

440390
let asset = (location.clone(), amount.into()).into();
441391
let fee_asset: MultiAsset = (location, fee.into()).into();
@@ -445,16 +395,7 @@ pub mod module {
445395
assets.push(asset);
446396
assets.push(fee_asset.clone());
447397

448-
Self::do_transfer_multiassets(who.clone(), assets, fee_asset, dest.clone(), dest_weight, false)?;
449-
450-
Self::deposit_event(Event::<T>::TransferredWithFee {
451-
sender: who,
452-
currency_id,
453-
fee,
454-
amount,
455-
dest,
456-
});
457-
Ok(())
398+
Self::do_transfer_multiassets(who, assets, fee_asset, dest, dest_weight)
458399
}
459400

460401
fn do_transfer_multiasset(
@@ -463,30 +404,7 @@ pub mod module {
463404
dest: MultiLocation,
464405
dest_weight: Weight,
465406
) -> DispatchResult {
466-
if !asset.is_fungible(None) {
467-
return Err(Error::<T>::NotFungible.into());
468-
}
469-
470-
if fungible_amount(&asset).is_zero() {
471-
return Ok(());
472-
}
473-
474-
Self::do_transfer_multiassets(
475-
who.clone(),
476-
vec![asset.clone()].into(),
477-
asset.clone(),
478-
dest.clone(),
479-
dest_weight,
480-
false,
481-
)?;
482-
483-
Self::deposit_event(Event::<T>::TransferredMultiAsset {
484-
sender: who,
485-
asset,
486-
dest,
487-
});
488-
489-
Ok(())
407+
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight)
490408
}
491409

492410
fn do_transfer_multiasset_with_fee(
@@ -496,27 +414,12 @@ pub mod module {
496414
dest: MultiLocation,
497415
dest_weight: Weight,
498416
) -> DispatchResult {
499-
if !asset.is_fungible(None) || !fee.is_fungible(None) {
500-
return Err(Error::<T>::NotFungible.into());
501-
}
502-
503-
if fungible_amount(&asset).is_zero() {
504-
return Ok(());
505-
}
506-
507417
// Push contains saturated addition, so we should be able to use it safely
508418
let mut assets = MultiAssets::new();
509-
assets.push(asset.clone());
419+
assets.push(asset);
510420
assets.push(fee.clone());
511421

512-
Self::do_transfer_multiassets(who.clone(), assets, fee.clone(), dest.clone(), dest_weight, false)?;
513-
514-
Self::deposit_event(Event::<T>::TransferredMultiAssetWithFee {
515-
sender: who,
516-
asset,
517-
fee,
518-
dest,
519-
});
422+
Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight)?;
520423

521424
Ok(())
522425
}
@@ -538,6 +441,7 @@ pub mod module {
538441
for (currency_id, amount) in &currencies {
539442
let location: MultiLocation = T::CurrencyIdConvert::convert(currency_id.clone())
540443
.ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
444+
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
541445
// Push contains saturated addition, so we should be able to use it safely
542446
assets.push((location, (*amount).into()).into())
543447
}
@@ -549,14 +453,7 @@ pub mod module {
549453

550454
let fee: MultiAsset = (fee_location, (*fee_amount).into()).into();
551455

552-
Self::do_transfer_multiassets(who.clone(), assets, fee, dest.clone(), dest_weight, false)?;
553-
554-
Self::deposit_event(Event::<T>::TransferredMultiCurrencies {
555-
sender: who,
556-
currencies,
557-
dest,
558-
});
559-
Ok(())
456+
Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight)
560457
}
561458

562459
fn do_transfer_multiassets(
@@ -565,7 +462,6 @@ pub mod module {
565462
fee: MultiAsset,
566463
dest: MultiLocation,
567464
dest_weight: Weight,
568-
deposit_event: bool,
569465
) -> DispatchResult {
570466
ensure!(
571467
assets.len() <= T::MaxAssetsForTransfer::get(),
@@ -575,12 +471,10 @@ pub mod module {
575471
// We check that all assets are valid and share the same reserve
576472
for i in 0..assets.len() {
577473
let asset = assets.get(i).ok_or(Error::<T>::AssetIndexNonExistent)?;
578-
if !asset.is_fungible(None) {
579-
return Err(Error::<T>::NotFungible.into());
580-
}
581-
if fungible_amount(asset).is_zero() {
582-
return Ok(());
583-
}
474+
ensure!(
475+
matches!(asset.fun, Fungibility::Fungible(x) if !x.is_zero()),
476+
Error::<T>::InvalidAsset
477+
);
584478
ensure!(
585479
fee.reserve() == asset.reserve(),
586480
Error::<T>::DistinctReserveForAssetAndFee
@@ -589,13 +483,24 @@ pub mod module {
589483

590484
let (transfer_kind, dest, reserve, recipient) = Self::transfer_kind(&fee, &dest)?;
591485
let mut msg = match transfer_kind {
592-
SelfReserveAsset => {
593-
Self::transfer_self_reserve_asset(assets.clone(), fee, dest.clone(), recipient, dest_weight)?
594-
}
595-
ToReserve => Self::transfer_to_reserve(assets.clone(), fee, dest.clone(), recipient, dest_weight)?,
596-
ToNonReserve => {
597-
Self::transfer_to_non_reserve(assets.clone(), fee, reserve, dest.clone(), recipient, dest_weight)?
486+
SelfReserveAsset => Self::transfer_self_reserve_asset(
487+
assets.clone(),
488+
fee.clone(),
489+
dest.clone(),
490+
recipient,
491+
dest_weight,
492+
)?,
493+
ToReserve => {
494+
Self::transfer_to_reserve(assets.clone(), fee.clone(), dest.clone(), recipient, dest_weight)?
598495
}
496+
ToNonReserve => Self::transfer_to_non_reserve(
497+
assets.clone(),
498+
fee.clone(),
499+
reserve,
500+
dest.clone(),
501+
recipient,
502+
dest_weight,
503+
)?,
599504
};
600505

601506
let origin_location = T::AccountIdToMultiLocation::convert(who.clone());
@@ -607,13 +512,12 @@ pub mod module {
607512
Error::<T>::XcmExecutionFailed
608513
})?;
609514

610-
if deposit_event {
611-
Self::deposit_event(Event::<T>::TransferredMultiAssets {
612-
sender: who,
613-
assets,
614-
dest,
615-
});
616-
}
515+
Self::deposit_event(Event::<T>::TransferredMultiAssets {
516+
sender: who,
517+
assets,
518+
fee,
519+
dest,
520+
});
617521

618522
Ok(())
619523
}

xtokens/src/tests.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ fn send_with_zero_fee_should_yield_an_error() {
847847
),
848848
40,
849849
),
850-
Error::<para::Runtime>::FeeCannotBeZero
850+
Error::<para::Runtime>::ZeroFee
851851
);
852852
});
853853
}
@@ -1048,3 +1048,54 @@ fn specifying_a_non_existent_asset_index_should_fail() {
10481048
);
10491049
});
10501050
}
1051+
1052+
#[test]
1053+
fn send_with_zero_amount() {
1054+
TestNet::reset();
1055+
1056+
ParaA::execute_with(|| {
1057+
assert_noop!(
1058+
ParaXTokens::transfer(
1059+
Some(ALICE).into(),
1060+
CurrencyId::B,
1061+
0,
1062+
Box::new(
1063+
(
1064+
Parent,
1065+
Parachain(2),
1066+
Junction::AccountId32 {
1067+
network: NetworkId::Any,
1068+
id: BOB.into(),
1069+
},
1070+
)
1071+
.into()
1072+
),
1073+
40,
1074+
),
1075+
Error::<para::Runtime>::ZeroAmount
1076+
);
1077+
1078+
assert_noop!(
1079+
ParaXTokens::transfer_multicurrencies(
1080+
Some(ALICE).into(),
1081+
vec![(CurrencyId::B, 0), (CurrencyId::B1, 50)],
1082+
1,
1083+
Box::new(
1084+
(
1085+
Parent,
1086+
Parachain(2),
1087+
Junction::AccountId32 {
1088+
network: NetworkId::Any,
1089+
id: BOB.into(),
1090+
},
1091+
)
1092+
.into()
1093+
),
1094+
40,
1095+
),
1096+
Error::<para::Runtime>::ZeroAmount
1097+
);
1098+
});
1099+
1100+
// TODO: should have more tests after https://github.com/paritytech/polkadot/issues/4996
1101+
}

0 commit comments

Comments
 (0)