Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transfer_with_transact rough implementation #4

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion traits/src/xcm_transfer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use frame_support::dispatch::DispatchResult;
use frame_support::weights::Weight;
use xcm::latest::prelude::*;
use sp_std::vec::Vec;
use xcm::{latest::prelude::*, DoubleEncoded};

/// Abstraction over cross-chain token transfers.
pub trait XcmTransfer<AccountId, Balance, CurrencyId> {
Expand All @@ -11,6 +12,9 @@ pub trait XcmTransfer<AccountId, Balance, CurrencyId> {
amount: Balance,
dest: MultiLocation,
dest_weight: Weight,
//maybe_call: Option<Vec<u8>>,
//maybe_transact_call: Option<DoubleEncoded<Call>>,
//maybe_transact_fee: Balance,
) -> DispatchResult;

/// Transfer `MultiAsset`
Expand Down
155 changes: 142 additions & 13 deletions xtokens/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use sp_runtime::{
};
use sp_std::{prelude::*, result::Result};

use xcm::prelude::*;
use xcm::{prelude::*, DoubleEncoded};
use xcm_executor::traits::{InvertLocation, WeightBounds};

pub use module::*;
Expand Down Expand Up @@ -94,6 +94,8 @@ pub mod module {
/// XCM executor.
type XcmExecutor: ExecuteXcm<Self::Call>;

type XcmSender: SendXcm;

/// MultiLocation filter
type MultiLocationsFilter: Contains<MultiLocation>;

Expand Down Expand Up @@ -195,6 +197,8 @@ pub mod module {
/// received. Receiving depends on if the XCM message could be delivered
/// by the network, and if the receiving chain would handle
/// messages correctly.
//#[pallet::weight(Pallet::<T>::weight_of_transfer(currency_id.clone(), *amount, dest, maybe_transact_call,
//#[pallet::weight(Pallet::<T>::weight_of_transfer(currency_id.clone(), dest_weight))]
#[pallet::weight(Pallet::<T>::weight_of_transfer(currency_id.clone(), *amount, dest))]
#[transactional]
pub fn transfer(
Expand All @@ -209,6 +213,31 @@ pub mod module {
Self::do_transfer(who, currency_id, amount, dest, dest_weight)
}

#[pallet::weight(0)]
#[transactional]
pub fn transfer_with_transact(
origin: OriginFor<T>,
currency_id: T::CurrencyId,
amount: T::Balance,
dest_id: u32,
dest_weight: Weight,
encoded_call_data: Vec<u8>,
//maybe_transact_call: Option<DoubleEncoded<T::Call>>,
transact_fee: T::Balance,
) -> DispatchResult {
let who = ensure_signed(origin)?;

Self::do_transfer_with_transact(
who,
currency_id,
amount,
dest_id,
dest_weight,
encoded_call_data,
transact_fee,
)
}

/// Transfer `MultiAsset`.
///
/// `dest_weight` is the weight for XCM execution on the dest chain, and
Expand Down Expand Up @@ -371,7 +400,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)
Self::do_transfer_multiassets(who, assets.clone(), fee.clone(), dest, dest_weight, None)
}
}

Expand All @@ -392,8 +421,90 @@ pub mod module {
Error::<T>::NotSupportedMultiLocation
);

let asset: MultiAsset = (location, amount.into()).into();
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight)
let asset: MultiAsset = (location.clone(), amount.into()).into();

Self::do_transfer_multiassets(
who.clone(),
vec![asset.clone()].into(),
asset,
dest.clone(),
dest_weight,
None,
)
}

fn do_transfer_with_transact(
who: T::AccountId,
currency_id: T::CurrencyId,
amount: T::Balance,
dest_id: u32,
dest_weight: Weight,
encoded_call_data: Vec<u8>,
transact_fee: T::Balance,
) -> DispatchResult {
let location: MultiLocation =
T::CurrencyIdConvert::convert(currency_id).ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;

let origin_location = T::AccountIdToMultiLocation::convert(who.clone());

let mut dest_chain_location: MultiLocation = (1, Parachain(dest_id)).into();
let _ = dest_chain_location.append_with(origin_location.clone().interior);

ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
ensure!(
T::MultiLocationsFilter::contains(&dest_chain_location),
Error::<T>::NotSupportedMultiLocation
);

let asset: MultiAsset = (location.clone(), amount.into()).into();
let transact_fee_asset: MultiAsset = (location, transact_fee.into()).into();

let mut override_dest = T::SelfLocation::get();
let _ = override_dest.append_with(origin_location.clone().interior);

let _ = Self::do_transfer_multiassets(
who.clone(),
vec![asset.clone()].into(),
asset,
dest_chain_location.clone(),
dest_weight,
// TODO: not a todo, but this part is important
Some(override_dest),
);

let origin_location = T::AccountIdToMultiLocation::convert(who.clone());
// TODO: is this the best way to get dest location
let target_chain_location = dest_chain_location.chain_part().ok_or(Error::<T>::AssetHasNoReserve)?;
let ancestry = T::LocationInverter::ancestry();

let transact_fee_asset = transact_fee_asset
.clone()
.reanchored(&target_chain_location, &ancestry)
.map_err(|_| Error::<T>::CannotReanchor)?;

//let double_encoded: DoubleEncoded<T::Call> = call.into();
let mut transact_fee_assets = MultiAssets::new();
transact_fee_assets.push(transact_fee_asset.clone());
let instructions = Xcm(vec![
DescendOrigin(origin_location.clone().interior),
WithdrawAsset(transact_fee_assets),
BuyExecution {
fees: transact_fee_asset,
weight_limit: WeightLimit::Limited(dest_weight),
},
Transact {
origin_type: OriginKind::SovereignAccount,
require_weight_at_most: dest_weight,
call: encoded_call_data.into(),
//call,
},
// TODO:
// RefundSurplus
// DepositAsset(user_account or back to sovereign_account)
]);

let _res = T::XcmSender::send_xcm(target_chain_location.clone(), instructions);
Ok(())
}

