mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 11:41:02 +00:00
Implement transfer_asset on CurrencyAdapter (#4549)
* Implement transfer_asset on CurrencyAdapter * Use Currency::transfer in transfer_asset * Add a test to assert that Currency::transfer was indeed used * Remove superfluous balance conversion to u128 * Rename transfer_asset and beam_asset Co-authored-by: Giles Cope <gilescope@gmail.com>
This commit is contained in:
@@ -17,8 +17,8 @@
|
||||
//! Adapters to work with `frame_support::traits::Currency` through XCM.
|
||||
|
||||
use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons};
|
||||
use sp_runtime::traits::{CheckedSub, SaturatedConversion};
|
||||
use sp_std::{convert::TryInto, marker::PhantomData, result};
|
||||
use sp_runtime::traits::CheckedSub;
|
||||
use sp_std::{marker::PhantomData, result};
|
||||
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result};
|
||||
use xcm_executor::{
|
||||
traits::{Convert, MatchesFungible, TransactAsset},
|
||||
@@ -31,8 +31,6 @@ enum Error {
|
||||
AssetNotFound,
|
||||
/// `MultiLocation` to `AccountId` conversion failed.
|
||||
AccountIdConversionFailed,
|
||||
/// `u128` amount to currency `Balance` conversion failed.
|
||||
AmountToBalanceConversionFailed,
|
||||
}
|
||||
|
||||
impl From<Error> for XcmError {
|
||||
@@ -41,8 +39,6 @@ impl From<Error> for XcmError {
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::AssetNotFound,
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,27 +145,37 @@ impl<
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount: u128 =
|
||||
Matcher::matches_fungible(&what).ok_or(Error::AssetNotFound)?.saturated_into();
|
||||
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotFound)?;
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount =
|
||||
amount.try_into().map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let _imbalance = Currency::deposit_creating(&who, balance_amount);
|
||||
let _imbalance = Currency::deposit_creating(&who, amount);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "withdraw_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount: u128 =
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?.saturated_into();
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount =
|
||||
amount.try_into().map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
Currency::withdraw(&who, balance_amount, WithdrawReasons::TRANSFER, AllowDeath)
|
||||
Currency::withdraw(&who, amount, WithdrawReasons::TRANSFER, AllowDeath)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
|
||||
Ok(what.clone().into())
|
||||
}
|
||||
|
||||
fn internal_transfer_asset(
|
||||
asset: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "internal_transfer_asset asset: {:?}, from: {:?}, to: {:?}", asset, from, to);
|
||||
let amount = Matcher::matches_fungible(asset).ok_or(Error::AssetNotFound)?;
|
||||
let from =
|
||||
AccountIdConverter::convert_ref(from).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let to =
|
||||
AccountIdConverter::convert_ref(to).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
Currency::transfer(&from, &to, amount, AllowDeath)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
|
||||
Ok(asset.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,14 +118,14 @@ impl<
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
> TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>
|
||||
{
|
||||
fn transfer_asset(
|
||||
fn internal_transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"transfer_asset what: {:?}, from: {:?}, to: {:?}",
|
||||
"internal_transfer_asset what: {:?}, from: {:?}, to: {:?}",
|
||||
what, from, to
|
||||
);
|
||||
// Check we handle this asset.
|
||||
@@ -325,12 +325,12 @@ impl<
|
||||
>::withdraw_asset(what, who)
|
||||
}
|
||||
|
||||
fn transfer_asset(
|
||||
fn internal_transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset(
|
||||
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::internal_transfer_asset(
|
||||
what, from, to,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ parameter_types! {
|
||||
pub type SovereignAccountOf =
|
||||
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<KusamaNetwork, AccountId>);
|
||||
|
||||
pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
pub type LocalCurrencyAdapter = XcmCurrencyAdapter<
|
||||
Balances,
|
||||
IsConcrete<KsmLocation>,
|
||||
SovereignAccountOf,
|
||||
@@ -131,6 +131,8 @@ pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
CheckAccount,
|
||||
>;
|
||||
|
||||
pub type LocalAssetTransactor = (LocalCurrencyAdapter,);
|
||||
|
||||
type LocalOriginConverter = (
|
||||
SovereignSignedViaLocation<SovereignAccountOf, Origin>,
|
||||
ChildParachainAsNative<origin::Origin, Origin>,
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
mod mock;
|
||||
|
||||
use mock::{
|
||||
kusama_like_with_balances, AccountId, Balance, Balances, BaseXcmWeight, XcmConfig, CENTS,
|
||||
kusama_like_with_balances, AccountId, Balance, Balances, BaseXcmWeight, System, XcmConfig,
|
||||
CENTS,
|
||||
};
|
||||
use polkadot_parachain::primitives::Id as ParaId;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
@@ -66,6 +67,36 @@ fn withdraw_and_deposit_works() {
|
||||
});
|
||||
}
|
||||
|
||||
/// Scenario:
|
||||
/// Alice simply wants to transfer funds to Bob's account via XCM.
|
||||
///
|
||||
/// Asserts that the balances are updated correctly and the correct events are fired.
|
||||
#[test]
|
||||
fn transfer_asset_works() {
|
||||
let bob = AccountId::new([1u8; 32]);
|
||||
let balances = vec![(ALICE, INITIAL_BALANCE), (bob.clone(), INITIAL_BALANCE)];
|
||||
kusama_like_with_balances(balances).execute_with(|| {
|
||||
let amount = REGISTER_AMOUNT;
|
||||
let weight = BaseXcmWeight::get();
|
||||
// Use `execute_xcm_in_credit` here to pass through the barrier
|
||||
let r = XcmExecutor::<XcmConfig>::execute_xcm_in_credit(
|
||||
AccountId32 { network: NetworkId::Any, id: ALICE.into() },
|
||||
Xcm(vec![TransferAsset {
|
||||
assets: (Here, amount).into(),
|
||||
beneficiary: AccountId32 { network: NetworkId::Any, id: bob.clone().into() }.into(),
|
||||
}]),
|
||||
weight,
|
||||
weight,
|
||||
);
|
||||
System::assert_last_event(
|
||||
pallet_balances::Event::Transfer { from: ALICE, to: bob.clone(), amount }.into(),
|
||||
);
|
||||
assert_eq!(r, Outcome::Complete(weight));
|
||||
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - amount);
|
||||
assert_eq!(Balances::free_balance(bob), INITIAL_BALANCE + amount);
|
||||
});
|
||||
}
|
||||
|
||||
/// Scenario:
|
||||
/// A parachain wants to be notified that a transfer worked correctly.
|
||||
/// It includes a `QueryHolding` order after the deposit to get notified on success.
|
||||
|
||||
Reference in New Issue
Block a user