mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-25 22:17:58 +00:00
feee773d15
`execute` and `send` try to decode the xcm in the parameters before reaching the filter line. The new extrinsics decode only after the filter line. These should be used instead of the old ones. ## TODO - [x] Tests - [x] Generate weights - [x] Deprecation issue -> https://github.com/paritytech/polkadot-sdk/issues/3771 - [x] PRDoc - [x] Handle error in pallet-contracts This would make writing XCMs in PJS Apps more difficult, but here's the fix for that: https://github.com/polkadot-js/apps/pull/10350. Already deployed! https://polkadot.js.org/apps/#/utilities/xcm Supersedes https://github.com/paritytech/polkadot-sdk/pull/1798/ --------- Co-authored-by: PG Herveou <pgherveou@gmail.com> Co-authored-by: command-bot <> Co-authored-by: Adrian Catangiu <adrian@parity.io>
184 lines
7.0 KiB
Rust
184 lines
7.0 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is part of Polkadot.
|
|
|
|
// Polkadot is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Polkadot is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use crate::xcm_config;
|
|
use frame_support::pallet_prelude::DispatchResult;
|
|
use frame_system::RawOrigin;
|
|
use parity_scale_codec::{Decode, Encode};
|
|
use primitives::Balance;
|
|
use rococo_runtime_constants::currency::*;
|
|
use runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
|
|
use sp_std::{marker::PhantomData, prelude::*};
|
|
use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
|
|
use xcm_executor::traits::TransactAsset;
|
|
|
|
/// A type containing the encoding of the People Chain pallets in its runtime. Used to construct any
|
|
/// remote calls. The codec index must correspond to the index of `IdentityMigrator` in the
|
|
/// `construct_runtime` of the remote chain.
|
|
#[derive(Encode, Decode)]
|
|
enum PeopleRuntimePallets<AccountId: Encode> {
|
|
#[codec(index = 248)]
|
|
IdentityMigrator(IdentityMigratorCalls<AccountId>),
|
|
}
|
|
|
|
/// Call encoding for the calls needed from the Identity Migrator pallet.
|
|
#[derive(Encode, Decode)]
|
|
enum IdentityMigratorCalls<AccountId: Encode> {
|
|
#[codec(index = 1)]
|
|
PokeDeposit(AccountId),
|
|
}
|
|
|
|
/// Type that implements `OnReapIdentity` that will send the deposit needed to store the same
|
|
/// information on a parachain, sends the deposit there, and then updates it.
|
|
pub struct ToParachainIdentityReaper<Runtime, AccountId>(PhantomData<(Runtime, AccountId)>);
|
|
impl<Runtime, AccountId> ToParachainIdentityReaper<Runtime, AccountId> {
|
|
/// Calculate the balance needed on the remote chain based on the `IdentityInfo` and `Subs` on
|
|
/// this chain. The total includes:
|
|
///
|
|
/// - Identity basic deposit
|
|
/// - `IdentityInfo` byte deposit
|
|
/// - Sub accounts deposit
|
|
/// - 2x existential deposit (1 for account existence, 1 such that the user can transact)
|
|
fn calculate_remote_deposit(bytes: u32, subs: u32) -> Balance {
|
|
// Remote deposit constants. Parachain uses `deposit / 100`
|
|
// Source:
|
|
// https://github.com/paritytech/polkadot-sdk/blob/a146918/cumulus/parachains/common/src/rococo.rs#L29
|
|
//
|
|
// Parachain Deposit Configuration:
|
|
//
|
|
// pub const BasicDeposit: Balance = deposit(1, 17);
|
|
// pub const ByteDeposit: Balance = deposit(0, 1);
|
|
// pub const SubAccountDeposit: Balance = deposit(1, 53);
|
|
// pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10;
|
|
let para_basic_deposit = deposit(1, 17) / 100;
|
|
let para_byte_deposit = deposit(0, 1) / 100;
|
|
let para_sub_account_deposit = deposit(1, 53) / 100;
|
|
let para_existential_deposit = EXISTENTIAL_DEPOSIT / 10;
|
|
|
|
// pallet deposits
|
|
let id_deposit =
|
|
para_basic_deposit.saturating_add(para_byte_deposit.saturating_mul(bytes as Balance));
|
|
let subs_deposit = para_sub_account_deposit.saturating_mul(subs as Balance);
|
|
|
|
id_deposit
|
|
.saturating_add(subs_deposit)
|
|
.saturating_add(para_existential_deposit.saturating_mul(2))
|
|
}
|
|
}
|
|
|
|
// Note / Warning: This implementation should only be used in a transactional context. If not, then
|
|
// an error could result in assets being burned.
|
|
impl<Runtime, AccountId> OnReapIdentity<AccountId> for ToParachainIdentityReaper<Runtime, AccountId>
|
|
where
|
|
Runtime: frame_system::Config + pallet_xcm::Config,
|
|
AccountId: Into<[u8; 32]> + Clone + Encode,
|
|
{
|
|
fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult {
|
|
use crate::{
|
|
impls::IdentityMigratorCalls::PokeDeposit,
|
|
weights::runtime_common_identity_migrator::WeightInfo as MigratorWeights,
|
|
};
|
|
|
|
let total_to_send = Self::calculate_remote_deposit(fields, subs);
|
|
|
|
// define asset / destination from relay perspective
|
|
let roc = Asset { id: AssetId(Here.into_location()), fun: Fungible(total_to_send) };
|
|
// People Chain: ParaId 1004
|
|
let destination: Location = Location::new(0, Parachain(1004));
|
|
|
|
// Do `check_out` accounting since the XCM Executor's `InitiateTeleport` doesn't support
|
|
// unpaid teleports.
|
|
|
|
// withdraw the asset from `who`
|
|
let who_origin =
|
|
Junction::AccountId32 { network: None, id: who.clone().into() }.into_location();
|
|
let _withdrawn = xcm_config::LocalAssetTransactor::withdraw_asset(&roc, &who_origin, None)
|
|
.map_err(|err| {
|
|
log::error!(
|
|
target: "runtime::on_reap_identity",
|
|
"withdraw_asset(what: {:?}, who_origin: {:?}) error: {:?}",
|
|
roc, who_origin, err
|
|
);
|
|
pallet_xcm::Error::<Runtime>::LowBalance
|
|
})?;
|
|
|
|
// check out
|
|
xcm_config::LocalAssetTransactor::can_check_out(
|
|
&destination,
|
|
&roc,
|
|
// not used in AssetTransactor
|
|
&XcmContext { origin: None, message_id: [0; 32], topic: None },
|
|
)
|
|
.map_err(|err| {
|
|
log::error!(
|
|
target: "runtime::on_reap_identity",
|
|
"can_check_out(destination: {:?}, asset: {:?}, _) error: {:?}",
|
|
destination, roc, err
|
|
);
|
|
pallet_xcm::Error::<Runtime>::CannotCheckOutTeleport
|
|
})?;
|
|
xcm_config::LocalAssetTransactor::check_out(
|
|
&destination,
|
|
&roc,
|
|
// not used in AssetTransactor
|
|
&XcmContext { origin: None, message_id: [0; 32], topic: None },
|
|
);
|
|
|
|
// reanchor
|
|
let roc_reanchored: Assets =
|
|
vec![Asset { id: AssetId(Location::new(1, Here)), fun: Fungible(total_to_send) }]
|
|
.into();
|
|
|
|
let poke = PeopleRuntimePallets::<AccountId>::IdentityMigrator(PokeDeposit(who.clone()));
|
|
let remote_weight_limit = MigratorWeights::<Runtime>::poke_deposit().saturating_mul(2);
|
|
|
|
// Actual program to execute on People Chain.
|
|
let program: Xcm<()> = Xcm(vec![
|
|
// Unpaid as this is constructed by the system, once per user. The user shouldn't have
|
|
// their balance reduced by teleport fees for the favor of migrating.
|
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
|
// Receive the asset into holding.
|
|
ReceiveTeleportedAsset(roc_reanchored),
|
|
// Deposit into the user's account.
|
|
DepositAsset {
|
|
assets: Wild(AllCounted(1)),
|
|
beneficiary: Junction::AccountId32 { network: None, id: who.clone().into() }
|
|
.into_location()
|
|
.into(),
|
|
},
|
|
// Poke the deposit to reserve the appropriate amount on the parachain.
|
|
Transact {
|
|
origin_kind: OriginKind::Superuser,
|
|
require_weight_at_most: remote_weight_limit,
|
|
call: poke.encode().into(),
|
|
},
|
|
]);
|
|
|
|
let encoded_versioned_xcm =
|
|
VersionedXcm::V4(program).encode().try_into().map_err(|error| {
|
|
log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error);
|
|
pallet_xcm::Error::<Runtime>::XcmTooLarge
|
|
})?;
|
|
// send
|
|
let _ = <pallet_xcm::Pallet<Runtime>>::send_blob(
|
|
RawOrigin::Root.into(),
|
|
Box::new(VersionedLocation::V4(destination)),
|
|
encoded_versioned_xcm,
|
|
)?;
|
|
Ok(())
|
|
}
|
|
}
|