Skip to content

Commit

Permalink
Merge pull request #65 from Phala-Network/xtransfer-update
Browse files Browse the repository at this point in the history
Asset wrapper and fee updates
  • Loading branch information
tolak authored Feb 24, 2022
2 parents 19e3e3b + 344f206 commit 719bfbe
Show file tree
Hide file tree
Showing 12 changed files with 819 additions and 58 deletions.
60 changes: 58 additions & 2 deletions pallets/xtransfer/src/assets_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ pub use self::pallet::*;
#[frame_support::pallet]
pub mod pallet {
use codec::{Decode, Encode};
use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::StorageVersion};
use frame_support::{
dispatch::DispatchResult, pallet_prelude::*, traits::StorageVersion, transactional,
};
use frame_system::pallet_prelude::*;
use scale_info::TypeInfo;
use sp_runtime::traits::StaticLookup;
Expand Down Expand Up @@ -35,11 +37,19 @@ pub mod pallet {
// Potential other bridge solutions
}

#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo)]
pub struct AssetProperties {
pub name: Vec<u8>,
pub symbol: Vec<u8>,
pub decimals: u8,
}

#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo)]
pub struct AssetRegistryInfo {
location: MultiLocation,
reserve_location: Option<MultiLocation>,
enabled_bridges: Vec<XBridge>,
properties: AssetProperties,
}

