Skip to content

Commit

Permalink
XcmTransfer Trait (#892)
Browse files Browse the repository at this point in the history
* Add more methods on XcmTransfer trait

* Add Transferred for XcmTransfer

* fix tests

* fix clippy
  • Loading branch information
zjb0807 authored Mar 13, 2023
1 parent 6df51b3 commit a730f79
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 30 deletions.
52 changes: 44 additions & 8 deletions traits/src/xcm_transfer.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,67 @@
use frame_support::dispatch::DispatchResult;
use frame_support::dispatch::DispatchError;
use sp_std::vec::Vec;
use xcm::v3::prelude::*;

pub struct Transferred<AccountId> {
pub sender: AccountId,
pub assets: MultiAssets,
pub fee: MultiAsset,
pub dest: MultiLocation,
}

/// Abstraction over cross-chain token transfers.
pub trait XcmTransfer<AccountId, Balance, CurrencyId> {
/// Transfer native currencies.
/// Transfer local assets with given `CurrencyId` and `Amount`.
fn transfer(
who: AccountId,
currency_id: CurrencyId,
amount: Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult;
) -> Result<Transferred<AccountId>, DispatchError>;

/// Transfer `MultiAsset`
fn transfer_multi_asset(
/// Transfer `MultiAsset` assets.
fn transfer_multiasset(
who: AccountId,
asset: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult;
) -> Result<Transferred<AccountId>, DispatchError>;

/// Transfer `MultiAssetWithFee`
/// Transfer native currencies specifying the fee and amount as separate.
fn transfer_with_fee(
who: AccountId,
currency_id: CurrencyId,
amount: Balance,
fee: Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<AccountId>, DispatchError>;

/// Transfer `MultiAsset` specifying the fee and amount as separate.
fn transfer_multiasset_with_fee(
who: AccountId,
asset: MultiAsset,
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult;
) -> Result<Transferred<AccountId>, DispatchError>;

/// Transfer several currencies specifying the item to be used as fee.
fn transfer_multicurrencies(
who: AccountId,
currencies: Vec<(CurrencyId, Balance)>,
fee_item: u32,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<AccountId>, DispatchError>;

/// Transfer several `MultiAsset` specifying the item to be used as fee.
fn transfer_multiassets(
who: AccountId,
assets: MultiAssets,
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<AccountId>, DispatchError>;
}
82 changes: 60 additions & 22 deletions xtokens/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ use xcm_executor::traits::WeightBounds;
pub use module::*;
use orml_traits::{
location::{Parse, Reserve},
xcm_transfer::Transferred,
GetByKey, XcmTransfer,
};

Expand Down Expand Up @@ -220,7 +221,7 @@ pub mod module {
) -> DispatchResult {
let who = ensure_signed(origin)?;
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
Self::do_transfer(who, currency_id, amount, dest, dest_weight_limit)
Self::do_transfer(who, currency_id, amount, dest, dest_weight_limit).map(|_| ())
}

/// Transfer `MultiAsset`.
Expand All @@ -246,7 +247,7 @@ pub mod module {
let who = ensure_signed(origin)?;
let asset: MultiAsset = (*asset).try_into().map_err(|()| Error::<T>::BadVersion)?;
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
Self::do_transfer_multiasset(who, asset, dest, dest_weight_limit)
Self::do_transfer_multiasset(who, asset, dest, dest_weight_limit).map(|_| ())
}

/// Transfer native currencies specifying the fee and amount as
Expand Down Expand Up @@ -283,7 +284,7 @@ pub mod module {
let who = ensure_signed(origin)?;
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;

Self::do_transfer_with_fee(who, currency_id, amount, fee, dest, dest_weight_limit)
Self::do_transfer_with_fee(who, currency_id, amount, fee, dest, dest_weight_limit).map(|_| ())
}

/// Transfer `MultiAsset` specifying the fee and amount as separate.
Expand Down Expand Up @@ -321,7 +322,7 @@ pub mod module {
let fee: MultiAsset = (*fee).try_into().map_err(|()| Error::<T>::BadVersion)?;
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;

Self::do_transfer_multiasset_with_fee(who, asset, fee, dest, dest_weight_limit)
Self::do_transfer_multiasset_with_fee(who, asset, fee, dest, dest_weight_limit).map(|_| ())
}

/// Transfer several currencies specifying the item to be used as fee
Expand Down Expand Up @@ -351,7 +352,7 @@ pub mod module {
let who = ensure_signed(origin)?;
let dest: MultiLocation = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;

Self::do_transfer_multicurrencies(who, currencies, fee_item, dest, dest_weight_limit)
Self::do_transfer_multicurrencies(who, currencies, fee_item, dest, dest_weight_limit).map(|_| ())
}

/// Transfer several `MultiAsset` specifying the item to be used as fee
Expand Down Expand Up @@ -385,7 +386,7 @@ pub mod module {
// We first grab the fee
let fee: &MultiAsset = assets.get(fee_item as usize).ok_or(Error::<T>::AssetIndexNonExistent)?;

Self::do_transfer_multiassets(who, assets.clone(), fee.clone(), dest, dest_weight_limit)
Self::do_transfer_multiassets(who, assets.clone(), fee.clone(), dest, dest_weight_limit).map(|_| ())
}
}

Expand All @@ -396,7 +397,7 @@ pub mod module {
amount: T::Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
let location: MultiLocation =
T::CurrencyIdConvert::convert(currency_id).ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;

Expand All @@ -417,7 +418,7 @@ pub mod module {
fee: T::Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
let location: MultiLocation =
T::CurrencyIdConvert::convert(currency_id).ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;

Expand All @@ -444,7 +445,7 @@ pub mod module {
asset: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight_limit)
}

Expand All @@ -454,15 +455,13 @@ pub mod module {
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
// Push contains saturated addition, so we should be able to use it safely
let mut assets = MultiAssets::new();
assets.push(asset);
assets.push(fee.clone());

Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight_limit)?;

Ok(())
Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight_limit)
}

fn do_transfer_multicurrencies(
Expand All @@ -471,7 +470,7 @@ pub mod module {
fee_item: u32,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
ensure!(
currencies.len() <= T::MaxAssetsForTransfer::get(),
Error::<T>::TooManyAssetsBeingSent
Expand Down Expand Up @@ -513,7 +512,7 @@ pub mod module {
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
ensure!(
assets.len() <= T::MaxAssetsForTransfer::get(),
Error::<T>::TooManyAssetsBeingSent
Expand Down Expand Up @@ -621,13 +620,18 @@ pub mod module {
}

Self::deposit_event(Event::<T>::TransferredMultiAssets {
sender: who.clone(),
assets: assets.clone(),
fee: fee.clone(),
dest,
});

Ok(Transferred {
sender: who,
assets,
fee,
dest,
});

Ok(())
})
}

/// Execute and send xcm with given assets and fee to dest chain or
Expand Down Expand Up @@ -947,30 +951,64 @@ pub mod module {
amount: T::Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer(who, currency_id, amount, dest, dest_weight_limit)
}

#[require_transactional]
fn transfer_multi_asset(
fn transfer_multiasset(
who: T::AccountId,
asset: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_multiasset(who, asset, dest, dest_weight_limit)
}

#[require_transactional]
fn transfer_with_fee(
who: T::AccountId,
currency_id: T::CurrencyId,
amount: T::Balance,
fee: T::Balance,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_with_fee(who, currency_id, amount, fee, dest, dest_weight_limit)
}

#[require_transactional]
fn transfer_multiasset_with_fee(
who: T::AccountId,
asset: MultiAsset,
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> DispatchResult {
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_multiasset_with_fee(who, asset, fee, dest, dest_weight_limit)
}

#[require_transactional]
fn transfer_multicurrencies(
who: T::AccountId,
currencies: Vec<(T::CurrencyId, T::Balance)>,
fee_item: u32,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_multicurrencies(who, currencies, fee_item, dest, dest_weight_limit)
}

#[require_transactional]
fn transfer_multiassets(
who: T::AccountId,
assets: MultiAssets,
fee: MultiAsset,
dest: MultiLocation,
dest_weight_limit: WeightLimit,
) -> Result<Transferred<T::AccountId>, DispatchError> {
Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight_limit)
}
}
}

Expand Down

0 comments on commit a730f79

Please sign in to comment.