4666047395
Updated 4763 files with dual copyright: - Parity Technologies (UK) Ltd. - Dijital Kurdistan Tech Institute
185 lines
7.0 KiB
Rust
185 lines
7.0 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
|
// This file is part of Pezkuwi.
|
|
|
|
// Pezkuwi 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.
|
|
|
|
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use crate::xcm_config;
|
|
use alloc::{boxed::Box, vec};
|
|
use codec::{Decode, Encode};
|
|
use core::marker::PhantomData;
|
|
use pezframe_support::pezpallet_prelude::DispatchResult;
|
|
use pezframe_system::RawOrigin;
|
|
use pezkuwi_primitives::Balance;
|
|
use pezkuwi_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
|
|
use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
|
|
use xcm_executor::traits::TransactAsset;
|
|
use zagros_runtime_constants::currency::*;
|
|
|
|
/// 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 pezpallet.
|
|
#[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 teyrchain, sends the deposit there, and then updates it.
|
|
pub struct ToTeyrchainIdentityReaper<Runtime, AccountId>(PhantomData<(Runtime, AccountId)>);
|
|
impl<Runtime, AccountId> ToTeyrchainIdentityReaper<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. Teyrchain uses `deposit / 100`
|
|
// Source:
|
|
// https://github.com/pezkuwichain/pezkuwi-sdk/blob/a146918/pezcumulus/parachains/common/src/westend.rs#L28
|
|
//
|
|
// Teyrchain 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;
|
|
|
|
// pezpallet 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 ToTeyrchainIdentityReaper<Runtime, AccountId>
|
|
where
|
|
Runtime: pezframe_system::Config + pezpallet_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::pezkuwi_runtime_common_identity_migrator::WeightInfo as MigratorWeights,
|
|
};
|
|
|
|
let total_to_send = Self::calculate_remote_deposit(fields, subs);
|
|
|
|
// define asset / destination from relay perspective
|
|
let wnd = Asset { id: AssetId(Here.into_location()), fun: Fungible(total_to_send) };
|
|
// People Chain: ParaId 1004
|
|
let destination: Location = Location::new(0, Teyrchain(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(&wnd, &who_origin, None)
|
|
.map_err(|err| {
|
|
log::error!(
|
|
target: "runtime::on_reap_identity",
|
|
"withdraw_asset(what: {:?}, who_origin: {:?}) error: {:?}",
|
|
wnd, who_origin, err
|
|
);
|
|
pezpallet_xcm::Error::<Runtime>::LowBalance
|
|
})?;
|
|
|
|
// check out
|
|
xcm_config::LocalAssetTransactor::can_check_out(
|
|
&destination,
|
|
&wnd,
|
|
// 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, wnd, err
|
|
);
|
|
pezpallet_xcm::Error::<Runtime>::CannotCheckOutTeleport
|
|
})?;
|
|
xcm_config::LocalAssetTransactor::check_out(
|
|
&destination,
|
|
&wnd,
|
|
// not used in AssetTransactor
|
|
&XcmContext { origin: None, message_id: [0; 32], topic: None },
|
|
);
|
|
|
|
// reanchor
|
|
let wnd_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(wnd_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 teyrchain.
|
|
Transact {
|
|
origin_kind: OriginKind::Superuser,
|
|
call: poke.encode().into(),
|
|
fallback_max_weight: Some(remote_weight_limit),
|
|
},
|
|
]);
|
|
|
|
// send
|
|
<pezpallet_xcm::Pezpallet<Runtime>>::send(
|
|
RawOrigin::Root.into(),
|
|
Box::new(VersionedLocation::from(destination)),
|
|
Box::new(VersionedXcm::from(program)),
|
|
)?;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "runtime-benchmarks")]
|
|
fn ensure_successful_identity_reaping(_: &AccountId, _: u32, _: u32) {
|
|
crate::Dmp::make_teyrchain_reachable(1004);
|
|
}
|
|
}
|