(
) -> pezframe_support::weights::Weight {
let on_chain_storage_version = ::on_chain_storage_version();
tracing::info!(
target: "runtime::xcm",
?on_chain_storage_version,
"Running migration storage v1 for xcm with storage version",
);
if on_chain_storage_version < 1 {
let mut count = 0;
Queries::::translate::>, _>(|_key, value| {
count += 1;
Some(value.into())
});
StorageVersion::new(1).put::();
tracing::info!(
target: "runtime::xcm",
?on_chain_storage_version,
"Running migration storage v1 for xcm with storage version was complete",
);
// calculate and return migration weights
T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)
} else {
tracing::warn!(
target: "runtime::xcm",
?on_chain_storage_version,
"Attempted to apply migration to v1 but failed because storage version is",
);
T::DbWeight::get().reads(1)
}
}
}
#[pezpallet::call(weight(::WeightInfo))]
impl Pezpallet {
#[pezpallet::call_index(0)]
pub fn send(
origin: OriginFor,
dest: Box,
message: Box>,
) -> DispatchResult {
>::send(origin, dest, message)?;
Ok(())
}
/// Teleport some assets from the local chain to some destination chain.
///
/// **This function is deprecated: Use `limited_teleport_assets` instead.**
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// id `fee_asset_id`. The weight limit for fees is not provided and thus is unlimited,
/// with all fees taken as needed from the asset.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `[Parent,
/// Teyrchain(..)]` to send from teyrchain to teyrchain, or `[Teyrchain(..)]` to send from
/// relay to teyrchain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` chain.
/// - `fee_asset_id`: Id of the asset from `assets` which should be used to pay fees.
#[pezpallet::call_index(1)]
#[allow(deprecated)]
#[deprecated(
note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_teleport_assets` or `transfer_assets`"
)]
pub fn teleport_assets(
origin: OriginFor,
dest: Box,
beneficiary: Box,
assets: Box,
fee_asset_id: Box,
) -> DispatchResult {
Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_id, Unlimited)
}
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve.
///
/// `assets` must have same reserve location and may not be teleportable to `dest`.
/// - `assets` have local reserve: transfer assets to sovereign account of destination
/// chain and forward a notification XCM to `dest` to mint and deposit reserve-based
/// assets to `beneficiary`.
/// - `assets` have destination reserve: burn local assets and forward a notification to
/// `dest` chain to withdraw the reserve assets from this chain's sovereign account and
/// deposit them to `beneficiary`.
/// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move
/// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest`
/// to mint and deposit reserve-based assets to `beneficiary`.
///
/// **This function is deprecated: Use `limited_reserve_transfer_assets` instead.**
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// id `fee_asset_id`. The weight limit for fees is not provided and thus is unlimited,
/// with all fees taken as needed from the asset.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `[Parent,
/// Teyrchain(..)]` to send from teyrchain to teyrchain, or `[Teyrchain(..)]` to send from
/// relay to teyrchain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_id`: Id of the asset from `assets` which should be used to pay fees.
#[pezpallet::call_index(2)]
#[allow(deprecated)]
#[deprecated(
note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_reserve_transfer_assets` or `transfer_assets`"
)]
pub fn reserve_transfer_assets(
origin: OriginFor,
dest: Box,
beneficiary: Box,
assets: Box,
fee_asset_id: Box,
) -> DispatchResult {
Self::do_reserve_transfer_assets(
origin,
dest,
beneficiary,
assets,
fee_asset_id,
Unlimited,
)
}
/// Execute an XCM message from a local, signed, origin.
///
/// An event is deposited indicating whether `msg` could be executed completely or only
/// partially.
///
/// No more than `max_weight` will be used in its attempted execution. If this is less than
/// the maximum amount of weight that the message could take to be executed, then no
/// execution attempt will be made.
#[pezpallet::call_index(3)]
#[pezpallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))]
pub fn execute(
origin: OriginFor,
message: Box::RuntimeCall>>,
max_weight: Weight,
) -> DispatchResultWithPostInfo {
let weight_used =
>::execute(origin, message, max_weight)?;
Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into())
}
/// Extoll that a particular destination can be communicated with through a particular
/// version of XCM.
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The destination that is being described.
/// - `xcm_version`: The latest version of XCM that `location` supports.
#[pezpallet::call_index(4)]
pub fn force_xcm_version(
origin: OriginFor,
location: Box,
version: XcmVersion,
) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
let location = *location;
SupportedVersion::::insert(XCM_VERSION, LatestVersionedLocation(&location), version);
Self::deposit_event(Event::SupportedVersionChanged { location, version });
Ok(())
}
/// Set a safe XCM version (the version that XCM should be encoded with if the most recent
/// version a destination can accept is unknown).
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `maybe_xcm_version`: The default XCM encoding version, or `None` to disable.
#[pezpallet::call_index(5)]
pub fn force_default_xcm_version(
origin: OriginFor,
maybe_xcm_version: Option,
) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
SafeXcmVersion::::set(maybe_xcm_version);
Ok(())
}
/// Ask a location to notify us regarding their XCM version and any changes to it.
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The location to which we should subscribe for XCM version notifications.
#[pezpallet::call_index(6)]
pub fn force_subscribe_version_notify(
origin: OriginFor,
location: Box,
) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
let location: Location = (*location).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::force_subscribe_version_notify",
"Failed to convert VersionedLocation for subscription target"
);
Error::::BadLocation
})?;
Self::request_version_notify(location).map_err(|e| {
tracing::debug!(
target: "xcm::pezpallet_xcm::force_subscribe_version_notify", error=?e,
"Failed to subscribe for version notifications for location"
);
match e {
XcmError::InvalidLocation => Error::::AlreadySubscribed,
_ => Error::::InvalidOrigin,
}
.into()
})
}
/// Require that a particular destination should no longer notify us regarding any XCM
/// version changes.
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The location to which we are currently subscribed for XCM version
/// notifications which we no longer desire.
#[pezpallet::call_index(7)]
pub fn force_unsubscribe_version_notify(
origin: OriginFor,
location: Box,
) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
let location: Location = (*location).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::force_unsubscribe_version_notify",
"Failed to convert VersionedLocation for unsubscription target"
);
Error::::BadLocation
})?;
Self::unrequest_version_notify(location).map_err(|e| {
tracing::debug!(
target: "xcm::pezpallet_xcm::force_unsubscribe_version_notify", error=?e,
"Failed to unsubscribe from version notifications for location"
);
match e {
XcmError::InvalidLocation => Error::::NoSubscription,
_ => Error::::InvalidOrigin,
}
.into()
})
}
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve.
///
/// `assets` must have same reserve location and may not be teleportable to `dest`.
/// - `assets` have local reserve: transfer assets to sovereign account of destination
/// chain and forward a notification XCM to `dest` to mint and deposit reserve-based
/// assets to `beneficiary`.
/// - `assets` have destination reserve: burn local assets and forward a notification to
/// `dest` chain to withdraw the reserve assets from this chain's sovereign account and
/// deposit them to `beneficiary`.
/// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move
/// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest`
/// to mint and deposit reserve-based assets to `beneficiary`.
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// id `fee_asset_id`, up to enough to pay for `weight_limit` of weight. If more weight
/// is needed than `weight_limit`, then the operation will fail and the sent assets may be
/// at risk.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `[Parent,
/// Teyrchain(..)]` to send from teyrchain to teyrchain, or `[Teyrchain(..)]` to send from
/// relay to teyrchain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_id`: Id of the asset from `assets` which should be used to pay fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
#[pezpallet::call_index(8)]
#[pezpallet::weight(T::WeightInfo::reserve_transfer_assets())]
pub fn limited_reserve_transfer_assets(
origin: OriginFor,
dest: Box,
beneficiary: Box,
assets: Box,
fee_asset_id: Box,
weight_limit: WeightLimit,
) -> DispatchResult {
Self::do_reserve_transfer_assets(
origin,
dest,
beneficiary,
assets,
fee_asset_id,
weight_limit,
)
}
/// Teleport some assets from the local chain to some destination chain.
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// id `fee_asset_id`, up to enough to pay for `weight_limit` of weight. If more weight
/// is needed than `weight_limit`, then the operation will fail and the sent assets may be
/// at risk.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `[Parent,
/// Teyrchain(..)]` to send from teyrchain to teyrchain, or `[Teyrchain(..)]` to send from
/// relay to teyrchain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` chain.
/// - `fee_asset_id`: Id of the asset from `assets` which should be used to pay fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
#[pezpallet::call_index(9)]
#[pezpallet::weight(T::WeightInfo::teleport_assets())]
pub fn limited_teleport_assets(
origin: OriginFor,
dest: Box,
beneficiary: Box,
assets: Box,
fee_asset_id: Box,
weight_limit: WeightLimit,
) -> DispatchResult {
Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_id, weight_limit)
}
/// Set or unset the global suspension state of the XCM executor.
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `suspended`: `true` to suspend, `false` to resume.
#[pezpallet::call_index(10)]
pub fn force_suspension(origin: OriginFor, suspended: bool) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
XcmExecutionSuspended::::set(suspended);
Ok(())
}
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve, or through teleports.
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// id `fee_asset_id` (hence referred to as `fees`), up to enough to pay for
/// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the
/// operation will fail and the sent assets may be at risk.
///
/// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable
/// to `dest`, no limitations imposed on `fees`.
/// - for local reserve: transfer assets to sovereign account of destination chain and
/// forward a notification XCM to `dest` to mint and deposit reserve-based assets to
/// `beneficiary`.
/// - for destination reserve: burn local assets and forward a notification to `dest` chain
/// to withdraw the reserve assets from this chain's sovereign account and deposit them
/// to `beneficiary`.
/// - for remote reserve: burn local assets, forward XCM to reserve chain to move reserves
/// from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` to mint
/// and deposit reserve-based assets to `beneficiary`.
/// - for teleports: burn local assets and forward XCM to `dest` chain to mint/teleport
/// assets and deposit them to `beneficiary`.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `X2(Parent,
/// Teyrchain(..))` to send from teyrchain to teyrchain, or `X1(Teyrchain(..))` to send
/// from relay to teyrchain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_id`: Id of the asset from `assets` which should be used to pay fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
#[pezpallet::call_index(11)]
pub fn transfer_assets(
origin: OriginFor,
dest: Box,
beneficiary: Box,
assets: Box,
fee_asset_id: Box,
weight_limit: WeightLimit,
) -> DispatchResult {
let origin = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let dest = (*dest).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets",
"Failed to convert destination VersionedLocation",
);
Error::::BadVersion
})?;
let beneficiary: Location = (*beneficiary).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets",
"Failed to convert beneficiary VersionedLocation",
);
Error::::BadVersion
})?;
let assets: Assets = (*assets).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets",
"Failed to convert VersionedAssets",
);
Error::::BadVersion
})?;
let fee_asset_id: AssetId = (*fee_asset_id).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets",
"Failed to convert VersionedAssetId",
);
Error::::BadVersion
})?;
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets",
?origin, ?dest, ?beneficiary, ?assets, ?fee_asset_id, ?weight_limit,
);
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets);
let assets = assets.into_inner();
// Find transfer types for fee and non-fee assets.
let (fees_transfer_type, assets_transfer_type) =
Self::find_fee_and_assets_transfer_types(&assets, &fee_asset_id, &dest)?;
// We check for network native asset reserve transfers in preparation for the Asset Hub
// Migration. This check will be removed after the migration and the determined
// reserve location adjusted accordingly. For more information, see https://github.com/pezkuwichain/pezkuwi-sdk/issues/301.
Self::ensure_network_asset_reserve_transfer_allowed(
&assets,
&fee_asset_id,
&assets_transfer_type,
&fees_transfer_type,
)?;
Self::do_transfer_assets(
origin,
dest,
Either::Left(beneficiary),
assets,
assets_transfer_type,
fee_asset_id,
fees_transfer_type,
weight_limit,
)
}
/// Claims assets trapped on this pezpallet because of leftover assets during XCM execution.
///
/// - `origin`: Anyone can call this extrinsic.
/// - `assets`: The exact assets that were trapped. Use the version to specify what version
/// was the latest when they were trapped.
/// - `beneficiary`: The location/account where the claimed assets will be deposited.
#[pezpallet::call_index(12)]
pub fn claim_assets(
origin: OriginFor,
assets: Box,
beneficiary: Box,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
tracing::debug!(target: "xcm::pezpallet_xcm::claim_assets", ?origin_location, ?assets, ?beneficiary);
// Extract version from `assets`.
let assets_version = assets.identify_version();
let assets: Assets = (*assets).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::claim_assets",
"Failed to convert input VersionedAssets",
);
Error::::BadVersion
})?;
let number_of_assets = assets.len() as u32;
let beneficiary: Location = (*beneficiary).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::claim_assets",
"Failed to convert beneficiary VersionedLocation",
);
Error::::BadVersion
})?;
let ticket: Location = GeneralIndex(assets_version as u128).into();
let mut message = Xcm(vec![
ClaimAsset { assets, ticket },
DepositAsset { assets: AllCounted(number_of_assets).into(), beneficiary },
]);
let weight = T::Weigher::weight(&mut message, Weight::MAX).map_err(|error| {
tracing::debug!(target: "xcm::pezpallet_xcm::claim_assets", ?error, "Failed to calculate weight");
Error::::UnweighableMessage
})?;
let mut hash = message.using_encoded(pezsp_io::hashing::blake2_256);
let outcome = T::XcmExecutor::prepare_and_execute(
origin_location,
message,
&mut hash,
weight,
weight,
);
outcome.ensure_complete().map_err(|error| {
tracing::error!(target: "xcm::pezpallet_xcm::claim_assets", ?error, "XCM execution failed with error");
Error::::LocalExecutionIncompleteWithError { index: error.index, error: error.error.into()}
})?;
Ok(())
}
/// Transfer assets from the local chain to the destination chain using explicit transfer
/// types for assets and fees.
///
/// `assets` must have same reserve location or may be teleportable to `dest`. Caller must
/// provide the `assets_transfer_type` to be used for `assets`:
/// - `TransferType::LocalReserve`: transfer assets to sovereign account of destination
/// chain and forward a notification XCM to `dest` to mint and deposit reserve-based
/// assets to `beneficiary`.
/// - `TransferType::DestinationReserve`: burn local assets and forward a notification to
/// `dest` chain to withdraw the reserve assets from this chain's sovereign account and
/// deposit them to `beneficiary`.
/// - `TransferType::RemoteReserve(reserve)`: burn local assets, forward XCM to `reserve`
/// chain to move reserves from this chain's SA to `dest` chain's SA, and forward another
/// XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. Typically
/// the remote `reserve` is Asset Hub.
/// - `TransferType::Teleport`: burn local assets and forward XCM to `dest` chain to
/// mint/teleport assets and deposit them to `beneficiary`.
///
/// On the destination chain, as well as any intermediary hops, `BuyExecution` is used to
/// buy execution using transferred `assets` identified by `remote_fees_id`.
/// Make sure enough of the specified `remote_fees_id` asset is included in the given list
/// of `assets`. `remote_fees_id` should be enough to pay for `weight_limit`. If more weight
/// is needed than `weight_limit`, then the operation will fail and the sent assets may be
/// at risk.
///
/// `remote_fees_id` may use different transfer type than rest of `assets` and can be
/// specified through `fees_transfer_type`.
///
/// The caller needs to specify what should happen to the transferred assets once they reach
/// the `dest` chain. This is done through the `custom_xcm_on_dest` parameter, which
/// contains the instructions to execute on `dest` as a final step.
/// This is usually as simple as:
/// `Xcm(vec![DepositAsset { assets: Wild(AllCounted(assets.len())), beneficiary }])`,
/// but could be something more exotic like sending the `assets` even further.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `[Parent,
/// Teyrchain(..)]` to send from teyrchain to teyrchain, or `[Teyrchain(..)]` to send from
/// relay to teyrchain, or `(parents: 2, (GlobalConsensus(..), ..))` to send from
/// teyrchain across a bridge to another ecosystem destination.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` (and possibly reserve) chains.
/// - `assets_transfer_type`: The XCM `TransferType` used to transfer the `assets`.
/// - `remote_fees_id`: One of the included `assets` to be used to pay fees.
/// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets.
/// - `custom_xcm_on_dest`: The XCM to be executed on `dest` chain as the last step of the
/// transfer, which also determines what happens to the assets on the destination chain.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
#[pezpallet::call_index(13)]
#[pezpallet::weight(T::WeightInfo::transfer_assets())]
pub fn transfer_assets_using_type_and_then(
origin: OriginFor,
dest: Box,
assets: Box,
assets_transfer_type: Box,
remote_fees_id: Box,
fees_transfer_type: Box,
custom_xcm_on_dest: Box>,
weight_limit: WeightLimit,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let dest: Location = (*dest).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets_using_type_and_then",
"Failed to convert destination VersionedLocation",
);
Error::::BadVersion
})?;
let assets: Assets = (*assets).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets_using_type_and_then",
"Failed to convert VersionedAssets",
);
Error::::BadVersion
})?;
let fees_id: AssetId = (*remote_fees_id).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets_using_type_and_then",
"Failed to convert remote_fees_id VersionedAssetId",
);
Error::::BadVersion
})?;
let remote_xcm: Xcm<()> = (*custom_xcm_on_dest).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets_using_type_and_then",
"Failed to convert custom_xcm_on_dest VersionedXcm",
);
Error::::BadVersion
})?;
tracing::debug!(
target: "xcm::pezpallet_xcm::transfer_assets_using_type_and_then",
?origin_location, ?dest, ?assets, ?assets_transfer_type, ?fees_id, ?fees_transfer_type,
?remote_xcm, ?weight_limit,
);
let assets = assets.into_inner();
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets);
Self::do_transfer_assets(
origin_location,
dest,
Either::Right(remote_xcm),
assets,
*assets_transfer_type,
fees_id,
*fees_transfer_type,
weight_limit,
)
}
/// Authorize another `aliaser` location to alias into the local `origin` making this call.
/// The `aliaser` is only authorized until the provided `expiry` block number.
/// The call can also be used for a previously authorized alias in order to update its
/// `expiry` block number.
///
/// Usually useful to allow your local account to be aliased into from a remote location
/// also under your control (like your account on another chain).
///
/// WARNING: make sure the caller `origin` (you) trusts the `aliaser` location to act in
/// their/your name. Once authorized using this call, the `aliaser` can freely impersonate
/// `origin` in XCM programs executed on the local chain.
#[pezpallet::call_index(14)]
pub fn add_authorized_alias(
origin: OriginFor,
aliaser: Box,
expires: Option,
) -> DispatchResult {
let signed_origin = ensure_signed(origin.clone())?;
let origin_location: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let new_aliaser: Location = (*aliaser).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::add_authorized_alias",
"Failed to convert aliaser VersionedLocation",
);
Error::::BadVersion
})?;
ensure!(origin_location != new_aliaser, Error::::BadLocation);
// remove `network` from inner `AccountId32` for easier matching
let origin_location = match origin_location.unpack() {
(0, [AccountId32 { network: _, id }]) => {
Location::new(0, [AccountId32 { network: None, id: *id }])
},
_ => return Err(Error::::InvalidOrigin.into()),
};
tracing::debug!(target: "xcm::pezpallet_xcm::add_authorized_alias", ?origin_location, ?new_aliaser, ?expires);
ensure!(origin_location != new_aliaser, Error::::BadLocation);
if let Some(expiry) = expires {
ensure!(
expiry
> pezframe_system::Pezpallet::::current_block_number()
.saturated_into::(),
Error::::ExpiresInPast
);
}
let versioned_origin = VersionedLocation::from(origin_location.clone());
let versioned_aliaser = VersionedLocation::from(new_aliaser.clone());
let entry = if let Some(entry) = AuthorizedAliases::::get(&versioned_origin) {
// entry already exists, update it
let (mut aliasers, mut ticket) = (entry.aliasers, entry.ticket);
if let Some(aliaser) =
aliasers.iter_mut().find(|aliaser| aliaser.location == versioned_aliaser)
{
// if the aliaser already exists, just update its expiry block
aliaser.expiry = expires;
} else {
// if it doesn't, we try to add it
let aliaser =
OriginAliaser { location: versioned_aliaser.clone(), expiry: expires };
aliasers.try_push(aliaser).map_err(|_| {
tracing::debug!(
target: "xcm::pezpallet_xcm::add_authorized_alias",
"Failed to add new aliaser to existing entry",
);
Error::::TooManyAuthorizedAliases
})?;
// we try to update the ticket (the storage deposit)
ticket = ticket.update(&signed_origin, aliasers_footprint(aliasers.len()))?;
}
AuthorizedAliasesEntry { aliasers, ticket }
} else {
// add new entry with its first alias
let ticket = TicketOf::::new(&signed_origin, aliasers_footprint(1))?;
let aliaser =
OriginAliaser { location: versioned_aliaser.clone(), expiry: expires };
let mut aliasers = BoundedVec::::new();
aliasers.try_push(aliaser).map_err(|error| {
tracing::debug!(
target: "xcm::pezpallet_xcm::add_authorized_alias", ?error,
"Failed to add first aliaser to new entry",
);
Error::::TooManyAuthorizedAliases
})?;
AuthorizedAliasesEntry { aliasers, ticket }
};
// write to storage
AuthorizedAliases::::insert(&versioned_origin, entry);
Self::deposit_event(Event::AliasAuthorized {
aliaser: new_aliaser,
target: origin_location,
expiry: expires,
});
Ok(())
}
/// Remove a previously authorized `aliaser` from the list of locations that can alias into
/// the local `origin` making this call.
#[pezpallet::call_index(15)]
pub fn remove_authorized_alias(
origin: OriginFor,
aliaser: Box,
) -> DispatchResult {
let signed_origin = ensure_signed(origin.clone())?;
let origin_location: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let to_remove: Location = (*aliaser).try_into().map_err(|()| {
tracing::debug!(
target: "xcm::pezpallet_xcm::remove_authorized_alias",
"Failed to convert aliaser VersionedLocation",
);
Error::::BadVersion
})?;
ensure!(origin_location != to_remove, Error::::BadLocation);
// remove `network` from inner `AccountId32` for easier matching
let origin_location = match origin_location.unpack() {
(0, [AccountId32 { network: _, id }]) => {
Location::new(0, [AccountId32 { network: None, id: *id }])
},
_ => return Err(Error::::InvalidOrigin.into()),
};
tracing::debug!(target: "xcm::pezpallet_xcm::remove_authorized_alias", ?origin_location, ?to_remove);
ensure!(origin_location != to_remove, Error::::BadLocation);
// convert to latest versioned
let versioned_origin = VersionedLocation::from(origin_location.clone());
let versioned_to_remove = VersionedLocation::from(to_remove.clone());
AuthorizedAliases::