[evm-template] XCM config for foreign assets (#219)

This commit is contained in:
Amar Singh
2024-06-18 11:42:17 -04:00
committed by GitHub
parent b2b65e9364
commit b0c0a81219
9 changed files with 329 additions and 54 deletions
@@ -0,0 +1,184 @@
use frame_support::{
dispatch::GetDispatchInfo, parameter_types, traits::AsEnsureOriginWithArg, weights::Weight,
};
use frame_system::{EnsureRoot, EnsureSigned};
use parity_scale_codec::{Compact, Decode, Encode};
use scale_info::TypeInfo;
use sp_core::H256;
use sp_runtime::traits::Hash as THash;
use sp_std::{
convert::{From, Into},
prelude::*,
};
use xcm::latest::Location;
use crate::{
constants::currency::{deposit, CENTS, MILLICENTS},
types::{AccountId, AssetId, Balance},
AssetManager, Assets, Balances, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
};
parameter_types! {
pub const AssetDeposit: Balance = 10 * CENTS;
pub const AssetAccountDeposit: Balance = deposit(1, 16);
pub const ApprovalDeposit: Balance = MILLICENTS;
pub const StringLimit: u32 = 50;
pub const MetadataDepositBase: Balance = deposit(1, 68);
pub const MetadataDepositPerByte: Balance = deposit(0, 1);
pub const RemoveItemsLimit: u32 = 1000;
}
// Required for runtime benchmarks
pallet_assets::runtime_benchmarks_enabled! {
pub struct BenchmarkHelper;
impl<AssetIdParameter> pallet_assets::BenchmarkHelper<AssetIdParameter> for BenchmarkHelper
where
AssetIdParameter: From<u128>,
{
fn create_asset_id_parameter(id: u32) -> AssetIdParameter {
(id as u128).into()
}
}
}
// Foreign assets
impl pallet_assets::Config for Runtime {
type ApprovalDeposit = ApprovalDeposit;
type AssetAccountDeposit = AssetAccountDeposit;
type AssetDeposit = AssetDeposit;
type AssetId = AssetId;
type AssetIdParameter = Compact<AssetId>;
type Balance = Balance;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = BenchmarkHelper;
type CallbackHandle = ();
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
type Currency = Balances;
type Extra = ();
type ForceOrigin = EnsureRoot<AccountId>;
type Freezer = ();
type MetadataDepositBase = MetadataDepositBase;
type MetadataDepositPerByte = MetadataDepositPerByte;
type RemoveItemsLimit = RemoveItemsLimit;
type RuntimeEvent = RuntimeEvent;
type StringLimit = StringLimit;
type WeightInfo = pallet_assets::weights::SubstrateWeight<Runtime>; //FIXME: run & update
}
// Our AssetType. For now we only handle Xcm Assets
#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub enum AssetType {
Xcm(xcm::v3::Location),
}
impl Default for AssetType {
fn default() -> Self {
Self::Xcm(xcm::v3::Location::here())
}
}
impl From<xcm::v3::Location> for AssetType {
fn from(location: xcm::v3::Location) -> Self {
Self::Xcm(location)
}
}
// This can be removed once we fully adopt xcm::v4 everywhere
impl TryFrom<Location> for AssetType {
type Error = ();
fn try_from(location: Location) -> Result<Self, Self::Error> {
Ok(Self::Xcm(location.try_into()?))
}
}
impl From<AssetType> for Option<xcm::v3::Location> {
fn from(val: AssetType) -> Self {
match val {
AssetType::Xcm(location) => Some(location),
}
}
}
// Implementation on how to retrieve the AssetId from an AssetType
impl From<AssetType> for AssetId {
fn from(asset: AssetType) -> AssetId {
match asset {
AssetType::Xcm(id) => {
let mut result: [u8; 16] = [0u8; 16];
let hash: H256 = id.using_encoded(<Runtime as frame_system::Config>::Hashing::hash);
result.copy_from_slice(&hash.as_fixed_bytes()[0..16]);
u128::from_le_bytes(result)
}
}
}
}
// We instruct how to register the Assets
// In this case, we tell it to Create an Asset in pallet-assets
pub struct AssetRegistrar;
use frame_support::{pallet_prelude::DispatchResult, transactional};
impl pallet_asset_manager::AssetRegistrar<Runtime> for AssetRegistrar {
#[transactional]
fn create_foreign_asset(
asset: AssetId,
min_balance: Balance,
metadata: AssetRegistrarMetadata,
is_sufficient: bool,
) -> DispatchResult {
Assets::force_create(
RuntimeOrigin::root(),
asset.into(),
sp_runtime::MultiAddress::Id(AssetManager::account_id()),
is_sufficient,
min_balance,
)?;
// Lastly, the metadata
Assets::force_set_metadata(
RuntimeOrigin::root(),
asset.into(),
metadata.name,
metadata.symbol,
metadata.decimals,
metadata.is_frozen,
)
}
#[transactional]
fn destroy_foreign_asset(asset: AssetId) -> DispatchResult {
// Mark the asset as destroying
Assets::start_destroy(RuntimeOrigin::root(), asset.into())
}
fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight {
// For us both of them (Foreign and Local) have the same annotated weight for a given
// witness
// We need to take the dispatch info from the destroy call, which is already annotated in
// the assets pallet
// This is the dispatch info of destroy
RuntimeCall::Assets(pallet_assets::Call::<Runtime>::start_destroy { id: asset.into() })
.get_dispatch_info()
.weight
}
}
#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub struct AssetRegistrarMetadata {
pub name: Vec<u8>,
pub symbol: Vec<u8>,
pub decimals: u8,
pub is_frozen: bool,
}
impl pallet_asset_manager::Config for Runtime {
type AssetId = AssetId;
type AssetRegistrar = AssetRegistrar;
type AssetRegistrarMetadata = AssetRegistrarMetadata;
type Balance = Balance;
type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
type ForeignAssetType = AssetType;
type RuntimeEvent = RuntimeEvent;
type WeightInfo = (); //FIXME: run & update
}