diff --git a/evm-template/Cargo.lock b/evm-template/Cargo.lock index c6739dc..b3169f4 100644 --- a/evm-template/Cargo.lock +++ b/evm-template/Cargo.lock @@ -6694,6 +6694,39 @@ dependencies = [ "num-traits", ] +[[package]] +name = "orml-traits" +version = "0.10.0" +source = "git+https://github.com/OpenZeppelin/open-runtime-module-library?branch=polkadot-v1.10.0#92fa20ffd3bef00f4838b6a0a6bcb7610b06cfaf" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "num-traits", + "orml-utilities", + "parity-scale-codec", + "paste", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.10.0)", + "staging-xcm", +] + +[[package]] +name = "orml-utilities" +version = "0.10.0" +source = "git+https://github.com/OpenZeppelin/open-runtime-module-library?branch=polkadot-v1.10.0#92fa20ffd3bef00f4838b6a0a6bcb7610b06cfaf" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.10.0)", +] + [[package]] name = "overload" version = "0.1.1" @@ -6718,6 +6751,25 @@ dependencies = [ "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.10.0)", ] +[[package]] +name = "pallet-asset-manager" +version = "0.1.0" +source = "git+https://github.com/OpenZeppelin/moonbeam.git?branch=polkadot-v1.10.0#e1cb96f42dbd156a9f12de8ce6d3143a0ffde1df" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.10.0)", + "staging-xcm", + "xcm-primitives", +] + [[package]] name = "pallet-asset-rate" version = "7.0.0" @@ -8030,6 +8082,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-manager", "pallet-assets", "pallet-aura", "pallet-authorship", @@ -8083,6 +8136,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "xcm-primitives", ] [[package]] @@ -15715,6 +15769,35 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "xcm-primitives" +version = "0.1.1" +source = "git+https://github.com/OpenZeppelin/moonbeam.git?branch=polkadot-v1.10.0#e1cb96f42dbd156a9f12de8ce6d3143a0ffde1df" +dependencies = [ + "cumulus-primitives-core", + "ethereum", + "ethereum-types", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "impl-trait-for-tuples", + "log", + "orml-traits", + "pallet-staking", + "parity-scale-codec", + "polkadot-runtime-common", + "scale-info", + "serde", + "sha3", + "sp-io", + "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.10.0)", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + [[package]] name = "xcm-procedural" version = "7.0.0" diff --git a/evm-template/Cargo.toml b/evm-template/Cargo.toml index 70c38ae..92b605a 100644 --- a/evm-template/Cargo.toml +++ b/evm-template/Cargo.toml @@ -159,6 +159,10 @@ pallet-evm-precompile-modexp = { git = "https://github.com/OpenZeppelin/frontier pallet-evm-precompile-sha3fips = { git = "https://github.com/OpenZeppelin/frontier", branch = "polkadot-v1.10.0", default-features = false } pallet-evm-precompile-simple = { git = "https://github.com/OpenZeppelin/frontier", branch = "polkadot-v1.10.0", default-features = false } +# Moonbeam +pallet-asset-manager = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-v1.10.0", default-features = false } +xcm-primitives = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-v1.10.0", default-features = false } + # Fuzzer substrate-runtime-fuzzer = { git = "https://github.com/srlabs/substrate-runtime-fuzzer.git", default-features = false } ziggy = { version = "0.8", default-features = false } diff --git a/evm-template/runtime/Cargo.toml b/evm-template/runtime/Cargo.toml index 4cb3cd0..7fa3d3f 100644 --- a/evm-template/runtime/Cargo.toml +++ b/evm-template/runtime/Cargo.toml @@ -96,6 +96,10 @@ pallet-evm-precompile-modexp = { workspace = true } pallet-evm-precompile-sha3fips = { workspace = true } pallet-evm-precompile-simple = { workspace = true } +# Moonbeam +pallet-asset-manager = { workspace = true } +xcm-primitives = { workspace = true } + [dev-dependencies] sp-io = { workspace = true } @@ -127,6 +131,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-manager/std", "pallet-assets/std", "pallet-aura/std", "pallet-authorship/std", @@ -173,6 +178,7 @@ std = [ "sp-version/std", "xcm-builder/std", "xcm-executor/std", + "xcm-primitives/std", "xcm/std", ] async-backing = [] @@ -188,6 +194,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", + "pallet-asset-manager/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", @@ -223,6 +230,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-manager/try-runtime", "pallet-assets/try-runtime", "pallet-aura/try-runtime", "pallet-authorship/try-runtime", diff --git a/evm-template/runtime/src/configs/asset_config.rs b/evm-template/runtime/src/configs/asset_config.rs new file mode 100644 index 0000000..e0e874b --- /dev/null +++ b/evm-template/runtime/src/configs/asset_config.rs @@ -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 pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + 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; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; + type CallbackHandle = (); + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); + type ForceOrigin = EnsureRoot; + type Freezer = (); + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type RemoveItemsLimit = RemoveItemsLimit; + type RuntimeEvent = RuntimeEvent; + type StringLimit = StringLimit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; //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 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 for AssetType { + type Error = (); + + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl From for Option { + fn from(val: AssetType) -> Self { + match val { + AssetType::Xcm(location) => Some(location), + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +impl From 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(::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 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::::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, + pub symbol: Vec, + 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; + type ForeignAssetType = AssetType; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); //FIXME: run & update +} diff --git a/evm-template/runtime/src/configs/mod.rs b/evm-template/runtime/src/configs/mod.rs index 2b4c94b..3dd3ef0 100644 --- a/evm-template/runtime/src/configs/mod.rs +++ b/evm-template/runtime/src/configs/mod.rs @@ -1,3 +1,5 @@ +pub mod asset_config; +pub use asset_config::AssetType; pub mod governance; pub mod xcm_config; @@ -11,15 +13,14 @@ use frame_support::{ dispatch::DispatchClass, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU32, ConstU64, Contains, EitherOfDiverse, FindAuthor, - InstanceFilter, TransformOrigin, + ConstU32, ConstU64, Contains, EitherOfDiverse, FindAuthor, InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, PalletId, }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, + EnsureRoot, }; pub use governance::origins::pallet_custom_origins; use governance::{origins::Treasurer, TreasurySpender}; @@ -53,7 +54,7 @@ use xcm_config::XcmOriginToTransactDispatchOrigin; use crate::{ constants::{ - currency::{deposit, CENTS, EXISTENTIAL_DEPOSIT, MICROCENTS, MILLICENTS}, + currency::{deposit, EXISTENTIAL_DEPOSIT, MICROCENTS}, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MAX_BLOCK_LENGTH, MAX_POV_SIZE, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION, WEIGHT_PER_GAS, }, @@ -313,39 +314,6 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; } -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; -} - -impl pallet_assets::Config for Runtime { - type ApprovalDeposit = ApprovalDeposit; - type AssetAccountDeposit = AssetAccountDeposit; - type AssetDeposit = AssetDeposit; - type AssetId = u32; - type AssetIdParameter = parity_scale_codec::Compact; - type Balance = Balance; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); - type CallbackHandle = (); - type CreateOrigin = AsEnsureOriginWithArg>; - type Currency = Balances; - type Extra = (); - type ForceOrigin = EnsureRoot; - type Freezer = (); - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type RemoveItemsLimit = RemoveItemsLimit; - type RuntimeEvent = RuntimeEvent; - type StringLimit = StringLimit; - type WeightInfo = pallet_assets::weights::SubstrateWeight; -} - parameter_types! { /// Relay Chain `TransactionByteFee` / 10 pub const TransactionByteFee: Balance = 10 * MICROCENTS; diff --git a/evm-template/runtime/src/configs/xcm_config.rs b/evm-template/runtime/src/configs/xcm_config.rs index 2363591..8e3e351 100644 --- a/evm-template/runtime/src/configs/xcm_config.rs +++ b/evm-template/runtime/src/configs/xcm_config.rs @@ -9,29 +9,30 @@ use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountKey20Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, NativeAsset, - NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + ConvertedConcreteId, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, + NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::JustTry, XcmExecutor}; +use xcm_primitives::AsAssetType; use crate::{ configs::{ - Balances, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, + AssetType, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }, - types::{AccountId, Balance}, - AllPalletsWithSystem, Assets, ParachainInfo, PolkadotXcm, + types::{AccountId, AssetId, Balance, XcmFeesToAccount}, + AllPalletsWithSystem, AssetManager, Assets, Balances, ParachainInfo, PolkadotXcm, }; parameter_types! { pub const RelayLocation: Location = Location::parent(); pub const RelayNetwork: Option = None; - pub PlaceholderAccount: AccountId = PolkadotXcm::check_account(); pub AssetsPalletLocation: Location = PalletInstance(::index() as u8).into(); + pub BalancesPalletLocation: Location = PalletInstance(::index() as u8).into(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -53,12 +54,12 @@ pub type LocationToAccountId = ( AccountKey20Aliases, ); -/// Means for transacting assets on this chain. +/// Means for transacting native currency on this chain. pub type LocalAssetTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an AccountId20 Location into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -72,16 +73,15 @@ pub type LocalFungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: Assets, // Use this currency when it is a fungible asset matching the given location or name: - TrustBackedAssetsConvertedConcreteId, + ConvertedConcreteId, JustTry>, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We don't track any teleports of `Assets`. NoChecking, - // We don't track any teleports of `Assets`, but a placeholder account is provided due to trait - // bounds. - PlaceholderAccount, + // We don't track any teleports. + (), >; /// Means for transacting assets on this chain. @@ -166,7 +166,10 @@ impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type SafeCallFilter = Everything; type SubscriptionService = PolkadotXcm; - type Trader = UsingComponents; + type Trader = ( + UsingComponents, + xcm_primitives::FirstAssetTrader, + ); type TransactionalProcessor = FrameTransactionalProcessor; type UniversalAliases = Nothing; // Teleporting is disabled. diff --git a/evm-template/runtime/src/lib.rs b/evm-template/runtime/src/lib.rs index 6e3a578..36da92f 100644 --- a/evm-template/runtime/src/lib.rs +++ b/evm-template/runtime/src/lib.rs @@ -191,6 +191,7 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment = 11, Assets: pallet_assets = 12, Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 13, + AssetManager: pallet_asset_manager = 14, // Governance Sudo: pallet_sudo = 15, diff --git a/evm-template/runtime/src/types.rs b/evm-template/runtime/src/types.rs index fd3eb7a..9dfcab8 100644 --- a/evm-template/runtime/src/types.rs +++ b/evm-template/runtime/src/types.rs @@ -7,14 +7,18 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, Verify}, MultiAddress, }; +use xcm_builder::ConvertedConcreteId; +use xcm_executor::traits::JustTry; +use xcm_primitives::AsAssetType; pub use crate::{ - configs::{xcm_config::RelayLocation, StakingAdminBodyId}, + configs::{xcm_config::RelayLocation, AssetType, StakingAdminBodyId, TreasuryAccount}, constants::{ BLOCK_PROCESSING_VELOCITY, RELAY_CHAIN_SLOT_DURATION_MILLIS, UNINCLUDED_SEGMENT_CAPACITY, }, AllPalletsWithSystem, Runtime, RuntimeCall, }; +use crate::{AssetManager, Assets}; /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = @@ -29,6 +33,9 @@ pub type AccountId = <::Signer as IdentifyAccount>::Account /// Balance of an account. pub type Balance = u128; +/// Identifier of an asset +pub type AssetId = u128; + /// Index of a transaction in the chain. pub type Nonce = u32; @@ -83,3 +90,20 @@ pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, >; + +/// This is the struct that will handle the revenue from xcm fees +/// We do not burn anything because we want to mimic exactly what +/// the sovereign account has +pub type XcmFeesToAccount = xcm_primitives::XcmFeesToAccount< + Assets, + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + AccountId, + TreasuryAccount, +>; diff --git a/evm-template/runtime/tests/constants_test.rs b/evm-template/runtime/tests/constants_test.rs index ae344f9..1be7b47 100644 --- a/evm-template/runtime/tests/constants_test.rs +++ b/evm-template/runtime/tests/constants_test.rs @@ -21,7 +21,7 @@ mod constant_tests { mod runtime_tests { use frame_support::{pallet_prelude::Weight, traits::TypedGet, PalletId}; use parachain_template_runtime::{ - configs::*, + configs::{asset_config::*, *}, constants::{currency::*, *}, *, };