impl From<MultiLocation> for XTransferAsset {
Expand Down Expand Up @@ -215,10 +225,12 @@ pub mod pallet {
T: pallet_assets::Config,
{
#[pallet::weight(195_000_000)]
#[transactional]
pub fn force_register_asset(
origin: OriginFor<T>,
asset: XTransferAsset,
asset_id: T::AssetId,
properties: AssetProperties,
owner: <T::Lookup as StaticLookup>::Source,
) -> DispatchResult {
T::AssetsCommitteeOrigin::ensure_origin(origin.clone())?;
Expand All @@ -233,14 +245,15 @@ pub mod pallet {
Error::<T>::AssetAlreadyExist
);
pallet_assets::pallet::Pallet::<T>::force_create(
origin,
origin.clone(),
asset_id,
owner,
true,
T::MinBalance::get(),
)?;
IdByAssets::<T>::insert(&asset, asset_id);
AssetByIds::<T>::insert(asset_id, &asset);

RegistryInfoByIds::<T>::insert(
asset_id,
AssetRegistryInfo {
Expand All @@ -251,8 +264,18 @@ pub mod pallet {
config: XBridgeConfig::Xcmp,
metadata: Box::new(Vec::new()),
}],
properties: properties.clone(),
},
);
pallet_assets::pallet::Pallet::<T>::force_set_metadata(
origin,
asset_id,
properties.name,
properties.symbol,
properties.decimals,
false,
)?;

Self::deposit_event(Event::AssetRegistered { asset_id, asset });
Ok(())
}
Expand All @@ -262,6 +285,7 @@ pub mod pallet {
/// will not success anymore, we should call pallet_assets::destory() manually
/// if we want to delete this asset from our chain
#[pallet::weight(195_000_000)]
#[transactional]
pub fn force_unregister_asset(
origin: OriginFor<T>,
asset_id: T::AssetId,
Expand Down Expand Up @@ -293,6 +317,32 @@ pub mod pallet {
}

#[pallet::weight(195_000_000)]
#[transactional]
pub fn force_set_metadata(
origin: OriginFor<T>,
asset_id: T::AssetId,
properties: AssetProperties,
) -> DispatchResult {
T::AssetsCommitteeOrigin::ensure_origin(origin.clone())?;

let mut info =
RegistryInfoByIds::<T>::get(&asset_id).ok_or(Error::<T>::AssetNotRegistered)?;
info.properties = properties.clone();
RegistryInfoByIds::<T>::insert(&asset_id, &info);
pallet_assets::pallet::Pallet::<T>::force_set_metadata(
origin,
asset_id,
properties.name,
properties.symbol,
properties.decimals,
false,
)?;

Ok(())
}

#[pallet::weight(195_000_000)]
#[transactional]
pub fn force_enable_chainbridge(
origin: OriginFor<T>,
asset_id: T::AssetId,
Expand Down Expand Up @@ -340,6 +390,7 @@ pub mod pallet {
}

#[pallet::weight(195_000_000)]
#[transactional]
pub fn force_disable_chainbridge(
origin: OriginFor<T>,
asset_id: T::AssetId,
Expand Down Expand Up @@ -385,6 +436,7 @@ pub mod pallet {
fn id(asset: &XTransferAsset) -> Option<AssetId>;
fn asset(id: &AssetId) -> Option<XTransferAsset>;
fn lookup_by_resource_id(resource_id: &[u8; 32]) -> Option<XTransferAsset>;
fn decimals(id: &AssetId) -> Option<u8>;
}

impl<T: Config> GetAssetRegistryInfo<<T as pallet_assets::Config>::AssetId> for Pallet<T> {
Expand All @@ -399,5 +451,9 @@ pub mod pallet {
fn lookup_by_resource_id(resource_id: &[u8; 32]) -> Option<XTransferAsset> {
AssetByResourceIds::<T>::get(resource_id)
}

fn decimals(id: &<T as pallet_assets::Config>::AssetId) -> Option<u8> {
RegistryInfoByIds::<T>::get(&id).map(|m| m.properties.decimals)
}
}
}
2 changes: 1 addition & 1 deletion pallets/xtransfer/src/bridge_transfer/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ parameter_types! {
);
pub ExecutionPriceInAsset2: (AssetId, u128) = (
AssetId2::get(),
1
2
);
pub NativeExecutionPrice: u128 = 1;
pub ExecutionPrices: Vec<(AssetId, u128)> = [
Expand Down
118 changes: 67 additions & 51 deletions pallets/xtransfer/src/bridge_transfer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,6 @@ pub mod pallet {

let dest_location: MultiLocation =
Decode::decode(&mut dest.as_slice()).map_err(|_| Error::<T>::DestUnrecognized)?;
let dest_reserve_location = dest_location
.reserve_location()
.ok_or(Error::<T>::DestUnrecognized)?;

let asset_location = Self::rid_to_location(&rid)?;
let asset_reserve_location = asset_location
Expand Down Expand Up @@ -397,44 +394,38 @@ pub mod pallet {
}
// To relaychain or other parachain, forward it by xcm
(1, X1(AccountId32 { .. })) | (1, X2(Parachain(_), AccountId32 { .. })) => {
let dest_reserve_account = dest_reserve_location.clone().into_account();
if asset_reserve_location != dest_reserve_location {
log::trace!(
target: LOG_TARGET,
"Reserve of asset and dest dismatch, deposit asset to dest reserve location.",
let temporary_account =
MultiLocation::new(0, X1(GeneralKey(b"bridge_transfer".to_vec())))
.into_account();
log::trace!(
target: LOG_TARGET,
"Deposit withdrawn asset to a temporary account: {:?}",
&temporary_account,
);
if rid == Self::gen_pha_rid(src_chainid) {
<T as Config>::Currency::deposit_creating(
&temporary_account.clone().into(),
amount,
);
if rid == Self::gen_pha_rid(src_chainid) {
<T as Config>::Currency::deposit_creating(
&dest_reserve_account.clone().into(),
amount,
);
} else {
let asset_id = Self::rid_to_assetid(&rid)?;
let asset_amount =
T::BalanceConverter::to_asset_balance(amount, asset_id)
.map_err(|_| Error::<T>::BalanceConversionFailed)?;
// Mint asset into dest reserve account
pallet_assets::pallet::Pallet::<T>::mint_into(
asset_id,
&dest_reserve_account.clone().into(),
asset_amount,
)
.map_err(|_| Error::<T>::FailedToTransactAsset)?;
}
} else {
let asset_id = Self::rid_to_assetid(&rid)?;
let asset_amount = T::BalanceConverter::to_asset_balance(amount, asset_id)
.map_err(|_| Error::<T>::BalanceConversionFailed)?;
// Mint asset into dest temporary account
pallet_assets::pallet::Pallet::<T>::mint_into(
asset_id,
&temporary_account.clone().into(),
asset_amount,
)
.map_err(|_| Error::<T>::FailedToTransactAsset)?;
}

// Two main tasks of transfer_fungible is:
// first) withdraw asset from reserve_id
// second) deposit asset into sovereign account of dest chain.(MINT OP)
//
// So if the reserve account does not have enough asset, transaction would fail.
// When someone transfer assets to EVM account from local chain our other parachains,
// assets would be deposited into reserve account, in other words, bridge transfer
// always based on reserve mode.
// After deposited asset into the temporary account, let xcm executor determine how to
// handle the asset.
T::XcmTransactor::transfer_fungible(
Junction::AccountId32 {
network: NetworkId::Any,
id: dest_reserve_account,
id: temporary_account,
}
.into(),
(asset_location, amount.into()).into(),
Expand All @@ -456,7 +447,10 @@ pub mod pallet {
}
}

impl<T: Config> Pallet<T> {
impl<T: Config> Pallet<T>
where
BalanceOf<T>: From<u128> + Into<u128>,
{
// TODO.wf: A more proper way to estimate fee
pub fn estimate_fee_in_pha(
dest_id: bridge::BridgeChainId,
Expand All @@ -471,6 +465,27 @@ pub mod pallet {
}
}

pub fn to_e12(amount: u128, decimals: u8) -> u128 {
if decimals > 12 {
amount.saturating_div(10u128.saturating_pow(decimals as u32 - 12))
} else {
amount.saturating_mul(10u128.saturating_pow(12 - decimals as u32))
}
}

pub fn from_e12(amount: u128, decimals: u8) -> u128 {
if decimals > 12 {
amount.saturating_mul(10u128.saturating_pow(decimals as u32 - 12))
} else {
amount.saturating_div(10u128.saturating_pow(12 - decimals as u32))
}
}

pub fn convert_fee_from_pha(fee_in_pha: BalanceOf<T>, price: u128, decimals: u8) -> u128 {
let fee_e12: u128 = fee_in_pha.into() * price / T::NativeExecutionPrice::get();
Self::from_e12(fee_e12.into(), decimals)
}

pub fn rid_to_location(rid: &[u8; 32]) -> Result<MultiLocation, DispatchError> {
let src_chainid: bridge::BridgeChainId = Self::get_chainid(rid);
let asset_location: MultiLocation = if *rid == Self::gen_pha_rid(src_chainid) {
Expand Down Expand Up @@ -516,24 +531,25 @@ pub mod pallet {
{
fn get_fee(chain_id: bridge::BridgeChainId, asset: &MultiAsset) -> Option<u128> {
match (&asset.id, &asset.fun) {
(Concrete(asset_id), Fungible(amount)) => {
let fee_estimated_in_pha =
Self::estimate_fee_in_pha(chain_id, (*amount).into());
(Concrete(location), Fungible(amount)) => {
let id = T::AssetsWrapper::id(&XTransferAsset(location.clone()))?;
let decimals = T::AssetsWrapper::decimals(&id).unwrap_or(12);
let fee_in_pha = Self::estimate_fee_in_pha(
chain_id,
(Self::to_e12(*amount, decimals)).into(),
);
if T::NativeChecker::is_native_asset(asset) {
Some(fee_estimated_in_pha.into())
Some(fee_in_pha.into())
} else {
let fee_in_asset;
let fee_prices = T::ExecutionPriceInfo::get();
if let Some(idx) = fee_prices.iter().position(|(fee_asset_id, _)| {
fee_asset_id == &Concrete(asset_id.clone())
}) {
fee_in_asset = Some(
fee_estimated_in_pha.into() * fee_prices[idx].1
/ T::NativeExecutionPrice::get(),
)
} else {
fee_in_asset = None
}
let fee_in_asset = fee_prices
.iter()
.position(|(fee_asset_id, _)| {
fee_asset_id == &Concrete(location.clone())
})
.map(|idx| {
Self::convert_fee_from_pha(fee_in_pha, fee_prices[idx].1, decimals)
});
fee_in_asset
}
}
Expand Down
Loading

0 comments on commit 719bfbe

Please sign in to comment.