fn do_transfer_with_fee(
Expand Down Expand Up @@ -422,7 +533,7 @@ pub mod module {
assets.push(asset);
assets.push(fee_asset.clone());

Self::do_transfer_multiassets(who, assets, fee_asset, dest, dest_weight)
Self::do_transfer_multiassets(who, assets, fee_asset, dest, dest_weight, None)
}

fn do_transfer_multiasset(
Expand All @@ -431,7 +542,7 @@ pub mod module {
dest: MultiLocation,
dest_weight: Weight,
) -> DispatchResult {
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight)
Self::do_transfer_multiassets(who, vec![asset.clone()].into(), asset, dest, dest_weight, None)
}

fn do_transfer_multiasset_with_fee(
Expand All @@ -446,7 +557,7 @@ pub mod module {
assets.push(asset);
assets.push(fee.clone());

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

Ok(())
}
Expand Down Expand Up @@ -490,7 +601,7 @@ pub mod module {

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

Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight)
Self::do_transfer_multiassets(who, assets, fee, dest, dest_weight, None)
}

fn do_transfer_multiassets(
Expand All @@ -499,6 +610,10 @@ pub mod module {
fee: MultiAsset,
dest: MultiLocation,
dest_weight: Weight,
//maybe_transact_call: Option<Vec<u8>>,
//maybe_transact_call: Option<DoubleEncoded<T::Call>>,
//maybe_transact_fee_asset: Option<MultiAsset>,
maybe_recipient_override: Option<MultiLocation>,
) -> DispatchResult {
ensure!(
assets.len() <= T::MaxAssetsForTransfer::get(),
Expand Down Expand Up @@ -571,22 +686,23 @@ pub mod module {

// Second xcm send to dest chain.
Self::execute_and_send_reserve_kind_xcm(
origin_location,
origin_location.clone(),
assets_to_dest,
fee_to_dest,
non_fee_reserve,
&dest,
None,
dest_weight,
// fee_reserve != non_fee_reserve
)?;
} else {
Self::execute_and_send_reserve_kind_xcm(
origin_location,
origin_location.clone(),
assets.clone(),
fee.clone(),
non_fee_reserve,
non_fee_reserve.clone(),
&dest,
None,
maybe_recipient_override,
dest_weight,
)?;
}
Expand Down Expand Up @@ -765,6 +881,7 @@ pub mod module {
let (dest, recipient) = Self::ensure_valid_dest(dest)?;

let self_location = T::SelfLocation::get();
// TODO: skip check
ensure!(dest != self_location, Error::<T>::NotCrossChainTransfer);
let reserve = reserve.ok_or(Error::<T>::AssetHasNoReserve)?;
let transfer_kind = if reserve == self_location {
Expand All @@ -784,6 +901,9 @@ pub mod module {
fn weight_of_transfer_multiasset(asset: &VersionedMultiAsset, dest: &VersionedMultiLocation) -> Weight {
let asset: Result<MultiAsset, _> = asset.clone().try_into();
let dest = dest.clone().try_into();
// TODO:
// if maybe_transact_call, include Transact instruction with
// required_weight_at_most
if let (Ok(asset), Ok(dest)) = (asset, dest) {
if let Ok((transfer_kind, dest, _, reserve)) =
Self::transfer_kind(T::ReserveProvider::reserve(&asset), &dest)
Expand Down Expand Up @@ -816,7 +936,13 @@ pub mod module {
}

/// Returns weight of `transfer` call.
fn weight_of_transfer(currency_id: T::CurrencyId, amount: T::Balance, dest: &VersionedMultiLocation) -> Weight {
fn weight_of_transfer(
currency_id: T::CurrencyId,
amount: T::Balance,
dest: &VersionedMultiLocation,
// maybe_transact_call: Option<Vec<u8>>,
// dest_weight: Weight,
) -> Weight {
if let Some(location) = T::CurrencyIdConvert::convert(currency_id) {
let asset = (location, amount.into()).into();
Self::weight_of_transfer_multiasset(&asset, dest)
Expand Down Expand Up @@ -908,6 +1034,9 @@ pub mod module {
amount: T::Balance,
dest: MultiLocation,
dest_weight: Weight,
//maybe_transact_call: Option<Vec<u8>>,
//maybe_transact_call: Option<DoubleEncoded<T::Call>>,
//maybe_transact_fee: T::Balance,
) -> DispatchResult {
Self::do_transfer(who, currency_id, amount, dest, dest_weight)
}
Expand Down