Implement `From<AccountId20> for Location`
Closed this issue · 1 comments
Motivation
Configuring FeeManager
enforces the boundary Into<[u8; 32]>
for the AccountId
type.
Here is how it works currently:
Configuration:
type FeeManager = XcmFeeManagerFromComponents<
IsChildSystemParachain<primitives::Id>,
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
>;
XcmToFeeAccount
struct:
/// A `HandleFee` implementation that simply deposits the fees into a specific on-chain
/// `ReceiverAccount`.
///
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If
/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be
/// logged and the fee burned.
pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
);
impl<
AssetTransactor: TransactAsset,
AccountId: Clone + Into<[u8; 32]>,
ReceiverAccount: Get<AccountId>,
> HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
{
fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
deposit_or_burn_fee::<AssetTransactor, _>(fee, context, ReceiverAccount::get());
Assets::new()
}
}
deposit_or_burn_fee()
function:
/// Try to deposit the given fee in the specified account.
/// Burns the fee in case of a failure.
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 32]>>(
fee: Assets,
context: Option<&XcmContext>,
receiver: AccountId,
) {
let dest = AccountId32 { network: None, id: receiver.into() }.into();
for asset in fee.into_inner() {
if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
log::trace!(
target: "xcm::fees",
"`AssetTransactor::deposit_asset` returned error: {:?}. Burning fee: {:?}. \
They might be burned.",
e, asset,
);
}
}
}
In order to use another AccountId
type (for example, 20 byte addresses for compatibility with Ethereum or Bitcoin), one has to duplicate the code as the following (roughly changing every 32
to 20
):
/// A `HandleFee` implementation that simply deposits the fees into a specific on-chain
/// `ReceiverAccount`.
///
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If
/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be
/// logged and the fee burned.
pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
);
impl<
AssetTransactor: TransactAsset,
AccountId: Clone + Into<[u8; 20]>,
ReceiverAccount: Get<AccountId>,
> HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
{
fn handle_fee(fee: XcmAssets, context: Option<&XcmContext>, _reason: FeeReason) -> XcmAssets {
deposit_or_burn_fee::<AssetTransactor, _>(fee, context, ReceiverAccount::get());
XcmAssets::new()
}
}
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 20]>>(
fee: XcmAssets,
context: Option<&XcmContext>,
receiver: AccountId,
) {
let dest = AccountKey20 { network: None, key: receiver.into() }.into();
for asset in fee.into_inner() {
if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
log::trace!(
target: "xcm::fees",
"`AssetTransactor::deposit_asset` returned error: {:?}. Burning fee: {:?}. \
They might be burned.",
e, asset,
);
}
}
}
This results in code duplication, and it is not an elegant solution.
I submitted and merged paritytech/polkadot-sdk#4959 which relaxed the trait bound for XcmFeeToAccount
, and now it accepts everything that implements Get<Location>
.
When this change is released in the next polkadot-sdk
version:
AccountId20
should also implement From
trait to Location
in order to allow frontier
users to easily configure FeeManager
.
I'll soon submit the PR that solves this issue