diff --git a/Cargo.lock b/Cargo.lock index 03d992038..42b1d13c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13729,12 +13729,15 @@ dependencies = [ "frame-try-runtime 0.45.0", "hex", "log", + "pallet-assets 41.0.0", "pallet-aura 38.0.0", "pallet-authorship 39.0.0", "pallet-balances 40.0.0", "pallet-collator-selection 20.0.0", "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", + "pallet-nfts 33.0.0", + "pallet-nfts-runtime-api 25.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", "pallet-revive", diff --git a/Cargo.toml b/Cargo.toml index d1109b76c..4a9c4b83c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", bra pallet-multisig = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } pallet-nft-fractionalization = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } pallet-nfts-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } +pallet-nfts-sdk = { package = "pallet-nfts", git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } pallet-preimage = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } pallet-proxy = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } pallet-revive = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml index 503642ef0..66814bdef 100644 --- a/pallets/nfts/runtime-api/Cargo.toml +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -9,9 +9,6 @@ readme = "README.md" repository.workspace = true version = "23.0.0" -[lints] -workspace = true - [package.metadata.docs.rs] targets = [ "x86_64-unknown-linux-gnu" ] diff --git a/pallets/nfts/runtime-api/src/lib.rs b/pallets/nfts/runtime-api/src/lib.rs index 87faa7909..23af6a381 100644 --- a/pallets/nfts/runtime-api/src/lib.rs +++ b/pallets/nfts/runtime-api/src/lib.rs @@ -22,6 +22,7 @@ extern crate alloc; use alloc::vec::Vec; + use codec::{Decode, Encode}; sp_api::decl_runtime_apis! { diff --git a/runtime/mainnet/Cargo.toml b/runtime/mainnet/Cargo.toml index 48691a517..eebb4a95e 100644 --- a/runtime/mainnet/Cargo.toml +++ b/runtime/mainnet/Cargo.toml @@ -33,11 +33,14 @@ frame-system.workspace = true frame-system-benchmarking.workspace = true frame-system-rpc-runtime-api.workspace = true frame-try-runtime.workspace = true +pallet-assets.workspace = true pallet-aura.workspace = true pallet-authorship.workspace = true pallet-balances.workspace = true pallet-message-queue.workspace = true pallet-multisig.workspace = true +pallet-nfts-runtime-api.workspace = true +pallet-nfts-sdk.workspace = true pallet-preimage.workspace = true pallet-proxy.workspace = true pallet-revive.workspace = true @@ -114,12 +117,15 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime/std", + "pallet-assets/std", "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", "pallet-message-queue/std", "pallet-multisig/std", + "pallet-nfts-runtime-api/std", + "pallet-nfts-sdk/std", "pallet-preimage/std", "pallet-proxy/std", "pallet-revive/std", @@ -166,10 +172,12 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-nfts-sdk/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-revive/runtime-benchmarks", @@ -199,12 +207,14 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-assets/try-runtime", "pallet-aura/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", + "pallet-nfts-sdk/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-revive/try-runtime", diff --git a/runtime/mainnet/src/apis.rs b/runtime/mainnet/src/apis.rs index 94451a097..2854076fe 100644 --- a/runtime/mainnet/src/apis.rs +++ b/runtime/mainnet/src/apis.rs @@ -3,7 +3,10 @@ use alloc::vec::Vec; use codec::Encode; use frame_support::{ genesis_builder_helper::{build_state, get_preset}, - traits::tokens::{Fortitude::Polite, Preservation::Preserve}, + traits::{ + nonfungibles_v2::Inspect, + tokens::{Fortitude::Polite, Preservation::Preserve}, + }, weights::{Weight, WeightToFee as _}, }; use pallet_revive::AddressMapper; @@ -30,9 +33,9 @@ use xcm_runtime_apis::{ use super::{ config::{monetary::fee::WeightToFee, system::RuntimeBlockWeights, xcm as xcm_config}, AccountId, Balance, Balances, Block, BlockNumber, BlockWeights, EventRecord, Executive, - ExtrinsicInclusionMode, InherentDataExt, Nonce, OriginCaller, ParachainSystem, PolkadotXcm, - Revive, Runtime, RuntimeCall, RuntimeEvent, RuntimeGenesisConfig, RuntimeOrigin, SessionKeys, - System, TransactionPayment, UncheckedExtrinsic, VERSION, + ExtrinsicInclusionMode, InherentDataExt, Nfts, Nonce, OriginCaller, ParachainSystem, + PolkadotXcm, Revive, Runtime, RuntimeCall, RuntimeEvent, RuntimeGenesisConfig, RuntimeOrigin, + SessionKeys, System, TransactionPayment, UncheckedExtrinsic, VERSION, }; impl_runtime_apis! { @@ -189,6 +192,50 @@ impl_runtime_apis! { } } + impl pallet_nfts_runtime_api::NftsApi for Runtime { + fn owner(collection: u32, item: u32) -> Option { + >::owner(&collection, &item) + } + + fn collection_owner(collection: u32) -> Option { + >::collection_owner(&collection) + } + + fn attribute( + collection: u32, + item: u32, + key: Vec, + ) -> Option> { + >::attribute(&collection, &item, &key) + } + + fn custom_attribute( + account: AccountId, + collection: u32, + item: u32, + key: Vec, + ) -> Option> { + >::custom_attribute( + &account, + &collection, + &item, + &key, + ) + } + + fn system_attribute( + collection: u32, + item: Option, + key: Vec, + ) -> Option> { + >::system_attribute(&collection, item.as_ref(), &key) + } + + fn collection_attribute(collection: u32, key: Vec) -> Option> { + >::collection_attribute(&collection, &key) + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs new file mode 100644 index 000000000..7029206fd --- /dev/null +++ b/runtime/mainnet/src/config/assets.rs @@ -0,0 +1,562 @@ +use frame_support::{ + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32}, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +use pallet_nfts::PalletFeatures; +use pallet_nfts_sdk as pallet_nfts; +use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId, Signature}; +use sp_runtime::traits::Verify; + +use crate::{ + config::monetary::ExistentialDeposit, deposit, AccountId, Balance, Balances, BlockNumber, + Runtime, RuntimeEvent, DAYS, +}; + +/// We allow root to execute privileged asset operations. +pub type AssetsForceOrigin = EnsureRoot; + +parameter_types! { + // Accounts for `Asset` max size. + // For details, refer to `ensure_asset_deposit`. + pub const AssetDeposit: Balance = deposit(1, 210); + // Enough to keep the balance in state / 100. + // For details, refer to `ensure_asset_account_deposit`. + pub const AssetAccountDeposit: Balance = deposit(1, 16) / 100; + pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); + pub const AssetsStringLimit: u32 = 50; + // Accounts for `Metadata` key size + some elements from `AssetMetadata`. + // For details, refer to `ensure_metadata_deposit_base`. + pub const MetadataDepositBase: Balance = deposit(1, 38); + pub const MetadataDepositPerByte: Balance = deposit(0, 1); +} + +pub(crate) type TrustBackedAssetsInstance = pallet_assets::Instance1; +impl pallet_assets::Config for Runtime { + type ApprovalDeposit = ApprovalDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type AssetDeposit = AssetDeposit; + type AssetId = AssetIdForTrustBackedAssets; + type AssetIdParameter = codec::Compact; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); + type ForceOrigin = AssetsForceOrigin; + type Freezer = (); + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type RemoveItemsLimit = ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; + type StringLimit = AssetsStringLimit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; +} + +parameter_types! { + // All features enabled. + pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + // Accounts for all the required elements to store a collection. + // For details, refer to `ensure_collection_deposit`. + pub const NftsCollectionDeposit: Balance = deposit(4, 294); + // Accounts for the required elements to keep one item of a collection in state. + // For details, refer to `ensure_item_deposit_deposit`. + pub const NftsItemDeposit: Balance = deposit(1, 861) / 100; + // Accounts for the base cost to include metadata for a collection or item. + // For details, refer to `ensure_metadata_deposit_base`. + pub const NftsMetadataDepositBase: Balance = deposit(1, 56) / 100; + // Accounts for the base cost to include attributes to a collection or item. + // For details, refer to `ensure_attribute_deposit_base`. + pub const NftsAttributeDepositBase: Balance = deposit(1, 89) / 100; + pub const NftsDepositPerByte: Balance = deposit(0, 1); + pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; +} + +impl pallet_nfts::Config for Runtime { + type ApprovalsLimit = ConstU32<20>; + type AttributeDepositBase = NftsAttributeDepositBase; + type CollectionDeposit = NftsCollectionDeposit; + type CollectionId = CollectionId; + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = NftsDepositPerByte; + type Features = NftsPalletFeatures; + type ForceOrigin = AssetsForceOrigin; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<30>; + type ItemDeposit = NftsItemDeposit; + type ItemId = ItemId; + type KeyLimit = ConstU32<64>; + type Locker = (); + type MaxAttributesPerCall = ConstU32<10>; + type MaxDeadlineDuration = NftsMaxDeadlineDuration; + type MaxTips = ConstU32<10>; + type MetadataDepositBase = NftsMetadataDepositBase; + type OffchainPublic = ::Signer; + type OffchainSignature = Signature; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<256>; + type ValueLimit = ConstU32<256>; + type WeightInfo = pallet_nfts::weights::SubstrateWeight; +} + +#[cfg(test)] +mod tests { + use std::any::TypeId; + + use codec::MaxEncodedLen; + use frame_support::{traits::StorageInfoTrait, Blake2_128Concat, StorageHasher}; + use sp_runtime::traits::Get; + + use super::*; + use crate::{AccountId, Balance}; + + mod assets { + use super::*; + + #[test] + fn ensure_asset_approval_deposit() { + assert_eq!(ExistentialDeposit::get(), ApprovalDeposit::get()); + assert_eq!( + TypeId::of::< + >::ApprovalDeposit, + >(), + TypeId::of::(), + ); + } + + #[test] + fn ensure_asset_account_deposit() { + // Provide a deposit enough to keep the balance in state. + assert_eq!(Balance::max_encoded_len(), 16); + assert_eq!( + deposit(1, Balance::max_encoded_len() as u32) / 100, + AssetAccountDeposit::get() + ); + + assert_eq!( + TypeId::of::<>::AssetAccountDeposit>(), + TypeId::of::(), + ); + } + + #[test] + fn ensure_asset_deposit() { + let max_size = Blake2_128Concat::max_len::< + >::AssetId, + >() + + pallet_assets::AssetDetails::::max_encoded_len(); + assert_eq!(max_size as u32, 210); + assert_eq!(deposit(1, max_size as u32), AssetDeposit::get()); + assert_eq!( + TypeId::of::< + >::AssetDeposit, + >(), + TypeId::of::(), + ); + } + + #[test] + fn defines_specific_asset_id() { + assert_eq!( + TypeId::of::<>::AssetId>( + ), + TypeId::of::(), + ); + } + + #[test] + fn defines_specific_asset_id_parameter() { + assert_eq!( + TypeId::of::< + >::AssetIdParameter, + >(), + TypeId::of::>(), + ); + } + + #[test] + fn units_to_record_balance() { + assert_eq!( + TypeId::of::<>::Balance>( + ), + TypeId::of::(), + ); + } + + #[test] + #[cfg(feature = "runtime-benchmarks")] + fn benchmark_helper_is_default() { + assert_eq!( + TypeId::of::< + >::BenchmarkHelper, + >(), + TypeId::of::<()>(), + ); + } + + #[test] + fn callback_handle_is_default() { + assert_eq!( + TypeId::of::< + >::CallbackHandle, + >(), + TypeId::of::<()>(), + ); + } + + #[test] + fn create_origin_ensures_signed() { + assert_eq!( + TypeId::of::< + >::CreateOrigin, + >(), + TypeId::of::>>(), + ); + } + + #[test] + fn balances_provide_currency() { + assert_eq!( + TypeId::of::<>::Currency>( + ), + TypeId::of::(), + ); + } + + #[test] + fn no_extra_data_is_stored() { + assert_eq!( + TypeId::of::<>::Extra>( + ), + TypeId::of::<()>(), + ); + } + + #[test] + fn force_origin_ensures_root() { + assert_eq!(TypeId::of::(), TypeId::of::>(),); + assert_eq!( + TypeId::of::< + >::ForceOrigin, + >(), + TypeId::of::(), + ); + } + + #[test] + fn freezer_is_not_configured() { + assert_eq!( + TypeId::of::<>::Freezer>( + ), + TypeId::of::<()>(), + ); + } + + #[test] + fn ensure_metadata_deposit_base() { + // Size doesn't include metadata name and symbol, these aren't part of the base cost, + // rather the cost of those parameters will be calculated based on their length times + // `NftsDepositPerByte`. + // Everything else but these two fields is part of this deposit base. + // src: https://github.com/paritytech/polkadot-sdk/blob/7a7e016a1da297adc13f855979232e0059df258a/substrate/frame/assets/src/types.rs#L188 + let max_size = Blake2_128Concat::max_len::< + >::AssetId, + >() + Balance::max_encoded_len() + + u8::max_encoded_len() + + bool::max_encoded_len(); + assert_eq!(deposit(1, max_size as u32), MetadataDepositBase::get()); + + assert_eq!( + TypeId::of::<>::MetadataDepositBase>(), + TypeId::of::(), + ); + } + + #[test] + fn ensure_metadata_deposit_per_byte() { + assert_eq!(deposit(0, 1), MetadataDepositPerByte::get()); + assert_eq!( + TypeId::of::<>::MetadataDepositPerByte>(), + TypeId::of::(), + ); + } + + #[test] + fn only_destroys_so_many_items_at_once() { + assert_eq!( + <>::RemoveItemsLimit as Get>::get(), + 1000, + ); + } + + #[test] + fn ensure_string_limit() { + assert_eq!(AssetsStringLimit::get(), 50,); + assert_eq!( + TypeId::of::< + >::StringLimit, + >(), + TypeId::of::(), + ); + } + + #[test] + fn default_weights_are_not_used() { + assert_ne!( + TypeId::of::< + >::WeightInfo, + >(), + TypeId::of::<()>(), + ); + } + } + + mod nfts { + use pallet_nfts::{AttributeNamespace, PalletFeature::*}; + use sp_runtime::{MultiSignature, MultiSigner}; + + use super::*; + + #[test] + fn item_approvals_limit_is_20() { + assert_eq!(<::ApprovalsLimit as Get>::get(), 20); + } + + #[test] + fn ensure_attribute_deposit_base() { + // We only account for key length without the `BoundedVec` element. + // as per: https://github.com/paritytech/polkadot-sdk/blob/1866c3b4673b66a62b1eb9c8c82f2cd827cbd388/substrate/frame/nfts/src/lib.rs#L1414 + let key_size = Blake2_128Concat::max_len::() + + Blake2_128Concat::max_len::() + + Blake2_128Concat::max_len::>(); + assert_eq!(key_size, 89); + assert_eq!(deposit(1, key_size as u32) / 100, NftsAttributeDepositBase::get()); + } + + #[test] + fn ensure_collection_deposit() { + // We account for the different elements stored when creating a new collection: + // src: https://github.com/paritytech/polkadot-sdk/blob/7aac8861752428e623b48741193d9a9d82e29cbf/substrate/frame/nfts/src/features/create_delete_collection.rs#L36 + + let max_collection_size = pallet_nfts::Collection::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + + let max_collection_role_size = pallet_nfts::CollectionRoleOf::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + + let max_collection_config_size = + pallet_nfts::CollectionConfigOf::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + + let max_collection_account_size = + pallet_nfts::CollectionAccount::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + + let total_collection_size = max_collection_size + + max_collection_role_size + + max_collection_config_size + + max_collection_account_size; + assert_eq!(total_collection_size, 294); + // 4 different storage items means 4 different keys. + assert_eq!(deposit(4, total_collection_size), NftsCollectionDeposit::get()); + } + + #[test] + fn collection_id_is_u32() { + assert_eq!( + TypeId::of::<::CollectionId>(), + TypeId::of::(), + ); + } + + #[test] + fn create_origin_ensures_signed() { + assert_eq!( + TypeId::of::<::CreateOrigin>(), + TypeId::of::>>(), + ); + } + + #[test] + fn balances_provides_currency() { + assert_eq!( + TypeId::of::<::Currency>(), + TypeId::of::(), + ); + } + + #[test] + fn ensure_deposit_per_byte_deposit() { + assert_eq!( + TypeId::of::<::DepositPerByte>(), + TypeId::of::(), + ); + assert_eq!( + <::DepositPerByte as Get>::get(), + deposit(0, 1) + ); + } + + #[test] + fn all_features_are_active() { + assert_eq!( + TypeId::of::<::Features>(), + TypeId::of::(), + ); + + assert!([Trading, Attributes, Approvals, Swaps] + .iter() + .all(|feat| ::Features::get().is_enabled(*feat))); + } + + #[test] + fn force_origin_ensures_root() { + assert_eq!( + TypeId::of::<::ForceOrigin>(), + TypeId::of::>(), + ); + } + + #[cfg(feature = "runtime-benchmarks")] + #[test] + fn benchmark_helper_is_default() { + assert_eq!( + TypeId::of::<::Helper>(), + TypeId::of::<()>(), + ); + } + + #[test] + fn max_attributes_per_item_is_30() { + assert_eq!( + <::ItemAttributesApprovalsLimit as Get>::get(), + 30 + ); + } + + #[test] + fn ensure_item_deposit() { + // Accounts for `Item` storage item max size. + let max_size = pallet_nfts::Item::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(max_size, 861); + assert_eq!(deposit(1, max_size) / 100, NftsItemDeposit::get()); + assert_eq!( + TypeId::of::<::ItemDeposit>(), + TypeId::of::(), + ); + } + + #[test] + fn item_id_is_u32() { + assert_eq!( + TypeId::of::<::ItemId>(), + TypeId::of::(), + ); + } + + #[test] + fn attribute_key_maximum_length_is_64() { + assert_eq!(<::KeyLimit as Get>::get(), 64,); + } + + #[test] + fn locker_is_default() { + assert_eq!( + TypeId::of::<::Locker>(), + TypeId::of::<()>(), + ); + } + + #[test] + fn max_attributes_set_per_call_is_10() { + assert_eq!( + <::MaxAttributesPerCall as Get>::get(), + 10, + ); + } + + #[test] + fn deadline_duration_is_360_days() { + assert_eq!(NftsMaxDeadlineDuration::get(), 12 * 30 * DAYS); + assert_eq!( + TypeId::of::<::MaxDeadlineDuration>(), + TypeId::of::(), + ); + } + + #[test] + fn max_tips_paid_at_once_is_10() { + assert_eq!(<::MaxTips as Get>::get(), 10,); + } + + #[test] + fn ensure_metadata_deposit_base() { + // MetadataDepositBase is used for both, items and collections. + let item_metadata_key_size = + Blake2_128Concat::max_len::() + Blake2_128Concat::max_len::(); + let collection_metadata_key_size = Blake2_128Concat::max_len::(); + // We use max of both key sizes and add size_of(Balance) which is always stored. + let base_size = item_metadata_key_size.max(collection_metadata_key_size) + + Balance::max_encoded_len(); + assert_eq!(base_size, 56); + assert_eq!(NftsMetadataDepositBase::get(), deposit(1, base_size as u32) / 100); + assert_eq!( + TypeId::of::<::MetadataDepositBase>(), + TypeId::of::(), + ); + } + + #[test] + fn off_chain_public_identifies_as_multisigner() { + assert_eq!( + TypeId::of::<::OffchainPublic>(), + TypeId::of::<::Signer>(), + ); + + assert_eq!(TypeId::of::<::Signer>(), TypeId::of::(),); + } + + #[test] + fn off_chain_signature_is_multisignature() { + assert_eq!( + TypeId::of::<::OffchainSignature>(), + TypeId::of::(), + ); + + assert_eq!(TypeId::of::(), TypeId::of::(),); + } + + #[test] + fn string_limit_is_256() { + assert_eq!(<::StringLimit as Get>::get(), 256,); + } + + #[test] + fn value_limit_is_256() { + assert_eq!(<::ValueLimit as Get>::get(), 256,); + } + + #[test] + fn default_weights_are_not_used() { + assert_ne!( + TypeId::of::<::WeightInfo>(), + TypeId::of::<()>(), + ); + } + } +} diff --git a/runtime/mainnet/src/config/mod.rs b/runtime/mainnet/src/config/mod.rs index bd74241b7..4f984bcb0 100644 --- a/runtime/mainnet/src/config/mod.rs +++ b/runtime/mainnet/src/config/mod.rs @@ -1,3 +1,5 @@ +// Assets. +mod assets; // Collation. mod collation; /// Governance. diff --git a/runtime/mainnet/src/lib.rs b/runtime/mainnet/src/lib.rs index 224ca073f..4f4e78382 100644 --- a/runtime/mainnet/src/lib.rs +++ b/runtime/mainnet/src/lib.rs @@ -34,6 +34,7 @@ use frame_system::{ CheckGenesis, CheckMortality, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, CheckWeight, EnsureRoot, }; +use pallet_nfts_sdk as pallet_nfts; use pallet_transaction_payment::ChargeTransactionPayment; // Polkadot imports use polkadot_runtime_common::SlowAdjustingFeeUpdate; @@ -267,6 +268,12 @@ mod runtime { // Utility #[runtime::pallet_index(43)] pub type Utility = pallet_utility::Pallet; + + // Assets + #[runtime::pallet_index(50)] + pub type Nfts = pallet_nfts::Pallet; + #[runtime::pallet_index(52)] + pub type Assets = pallet_assets::Pallet; } #[cfg(feature = "runtime-benchmarks")]