From cf99ad46b804cf6a1ba9ba5ada4ec35f1612fa25 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Wed, 5 Feb 2025 04:34:53 +0100 Subject: [PATCH 01/25] refactor(mainnet): include assets fmt refactor(collator): not necessary import --- Cargo.lock | 3 + runtime/mainnet/Cargo.toml | 10 + runtime/mainnet/src/config/assets.rs | 325 +++++++++++++++++++++++++++ runtime/mainnet/src/config/mod.rs | 2 + runtime/mainnet/src/lib.rs | 6 + 5 files changed, 346 insertions(+) create mode 100644 runtime/mainnet/src/config/assets.rs diff --git a/Cargo.lock b/Cargo.lock index 03d99203..a05e820b 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 31.0.0", + "pallet-nfts-runtime-api 25.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", "pallet-revive", diff --git a/runtime/mainnet/Cargo.toml b/runtime/mainnet/Cargo.toml index 48691a51..c780cf28 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.workspace = true +pallet-nfts-runtime-api.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/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/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/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-revive/try-runtime", diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs new file mode 100644 index 00000000..d0d1d45c --- /dev/null +++ b/runtime/mainnet/src/config/assets.rs @@ -0,0 +1,325 @@ +use frame_support::{ + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32}, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +use pallet_nfts::PalletFeatures; +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, UNIT, +}; + +/// We allow root to execute privileged asset operations. +pub type AssetsForceOrigin = EnsureRoot; + +parameter_types! { + pub const AssetDeposit: Balance = deposit(1, 210); + // Enough to keep the balance in state. + pub const AssetAccountDeposit: Balance = deposit(1, 16); + pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); + pub const AssetsStringLimit: u32 = 50; + // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 26 bytes (16+4+4+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = deposit(1, 46); + pub const MetadataDepositPerByte: Balance = deposit(0, 1); +} + +pub(crate) type TrustBackedAssetsInstance = pallet_assets::Instance1; +pub type TrustBackedAssetsCall = pallet_assets::Call; +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! { + pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) + pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); + pub const NftsCollectionDeposit: Balance = 10 * UNIT; + // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); + pub const NftsItemDeposit: Balance = UNIT / 100; + pub const NftsMetadataDepositBase: Balance = deposit(1, 129); + pub const NftsAttributeDepositBase: Balance = deposit(1, 0); + pub const NftsDepositPerByte: Balance = deposit(0, 1); + pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; +} + +impl pallet_nfts::Config for Runtime { + // TODO: source from primitives + type ApprovalsLimit = ConstU32<20>; + type AttributeDepositBase = NftsAttributeDepositBase; + type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; + type CollectionBalanceDeposit = NftsCollectionBalanceDeposit; + type CollectionDeposit = NftsCollectionDeposit; + // TODO: source from primitives + 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; + // TODO: source from primitives + type ItemId = ItemId; + // TODO: source from primitives + 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 pop_runtime_common::MILLI_UNIT; + use sp_runtime::traits::Get; + + use super::*; + use crate::{AccountId, Balance}; + + mod assets { + use super::*; + + #[test] + fn ensure_asset_approval_deposit() { + assert_eq!(MILLI_UNIT * 100, 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!(deposit(1, Balance::max_encoded_len() as u32), 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!(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() { + let max_size = Blake2_128Concat::max_len::< + >::AssetId, + >() + pallet_assets::AssetMetadata::::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 super::*; + + #[test] + fn ensure_account_balance_deposit() { + let max_size = pallet_nfts::AccountBalance::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + } + + #[test] + fn ensure_collection_approval_deposit() { + let max_size = pallet_nfts::CollectionApprovals::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionApprovalDeposit::get()); + } + } +} diff --git a/runtime/mainnet/src/config/mod.rs b/runtime/mainnet/src/config/mod.rs index bd74241b..4f984bcb 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 224ca073..5ef966f9 100644 --- a/runtime/mainnet/src/lib.rs +++ b/runtime/mainnet/src/lib.rs @@ -267,6 +267,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")] From 726b37707bbef373bb118a4ce22410ea1424b568 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 01:50:11 +0100 Subject: [PATCH 02/25] test(assets): add nfts config unit tests --- runtime/mainnet/src/config/assets.rs | 269 ++++++++++++++++++++++++++- 1 file changed, 261 insertions(+), 8 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index d0d1d45c..499be8a2 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -9,7 +9,7 @@ use sp_runtime::traits::Verify; use crate::{ config::monetary::ExistentialDeposit, deposit, AccountId, Balance, Balances, BlockNumber, - Runtime, RuntimeEvent, DAYS, UNIT, + Runtime, RuntimeEvent, DAYS, }; /// We allow root to execute privileged asset operations. @@ -56,12 +56,18 @@ parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); - pub const NftsCollectionDeposit: Balance = 10 * UNIT; + // Accounts for `Collection` + + // `CollectionRoleOf` + + // `CollectionConfigOf` + + // `CollectionAccount` + // Refer to `ensure_collection_deposit` test for specifics. + pub const NftsCollectionDeposit: Balance = deposit(4, 294); // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); - pub const NftsItemDeposit: Balance = UNIT / 100; - pub const NftsMetadataDepositBase: Balance = deposit(1, 129); - pub const NftsAttributeDepositBase: Balance = deposit(1, 0); + // Accounts for `Item` storage item max size. + pub const NftsItemDeposit: Balance = deposit(1, 861); + pub const NftsMetadataDepositBase: Balance = deposit(1, 56); + pub const NftsAttributeDepositBase: Balance = deposit(1, 175); pub const NftsDepositPerByte: Balance = deposit(0, 1); pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } @@ -302,15 +308,29 @@ mod tests { } mod nfts { + use pallet_nfts::PalletFeature::*; + use sp_runtime::{MultiSignature, MultiSigner}; + use super::*; #[test] - fn ensure_account_balance_deposit() { - let max_size = pallet_nfts::AccountBalance::::storage_info() + fn item_approvals_limit_is_20() { + assert_eq!(<::ApprovalsLimit as Get>::get(), 20); + } + + #[test] + fn ensure_attribute_deposit_base() { + // Max possible size of Attribute. + let max_size = pallet_nfts::Attribute::::storage_info() .first() .and_then(|info| info.max_size) .unwrap_or_default(); - assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + // Size of Attribute value: `(BoundedVec, AttributeDepositOf)`. + let value_size = <::ValueLimit as Get>::get() + + AccountId::max_encoded_len() as u32 + + Balance::max_encoded_len() as u32; + // We only account for the key length as the deposit base. + assert_eq!(deposit(1, max_size - value_size), NftsAttributeDepositBase::get()); } #[test] @@ -321,5 +341,238 @@ mod tests { .unwrap_or_default(); assert_eq!(deposit(1, max_size), NftsCollectionApprovalDeposit::get()); } + + #[test] + fn ensure_account_balance_deposit() { + let max_size = pallet_nfts::AccountBalance::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + } + + #[test] + fn ensure_collection_deposit() { + let max_collection_size = pallet_nfts::Collection::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + + // Left for the reviewer to verify discrepancy. + // println!("STORAGE INFO MAX SIZE: {:?}", &max_collection_size); + // let key = Blake2_128Concat::max_len::(); + // let value_size = AccountId::max_encoded_len() + Balance::max_encoded_len() + 8 + 8 + + // 8 + 8; println!("MAX CALCULATED SIZE: {:?}", key + value_size); + + 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; + + // 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_feature_are_active() { + assert_eq!( + TypeId::of::<::Features>(), + TypeId::of::(), + ); + + let features = [Trading, Attributes, Approvals, Swaps]; + + for feat in features { + assert!(::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_deposit() { + let max_size = pallet_nfts::Item::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), 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_lenght_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 take the bigger of both sizes and size_of(Balance) which is always written. + let base_size = item_metadata_key_size.max(collection_metadata_key_size) + + Balance::max_encoded_len(); + assert_eq!(NftsMetadataDepositBase::get(), deposit(1, base_size as u32)); + 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::<()>(), + ); + } } } From e614927728f48ae8b176f86ee4207083c062c71a Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:54:57 +0100 Subject: [PATCH 03/25] refactor(proxy): Add assets & smart contract proxy type --- runtime/common/src/lib.rs | 74 +-------- runtime/common/src/proxy.rs | 74 +++++++++ runtime/devnet/src/config/proxy.rs | 6 + runtime/mainnet/src/config/proxy.rs | 241 ++++++++++++++++++++-------- runtime/testnet/src/config/proxy.rs | 6 + 5 files changed, 260 insertions(+), 141 deletions(-) create mode 100644 runtime/common/src/proxy.rs diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index e0890ee3..f54715bc 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -6,6 +6,8 @@ pub use parachains_common::{AccountId, AuraId, Balance, Block, BlockNumber, Hash pub use polkadot_primitives::MAX_POV_SIZE; use sp_runtime::Perbill; +pub mod proxy; + /// Nonce for an account pub type Nonce = u32; @@ -73,75 +75,3 @@ mod async_backing_params { pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; } pub use async_backing_params::*; - -/// Proxy commons for Pop runtimes -pub mod proxy { - - use codec::{Decode, Encode, MaxEncodedLen}; - use frame_support::parameter_types; - use sp_runtime::RuntimeDebug; - - use super::{deposit, Balance}; - - parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 40); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 32; - // One storage item; key size 32, value size 16 - pub const AnnouncementDepositBase: Balance = deposit(1, 48); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 32; - } - - /// The type used to represent the kinds of proxying allowed. - #[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, - )] - pub enum ProxyType { - /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. - Any, - /// Can execute any call that does not transfer funds or assets. - NonTransfer, - /// Proxy with the ability to reject time-delay proxy announcements. - CancelProxy, - /// Assets proxy. Can execute any call from `assets`, **including asset transfers**. - Assets, - /// Owner proxy. Can execute calls related to asset ownership. - AssetOwner, - /// Asset manager. Can execute calls related to asset management. - AssetManager, - /// Collator selection proxy. Can execute calls related to collator selection mechanism. - Collator, - } - impl Default for ProxyType { - fn default() -> Self { - Self::Any - } - } - - impl ProxyType { - pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { - match (s, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::Assets, ProxyType::AssetOwner) => true, - (ProxyType::Assets, ProxyType::AssetManager) => true, - (ProxyType::NonTransfer, ProxyType::Collator) => true, - _ => false, - } - } - } -} diff --git a/runtime/common/src/proxy.rs b/runtime/common/src/proxy.rs new file mode 100644 index 00000000..1c677e93 --- /dev/null +++ b/runtime/common/src/proxy.rs @@ -0,0 +1,74 @@ +/// Proxy commons for Pop runtimes +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::parameter_types; +use sp_runtime::RuntimeDebug; + +use crate::{deposit, Balance}; + +parameter_types! { + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Assets proxy. Can execute any call from `assets`, **including asset transfers**. + Assets, + /// Owner proxy. Can execute calls related to asset ownership. + AssetOwner, + /// Asset manager. Can execute calls related to asset management. + AssetManager, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, + /// Smart contract proxy. Can execute calls related to smart contract management. + SmartContract, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl ProxyType { + /// Defines proxies permission hierarchy. + // Example: A proxy that is not superset of another one won't be able to remove + // that proxy relationship + // src: https://github.com/paritytech/polkadot-sdk/blob/4cd07c56378291fddb9fceab3b508cf99034126a/substrate/frame/proxy/src/lib.rs#L802 + pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { + match (s, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Assets, ProxyType::AssetOwner) => true, + (ProxyType::Assets, ProxyType::AssetManager) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index 48653027..f5eef873 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -86,6 +86,12 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), + ProxyType::SmartContract => matches!( + c, + RuntimeCall::Contracts { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), } } diff --git a/runtime/mainnet/src/config/proxy.rs b/runtime/mainnet/src/config/proxy.rs index 411d6f29..93c2b8af 100644 --- a/runtime/mainnet/src/config/proxy.rs +++ b/runtime/mainnet/src/config/proxy.rs @@ -1,79 +1,112 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::InstanceFilter; -use pop_runtime_common::proxy::{MaxPending, MaxProxies}; -use sp_runtime::RuntimeDebug; +use pop_runtime_common::proxy::{MaxPending, MaxProxies, ProxyType}; use crate::{ - deposit, parameter_types, Balance, Balances, BlakeTwo256, Runtime, RuntimeCall, RuntimeEvent, + config::assets::TrustBackedAssetsCall, deposit, parameter_types, Balance, Balances, + BlakeTwo256, Runtime, RuntimeCall, RuntimeEvent, }; -/// The type used to represent the kinds of proxying allowed. -// Mainnet will use this definition of ProxyType instead of the ones in -// `pop-common` crates until `pallet-assets` is in runtime. -// `ProxyType` in `pop-common` include Assets specific proxies which won't -// make much sense in this runtime. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. - Any, - /// Can execute any call that does not transfer funds or assets. - NonTransfer, - /// Proxy with the ability to reject time-delay proxy announcements. - CancelProxy, - /// Collator selection proxy. Can execute calls related to collator selection mechanism. - Collator, -} -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} - -impl ProxyType { - /// Defines proxies permission hierarchy. - // Example: A proxy that is not superset of another one won't be able to remove - // that proxy relationship - // src: https://github.com/paritytech/polkadot-sdk/blob/4cd07c56378291fddb9fceab3b508cf99034126a/substrate/frame/proxy/src/lib.rs#L802 - pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { - match (s, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::NonTransfer, ProxyType::Collator) => true, - _ => false, - } - } +fn is_transfer_call(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::Balances { .. } | + RuntimeCall::Assets { .. } | + RuntimeCall::Nfts { .. } | + RuntimeCall::Treasury { .. } + ) } impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, - ProxyType::NonTransfer => !matches!(c, RuntimeCall::Balances { .. }), + ProxyType::NonTransfer => + !is_transfer_call(c) && + // Wrapped transfer calls are filtered too. + matches!( + c, + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) | + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) + if !calls.iter().any(|call| is_transfer_call(&call)) + ) && matches!( + c, + RuntimeCall::Utility(pallet_utility::Call::as_derivative { call, .. }) + if !is_transfer_call(&call) + ), ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), + ProxyType::Assets => { + matches!( + c, + RuntimeCall::Assets { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } | + RuntimeCall::Nfts { .. } + ) + }, + ProxyType::AssetOwner => matches!( + c, + RuntimeCall::Assets(TrustBackedAssetsCall::create { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::start_destroy { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::destroy_accounts { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::destroy_approvals { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::finish_destroy { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::transfer_ownership { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_team { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::create { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::destroy { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::redeposit { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::transfer_ownership { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_team { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_collection { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::AssetManager => matches!( + c, + RuntimeCall::Assets(TrustBackedAssetsCall::mint { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::burn { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::freeze { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::block { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::thaw { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::freeze_asset { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::force_mint { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::update_mint_settings { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::mint_pre_signed { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_item_transfer { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_item_properties { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::clear_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_collection_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::clear_collection_metadata { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), ProxyType::Collator => matches!( c, RuntimeCall::CollatorSelection { .. } | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), + ProxyType::SmartContract => matches!( + c, + RuntimeCall::Revive { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), } } @@ -112,43 +145,113 @@ impl pallet_proxy::Config for Runtime { mod tests { use std::any::TypeId; + use codec::MaxEncodedLen; use frame_support::{traits::Get, StorageHasher, Twox64Concat}; use pallet_proxy::Config; use parachains_common::BlockNumber; - use sp_runtime::traits::Hash; + use pop_runtime_common::proxy::ProxyType::*; + use sp_runtime::{traits::Hash, MultiAddress}; use super::*; use crate::AccountId; #[test] fn proxy_type_default_is_any() { - assert_eq!(ProxyType::default(), ProxyType::Any); + assert_eq!(ProxyType::default(), Any); } #[test] - fn proxy_type_superset_as_defined() { + fn proxy_type_supersets_as_defined() { let all_proxies = vec![ - ProxyType::Any, - ProxyType::NonTransfer, - ProxyType::CancelProxy, - ProxyType::Collator, + Any, + NonTransfer, + CancelProxy, + Assets, + AssetOwner, + AssetManager, + Collator, + SmartContract, ]; for proxy in all_proxies { // Every proxy is part of itself. assert!(ProxyType::is_superset(&proxy, &proxy)); - // Any contains all others, but is not contained. - if proxy != ProxyType::Any { - assert!(ProxyType::is_superset(&ProxyType::Any, &proxy)); - assert!(!ProxyType::is_superset(&proxy, &ProxyType::Any)); + // `Any` contains all others, but it is not contained. + if proxy != Any { + assert!(ProxyType::is_superset(&Any, &proxy)); + assert!(!ProxyType::is_superset(&proxy, &Any)); + } + if proxy != NonTransfer { + if proxy == Collator { + // `NonTransfer` is superset for `Collator`. + assert!(ProxyType::is_superset(&NonTransfer, &proxy)); + assert!(!ProxyType::is_superset(&proxy, &NonTransfer)); + } else if proxy != Any { + assert!(!ProxyType::is_superset(&proxy, &NonTransfer)); + } + } + // `CancelProxy` does not contain any other proxy. + if proxy != CancelProxy { + assert!(!ProxyType::is_superset(&CancelProxy, &proxy)); + } + // `Asset` proxy type is superset of `AssetOwner` and `AssetManager`. + if proxy != Assets { + if proxy == AssetOwner { + assert!(ProxyType::is_superset(&Assets, &proxy)); + assert!(!ProxyType::is_superset(&proxy, &Assets)); + } else if proxy == AssetManager { + assert!(ProxyType::is_superset(&Assets, &proxy)); + assert!(!ProxyType::is_superset(&proxy, &Assets)); + } else if proxy != Any { + assert!(!ProxyType::is_superset(&proxy, &Assets)); + } } - // CancelProxy does not contain any other proxy. - if proxy != ProxyType::CancelProxy { - assert!(!ProxyType::is_superset(&ProxyType::CancelProxy, &proxy)); + // `SmartContract` does not contain any other proxy. + if proxy != SmartContract { + assert!(!ProxyType::is_superset(&SmartContract, &proxy)); } } - assert!(ProxyType::is_superset(&ProxyType::NonTransfer, &ProxyType::Collator)); - assert!(!ProxyType::is_superset(&ProxyType::Collator, &ProxyType::NonTransfer)); + } + + #[test] + fn non_transfer_instance_filter_works() { + use sp_keyring::AccountKeyring::Alice; + let alice_address = MultiAddress::Id(Alice.to_account_id()); + let transfer_calls = [ + RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { + dest: alice_address.clone(), + value: 0, + }), + RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { + id: codec::Compact(0), + target: alice_address.clone(), + amount: 0, + }), + RuntimeCall::Nfts(pallet_nfts::Call::transfer { + collection: 0, + item: 0, + dest: alice_address.clone(), + }), + RuntimeCall::Treasury(pallet_treasury::Call::spend_local { + amount: 0, + beneficiary: alice_address, + }), + ]; + + for call in transfer_calls { + // Transfers related calls are filtered. + assert!(!NonTransfer.filter(&call)); + // Wrapped transfer calls are filtered too. + assert!(!NonTransfer.filter(&RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![call.clone()] + }))); + assert!(!NonTransfer.filter(&RuntimeCall::Utility(pallet_utility::Call::batch_all { + calls: vec![call.clone()] + }))); + assert!(!NonTransfer.filter(&RuntimeCall::Utility( + pallet_utility::Call::as_derivative { index: 0, call: Box::new(call) } + ))); + } } #[test] diff --git a/runtime/testnet/src/config/proxy.rs b/runtime/testnet/src/config/proxy.rs index ff70240e..b243b8fe 100644 --- a/runtime/testnet/src/config/proxy.rs +++ b/runtime/testnet/src/config/proxy.rs @@ -86,6 +86,12 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), + ProxyType::SmartContract => matches!( + c, + RuntimeCall::Contracts { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), } } From f8fdeea03d34d5e65bc62152edb742e70c8e39c8 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:42:24 +0100 Subject: [PATCH 04/25] refactor(assets): implement nfts runtime api --- Cargo.toml | 8 +++--- runtime/mainnet/src/apis.rs | 55 ++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1109b76..5a79c5c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,12 +69,13 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b # Local pallet-api = { path = "pallets/api", default-features = false } pallet-nfts = { path = "pallets/nfts", default-features = false } +pallet-nfts-runtime-api = { path = "pallets/nfts", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } @@ -94,7 +95,6 @@ pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk", branch pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } 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-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/runtime/mainnet/src/apis.rs b/runtime/mainnet/src/apis.rs index 94451a09..2854076f 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) { From 6b4b50540ce1e2b79e55f116d44654b0434c21aa Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:13:35 +0100 Subject: [PATCH 05/25] fix(pallet-nfts-api): workspace linters are not defined --- Cargo.lock | 15 ++++++++++++--- Cargo.toml | 8 ++++---- pallets/nfts/runtime-api/Cargo.toml | 3 --- pallets/nfts/runtime-api/src/lib.rs | 1 + runtime/mainnet/Cargo.toml | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a05e820b..6860cf4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10203,6 +10203,15 @@ dependencies = [ "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pallet-nfts-runtime-api" +version = "23.0.0" +dependencies = [ + "pallet-nfts 31.0.0", + "parity-scale-codec", + "sp-api 35.0.0", +] + [[package]] name = "pallet-nfts-runtime-api" version = "25.0.0" @@ -13663,7 +13672,7 @@ dependencies = [ "pallet-multisig 39.0.0", "pallet-nft-fractionalization", "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 25.0.0", + "pallet-nfts-runtime-api 23.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", "pallet-scheduler 40.0.0", @@ -13737,7 +13746,7 @@ dependencies = [ "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 25.0.0", + "pallet-nfts-runtime-api 23.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", "pallet-revive", @@ -13817,7 +13826,7 @@ dependencies = [ "pallet-multisig 39.0.0", "pallet-nft-fractionalization", "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 25.0.0", + "pallet-nfts-runtime-api 23.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", "pallet-scheduler 40.0.0", diff --git a/Cargo.toml b/Cargo.toml index 5a79c5c3..e19de606 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,13 +69,13 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b # Local pallet-api = { path = "pallets/api", default-features = false } pallet-nfts = { path = "pallets/nfts", default-features = false } -pallet-nfts-runtime-api = { path = "pallets/nfts", default-features = false } +pallet-nfts-runtime-api = { path = "pallets/nfts/runtime-api", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { 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 503642ef..66814bde 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 87faa790..23af6a38 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 c780cf28..50ac9890 100644 --- a/runtime/mainnet/Cargo.toml +++ b/runtime/mainnet/Cargo.toml @@ -22,6 +22,8 @@ scale-info.workspace = true smallvec.workspace = true # Local +pallet-nfts.workspace = true +pallet-nfts-runtime-api.workspace = true pop-runtime-common = { workspace = true, default-features = false } # Substrate @@ -39,8 +41,6 @@ pallet-authorship.workspace = true pallet-balances.workspace = true pallet-message-queue.workspace = true pallet-multisig.workspace = true -pallet-nfts.workspace = true -pallet-nfts-runtime-api.workspace = true pallet-preimage.workspace = true pallet-proxy.workspace = true pallet-revive.workspace = true From 5c75dc7e5b2cb1ade41ffb381ff5afb4b0bb4192 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:37:04 +0100 Subject: [PATCH 06/25] docs(assets): clarify deposits --- runtime/mainnet/src/config/assets.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 499be8a2..3dca4909 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -16,6 +16,7 @@ use crate::{ pub type AssetsForceOrigin = EnsureRoot; parameter_types! { + // Accounts for `Asset` max size. pub const AssetDeposit: Balance = deposit(1, 210); // Enough to keep the balance in state. pub const AssetAccountDeposit: Balance = deposit(1, 16); @@ -56,7 +57,7 @@ parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); - // Accounts for `Collection` + + // Accounts for state from `Collection` + // `CollectionRoleOf` + // `CollectionConfigOf` + // `CollectionAccount` @@ -66,7 +67,9 @@ parameter_types! { pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); // Accounts for `Item` storage item max size. pub const NftsItemDeposit: Balance = deposit(1, 861); + // Key = max(size_of(item_metadata_key), size_of(collection_metadata_key)) + Balance: 16 bytes pub const NftsMetadataDepositBase: Balance = deposit(1, 56); + // Accounts for key size of `Attribute`. pub const NftsAttributeDepositBase: Balance = deposit(1, 175); pub const NftsDepositPerByte: Balance = deposit(0, 1); pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; @@ -527,7 +530,7 @@ mod tests { let item_metadata_key_size = Blake2_128Concat::max_len::() + Blake2_128Concat::max_len::(); let collection_metadata_key_size = Blake2_128Concat::max_len::(); - // We take the bigger of both sizes and size_of(Balance) which is always written. + // We use max of both key sizes and add size_of(Balance) which is always written. let base_size = item_metadata_key_size.max(collection_metadata_key_size) + Balance::max_encoded_len(); assert_eq!(NftsMetadataDepositBase::get(), deposit(1, base_size as u32)); From e94a545016b794c3e7b65d0141820457445c7d13 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:47:48 +0100 Subject: [PATCH 07/25] chore(proxy): improve usage of references --- runtime/mainnet/src/config/proxy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/mainnet/src/config/proxy.rs b/runtime/mainnet/src/config/proxy.rs index 93c2b8af..0f44bec3 100644 --- a/runtime/mainnet/src/config/proxy.rs +++ b/runtime/mainnet/src/config/proxy.rs @@ -27,11 +27,11 @@ impl InstanceFilter for ProxyType { c, RuntimeCall::Utility(pallet_utility::Call::batch { calls }) | RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) - if !calls.iter().any(|call| is_transfer_call(&call)) + if !calls.iter().any(|call| is_transfer_call(call)) ) && matches!( c, RuntimeCall::Utility(pallet_utility::Call::as_derivative { call, .. }) - if !is_transfer_call(&call) + if !is_transfer_call(call) ), ProxyType::CancelProxy => matches!( c, From 13a239220e9f849f282f5b389b75a6fa331b997d Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:57:42 +0100 Subject: [PATCH 08/25] docs(assets): update src reference --- runtime/mainnet/src/config/assets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 3dca4909..f81d1015 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -23,7 +23,7 @@ parameter_types! { pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); pub const AssetsStringLimit: u32 = 50; // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 26 bytes (16+4+4+1+1) - // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + // https://github.com/paritytech/polkadot-sdk/blob/7a7e016a1da297adc13f855979232e0059df258a/substrate/frame/assets/src/types.rs#L188 pub const MetadataDepositBase: Balance = deposit(1, 46); pub const MetadataDepositPerByte: Balance = deposit(0, 1); } From 47b3c9234fcbc061317a0b41a74936dd78ec58d5 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:04:10 +0100 Subject: [PATCH 09/25] chore(assets): update MetadataDepositBase --- runtime/mainnet/src/config/assets.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index f81d1015..ca437cc0 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -22,9 +22,9 @@ parameter_types! { pub const AssetAccountDeposit: Balance = deposit(1, 16); pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); pub const AssetsStringLimit: u32 = 50; - // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 26 bytes (16+4+4+1+1) + // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 18 bytes (16+1+1) // https://github.com/paritytech/polkadot-sdk/blob/7a7e016a1da297adc13f855979232e0059df258a/substrate/frame/assets/src/types.rs#L188 - pub const MetadataDepositBase: Balance = deposit(1, 46); + pub const MetadataDepositBase: Balance = deposit(1, 38); pub const MetadataDepositPerByte: Balance = deposit(0, 1); } @@ -260,9 +260,13 @@ mod tests { #[test] fn ensure_metadata_deposit_base() { + // Accounts for the key length + + // Value max length without name and symbol, which are accounted per byte. let max_size = Blake2_128Concat::max_len::< >::AssetId, - >() + pallet_assets::AssetMetadata::::max_encoded_len(); + >() + Balance::max_encoded_len() + + u8::max_encoded_len() + + bool::max_encoded_len(); assert_eq!(deposit(1, max_size as u32), MetadataDepositBase::get()); assert_eq!( From e5f42128e554144404f443bf68e215ebdf953b03 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:31:23 +0100 Subject: [PATCH 10/25] docs(assets): remove TODOs --- runtime/mainnet/src/config/assets.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index ca437cc0..a351957f 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -55,6 +55,7 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + // Accounts for `AccountBalance` max size. // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); // Accounts for state from `Collection` + @@ -63,6 +64,7 @@ parameter_types! { // `CollectionAccount` // Refer to `ensure_collection_deposit` test for specifics. pub const NftsCollectionDeposit: Balance = deposit(4, 294); + // Accounts for `CollectionApprovals` max size. // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); // Accounts for `Item` storage item max size. @@ -76,13 +78,11 @@ parameter_types! { } impl pallet_nfts::Config for Runtime { - // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; type CollectionBalanceDeposit = NftsCollectionBalanceDeposit; type CollectionDeposit = NftsCollectionDeposit; - // TODO: source from primitives type CollectionId = CollectionId; type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; @@ -93,9 +93,7 @@ impl pallet_nfts::Config for Runtime { type Helper = (); type ItemAttributesApprovalsLimit = ConstU32<30>; type ItemDeposit = NftsItemDeposit; - // TODO: source from primitives type ItemId = ItemId; - // TODO: source from primitives type KeyLimit = ConstU32<64>; type Locker = (); type MaxAttributesPerCall = ConstU32<10>; @@ -368,8 +366,8 @@ mod tests { // Left for the reviewer to verify discrepancy. // println!("STORAGE INFO MAX SIZE: {:?}", &max_collection_size); // let key = Blake2_128Concat::max_len::(); - // let value_size = AccountId::max_encoded_len() + Balance::max_encoded_len() + 8 + 8 + - // 8 + 8; println!("MAX CALCULATED SIZE: {:?}", key + value_size); + // let value_size = AccountId::max_encoded_len() + Balance::max_encoded_len() + (8 * 4); + // println!("MAX CALCULATED SIZE: {:?}", key + value_size); let max_collection_role_size = pallet_nfts::CollectionRoleOf::::storage_info() .first() @@ -392,7 +390,7 @@ mod tests { max_collection_role_size + max_collection_config_size + max_collection_account_size; - + println!("{:?}", deposit(4, total_collection_size)); // 4 different storage items means 4 different keys. assert_eq!(deposit(4, total_collection_size), NftsCollectionDeposit::get()); } From 6a7fb18893dbc2706edecd0be51a496efcfc0128 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:06:50 +0100 Subject: [PATCH 11/25] refactor(proxy): revert SmartContract ProxyType --- runtime/common/src/proxy.rs | 2 -- runtime/devnet/src/config/proxy.rs | 6 ------ runtime/mainnet/src/config/proxy.rs | 22 ++-------------------- runtime/testnet/src/config/proxy.rs | 6 ------ 4 files changed, 2 insertions(+), 34 deletions(-) diff --git a/runtime/common/src/proxy.rs b/runtime/common/src/proxy.rs index 1c677e93..6e36f2e4 100644 --- a/runtime/common/src/proxy.rs +++ b/runtime/common/src/proxy.rs @@ -46,8 +46,6 @@ pub enum ProxyType { AssetManager, /// Collator selection proxy. Can execute calls related to collator selection mechanism. Collator, - /// Smart contract proxy. Can execute calls related to smart contract management. - SmartContract, } impl Default for ProxyType { fn default() -> Self { diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index f5eef873..48653027 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -86,12 +86,6 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), - ProxyType::SmartContract => matches!( - c, - RuntimeCall::Contracts { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), } } diff --git a/runtime/mainnet/src/config/proxy.rs b/runtime/mainnet/src/config/proxy.rs index 0f44bec3..bb31ebb6 100644 --- a/runtime/mainnet/src/config/proxy.rs +++ b/runtime/mainnet/src/config/proxy.rs @@ -101,12 +101,6 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), - ProxyType::SmartContract => matches!( - c, - RuntimeCall::Revive { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), } } @@ -162,16 +156,8 @@ mod tests { #[test] fn proxy_type_supersets_as_defined() { - let all_proxies = vec![ - Any, - NonTransfer, - CancelProxy, - Assets, - AssetOwner, - AssetManager, - Collator, - SmartContract, - ]; + let all_proxies = + vec![Any, NonTransfer, CancelProxy, Assets, AssetOwner, AssetManager, Collator]; for proxy in all_proxies { // Every proxy is part of itself. assert!(ProxyType::is_superset(&proxy, &proxy)); @@ -206,10 +192,6 @@ mod tests { assert!(!ProxyType::is_superset(&proxy, &Assets)); } } - // `SmartContract` does not contain any other proxy. - if proxy != SmartContract { - assert!(!ProxyType::is_superset(&SmartContract, &proxy)); - } } } diff --git a/runtime/testnet/src/config/proxy.rs b/runtime/testnet/src/config/proxy.rs index b243b8fe..ff70240e 100644 --- a/runtime/testnet/src/config/proxy.rs +++ b/runtime/testnet/src/config/proxy.rs @@ -86,12 +86,6 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), - ProxyType::SmartContract => matches!( - c, - RuntimeCall::Contracts { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), } } From 88f5eab1dde9083318a5ea310f32c78b9e9d34e6 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:09:12 +0100 Subject: [PATCH 12/25] revert: e614927728f48ae8b176f86ee4207083c062c71a --- runtime/common/src/lib.rs | 74 ++++++++- runtime/common/src/proxy.rs | 72 --------- runtime/mainnet/src/config/proxy.rs | 227 +++++++++------------------- 3 files changed, 143 insertions(+), 230 deletions(-) delete mode 100644 runtime/common/src/proxy.rs diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index f54715bc..e0890ee3 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -6,8 +6,6 @@ pub use parachains_common::{AccountId, AuraId, Balance, Block, BlockNumber, Hash pub use polkadot_primitives::MAX_POV_SIZE; use sp_runtime::Perbill; -pub mod proxy; - /// Nonce for an account pub type Nonce = u32; @@ -75,3 +73,75 @@ mod async_backing_params { pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; } pub use async_backing_params::*; + +/// Proxy commons for Pop runtimes +pub mod proxy { + + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::parameter_types; + use sp_runtime::RuntimeDebug; + + use super::{deposit, Balance}; + + parameter_types! { + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; + } + + /// The type used to represent the kinds of proxying allowed. + #[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, + )] + pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Assets proxy. Can execute any call from `assets`, **including asset transfers**. + Assets, + /// Owner proxy. Can execute calls related to asset ownership. + AssetOwner, + /// Asset manager. Can execute calls related to asset management. + AssetManager, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, + } + impl Default for ProxyType { + fn default() -> Self { + Self::Any + } + } + + impl ProxyType { + pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { + match (s, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Assets, ProxyType::AssetOwner) => true, + (ProxyType::Assets, ProxyType::AssetManager) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } + } +} diff --git a/runtime/common/src/proxy.rs b/runtime/common/src/proxy.rs deleted file mode 100644 index 6e36f2e4..00000000 --- a/runtime/common/src/proxy.rs +++ /dev/null @@ -1,72 +0,0 @@ -/// Proxy commons for Pop runtimes -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::parameter_types; -use sp_runtime::RuntimeDebug; - -use crate::{deposit, Balance}; - -parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 40); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 32; - // One storage item; key size 32, value size 16 - pub const AnnouncementDepositBase: Balance = deposit(1, 48); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 32; -} - -/// The type used to represent the kinds of proxying allowed. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. - Any, - /// Can execute any call that does not transfer funds or assets. - NonTransfer, - /// Proxy with the ability to reject time-delay proxy announcements. - CancelProxy, - /// Assets proxy. Can execute any call from `assets`, **including asset transfers**. - Assets, - /// Owner proxy. Can execute calls related to asset ownership. - AssetOwner, - /// Asset manager. Can execute calls related to asset management. - AssetManager, - /// Collator selection proxy. Can execute calls related to collator selection mechanism. - Collator, -} -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} - -impl ProxyType { - /// Defines proxies permission hierarchy. - // Example: A proxy that is not superset of another one won't be able to remove - // that proxy relationship - // src: https://github.com/paritytech/polkadot-sdk/blob/4cd07c56378291fddb9fceab3b508cf99034126a/substrate/frame/proxy/src/lib.rs#L802 - pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { - match (s, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::Assets, ProxyType::AssetOwner) => true, - (ProxyType::Assets, ProxyType::AssetManager) => true, - (ProxyType::NonTransfer, ProxyType::Collator) => true, - _ => false, - } - } -} diff --git a/runtime/mainnet/src/config/proxy.rs b/runtime/mainnet/src/config/proxy.rs index bb31ebb6..411d6f29 100644 --- a/runtime/mainnet/src/config/proxy.rs +++ b/runtime/mainnet/src/config/proxy.rs @@ -1,100 +1,73 @@ +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::InstanceFilter; -use pop_runtime_common::proxy::{MaxPending, MaxProxies, ProxyType}; +use pop_runtime_common::proxy::{MaxPending, MaxProxies}; +use sp_runtime::RuntimeDebug; use crate::{ - config::assets::TrustBackedAssetsCall, deposit, parameter_types, Balance, Balances, - BlakeTwo256, Runtime, RuntimeCall, RuntimeEvent, + deposit, parameter_types, Balance, Balances, BlakeTwo256, Runtime, RuntimeCall, RuntimeEvent, }; -fn is_transfer_call(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::Balances { .. } | - RuntimeCall::Assets { .. } | - RuntimeCall::Nfts { .. } | - RuntimeCall::Treasury { .. } - ) +/// The type used to represent the kinds of proxying allowed. +// Mainnet will use this definition of ProxyType instead of the ones in +// `pop-common` crates until `pallet-assets` is in runtime. +// `ProxyType` in `pop-common` include Assets specific proxies which won't +// make much sense in this runtime. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl ProxyType { + /// Defines proxies permission hierarchy. + // Example: A proxy that is not superset of another one won't be able to remove + // that proxy relationship + // src: https://github.com/paritytech/polkadot-sdk/blob/4cd07c56378291fddb9fceab3b508cf99034126a/substrate/frame/proxy/src/lib.rs#L802 + pub fn is_superset(s: &ProxyType, o: &ProxyType) -> bool { + match (s, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } } impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, - ProxyType::NonTransfer => - !is_transfer_call(c) && - // Wrapped transfer calls are filtered too. - matches!( - c, - RuntimeCall::Utility(pallet_utility::Call::batch { calls }) | - RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) - if !calls.iter().any(|call| is_transfer_call(call)) - ) && matches!( - c, - RuntimeCall::Utility(pallet_utility::Call::as_derivative { call, .. }) - if !is_transfer_call(call) - ), + ProxyType::NonTransfer => !matches!(c, RuntimeCall::Balances { .. }), ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), - ProxyType::Assets => { - matches!( - c, - RuntimeCall::Assets { .. } | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } | - RuntimeCall::Nfts { .. } - ) - }, - ProxyType::AssetOwner => matches!( - c, - RuntimeCall::Assets(TrustBackedAssetsCall::create { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::start_destroy { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::destroy_accounts { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::destroy_approvals { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::finish_destroy { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::transfer_ownership { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::set_team { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::create { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::destroy { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::redeposit { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::transfer_ownership { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_team { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_collection { .. }) | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), - ProxyType::AssetManager => matches!( - c, - RuntimeCall::Assets(TrustBackedAssetsCall::mint { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::burn { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::freeze { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::block { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::thaw { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::freeze_asset { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | - RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::force_mint { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::update_mint_settings { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::mint_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_properties { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_collection_metadata { .. }) | - RuntimeCall::Utility { .. } | - RuntimeCall::Multisig { .. } - ), ProxyType::Collator => matches!( c, RuntimeCall::CollatorSelection { .. } | @@ -139,101 +112,43 @@ impl pallet_proxy::Config for Runtime { mod tests { use std::any::TypeId; - use codec::MaxEncodedLen; use frame_support::{traits::Get, StorageHasher, Twox64Concat}; use pallet_proxy::Config; use parachains_common::BlockNumber; - use pop_runtime_common::proxy::ProxyType::*; - use sp_runtime::{traits::Hash, MultiAddress}; + use sp_runtime::traits::Hash; use super::*; use crate::AccountId; #[test] fn proxy_type_default_is_any() { - assert_eq!(ProxyType::default(), Any); + assert_eq!(ProxyType::default(), ProxyType::Any); } #[test] - fn proxy_type_supersets_as_defined() { - let all_proxies = - vec![Any, NonTransfer, CancelProxy, Assets, AssetOwner, AssetManager, Collator]; + fn proxy_type_superset_as_defined() { + let all_proxies = vec![ + ProxyType::Any, + ProxyType::NonTransfer, + ProxyType::CancelProxy, + ProxyType::Collator, + ]; for proxy in all_proxies { // Every proxy is part of itself. assert!(ProxyType::is_superset(&proxy, &proxy)); - // `Any` contains all others, but it is not contained. - if proxy != Any { - assert!(ProxyType::is_superset(&Any, &proxy)); - assert!(!ProxyType::is_superset(&proxy, &Any)); + // Any contains all others, but is not contained. + if proxy != ProxyType::Any { + assert!(ProxyType::is_superset(&ProxyType::Any, &proxy)); + assert!(!ProxyType::is_superset(&proxy, &ProxyType::Any)); } - if proxy != NonTransfer { - if proxy == Collator { - // `NonTransfer` is superset for `Collator`. - assert!(ProxyType::is_superset(&NonTransfer, &proxy)); - assert!(!ProxyType::is_superset(&proxy, &NonTransfer)); - } else if proxy != Any { - assert!(!ProxyType::is_superset(&proxy, &NonTransfer)); - } + // CancelProxy does not contain any other proxy. + if proxy != ProxyType::CancelProxy { + assert!(!ProxyType::is_superset(&ProxyType::CancelProxy, &proxy)); } - // `CancelProxy` does not contain any other proxy. - if proxy != CancelProxy { - assert!(!ProxyType::is_superset(&CancelProxy, &proxy)); - } - // `Asset` proxy type is superset of `AssetOwner` and `AssetManager`. - if proxy != Assets { - if proxy == AssetOwner { - assert!(ProxyType::is_superset(&Assets, &proxy)); - assert!(!ProxyType::is_superset(&proxy, &Assets)); - } else if proxy == AssetManager { - assert!(ProxyType::is_superset(&Assets, &proxy)); - assert!(!ProxyType::is_superset(&proxy, &Assets)); - } else if proxy != Any { - assert!(!ProxyType::is_superset(&proxy, &Assets)); - } - } - } - } - - #[test] - fn non_transfer_instance_filter_works() { - use sp_keyring::AccountKeyring::Alice; - let alice_address = MultiAddress::Id(Alice.to_account_id()); - let transfer_calls = [ - RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { - dest: alice_address.clone(), - value: 0, - }), - RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { - id: codec::Compact(0), - target: alice_address.clone(), - amount: 0, - }), - RuntimeCall::Nfts(pallet_nfts::Call::transfer { - collection: 0, - item: 0, - dest: alice_address.clone(), - }), - RuntimeCall::Treasury(pallet_treasury::Call::spend_local { - amount: 0, - beneficiary: alice_address, - }), - ]; - - for call in transfer_calls { - // Transfers related calls are filtered. - assert!(!NonTransfer.filter(&call)); - // Wrapped transfer calls are filtered too. - assert!(!NonTransfer.filter(&RuntimeCall::Utility(pallet_utility::Call::batch { - calls: vec![call.clone()] - }))); - assert!(!NonTransfer.filter(&RuntimeCall::Utility(pallet_utility::Call::batch_all { - calls: vec![call.clone()] - }))); - assert!(!NonTransfer.filter(&RuntimeCall::Utility( - pallet_utility::Call::as_derivative { index: 0, call: Box::new(call) } - ))); } + assert!(ProxyType::is_superset(&ProxyType::NonTransfer, &ProxyType::Collator)); + assert!(!ProxyType::is_superset(&ProxyType::Collator, &ProxyType::NonTransfer)); } #[test] From fb9234215336ce342c3edb6c15fff56ec2130c98 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:13:59 +0100 Subject: [PATCH 13/25] style(Cargo): revert format changes on dep comments --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e19de606..50044369 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,9 +73,9 @@ pallet-nfts-runtime-api = { path = "pallets/nfts/runtime-api", default-features pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } From 84188ad70ecf80bf071da0098dbe66ffc5649e49 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:38:21 +0100 Subject: [PATCH 14/25] chore(assets): apply feedback to tests --- runtime/mainnet/src/config/assets.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index a351957f..9f9007ba 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -125,7 +125,7 @@ mod tests { #[test] fn ensure_asset_approval_deposit() { - assert_eq!(MILLI_UNIT * 100, ApprovalDeposit::get()); + assert_eq!(ExistentialDeposit::get(), ApprovalDeposit::get()); assert_eq!( TypeId::of::< >::ApprovalDeposit, @@ -492,7 +492,7 @@ mod tests { } #[test] - fn attribute_key_maximum_lenght_is_64() { + fn attribute_key_maximum_length_is_64() { assert_eq!(<::KeyLimit as Get>::get(), 64,); } From b813b5247a880d01cd24ae426b8e96745c6dd9f1 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:39:11 +0100 Subject: [PATCH 15/25] chore(assets): removed unused type --- runtime/mainnet/src/config/assets.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 9f9007ba..19707b72 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -29,7 +29,6 @@ parameter_types! { } pub(crate) type TrustBackedAssetsInstance = pallet_assets::Instance1; -pub type TrustBackedAssetsCall = pallet_assets::Call; impl pallet_assets::Config for Runtime { type ApprovalDeposit = ApprovalDeposit; type AssetAccountDeposit = AssetAccountDeposit; From 5263090ef542a96fcbde357ff3be969ae6f7eecf Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:57:16 +0100 Subject: [PATCH 16/25] revert: fb9234215336ce342c3edb6c15fff56ec2130c98 This reverts commit fb9234215336ce342c3edb6c15fff56ec2130c98. --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 50044369..e19de606 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,9 +73,9 @@ pallet-nfts-runtime-api = { path = "pallets/nfts/runtime-api", default-features pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } From 8708e32a95c45af352f8c85b017a7e6ad5739c24 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 10:34:21 +0100 Subject: [PATCH 17/25] docs(assets): better comments --- runtime/mainnet/src/config/assets.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 19707b72..4798a5b5 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -257,8 +257,8 @@ mod tests { #[test] fn ensure_metadata_deposit_base() { - // Accounts for the key length + - // Value max length without name and symbol, which are accounted per byte. + // Size doesn't include metadata name and symbol, which are accounted per byte. + // Everything else but these two fields is part of this deposit base. let max_size = Blake2_128Concat::max_len::< >::AssetId, >() + Balance::max_encoded_len() + @@ -362,12 +362,6 @@ mod tests { .and_then(|info| info.max_size) .unwrap_or_default(); - // Left for the reviewer to verify discrepancy. - // println!("STORAGE INFO MAX SIZE: {:?}", &max_collection_size); - // let key = Blake2_128Concat::max_len::(); - // let value_size = AccountId::max_encoded_len() + Balance::max_encoded_len() + (8 * 4); - // println!("MAX CALCULATED SIZE: {:?}", key + value_size); - let max_collection_role_size = pallet_nfts::CollectionRoleOf::::storage_info() .first() .and_then(|info| info.max_size) From 976a845caaf283c773e2d6b60e0e63d6d01c3a2a Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:51:44 +0100 Subject: [PATCH 18/25] chore(assets): lower nfts deposit costs --- runtime/mainnet/src/config/assets.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 4798a5b5..5f085450 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -56,7 +56,7 @@ parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); // Accounts for `AccountBalance` max size. // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) - pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); + pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120) / 100; // Accounts for state from `Collection` + // `CollectionRoleOf` + // `CollectionConfigOf` + @@ -65,13 +65,13 @@ parameter_types! { pub const NftsCollectionDeposit: Balance = deposit(4, 294); // Accounts for `CollectionApprovals` max size. // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137) / 100; // Accounts for `Item` storage item max size. - pub const NftsItemDeposit: Balance = deposit(1, 861); + pub const NftsItemDeposit: Balance = deposit(1, 861) / 100; // Key = max(size_of(item_metadata_key), size_of(collection_metadata_key)) + Balance: 16 bytes - pub const NftsMetadataDepositBase: Balance = deposit(1, 56); + pub const NftsMetadataDepositBase: Balance = deposit(1, 56) / 100; // Accounts for key size of `Attribute`. - pub const NftsAttributeDepositBase: Balance = deposit(1, 175); + pub const NftsAttributeDepositBase: Balance = deposit(1, 175) / 100; pub const NftsDepositPerByte: Balance = deposit(0, 1); pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } @@ -113,7 +113,6 @@ mod tests { use codec::MaxEncodedLen; use frame_support::{traits::StorageInfoTrait, Blake2_128Concat, StorageHasher}; - use pop_runtime_common::MILLI_UNIT; use sp_runtime::traits::Get; use super::*; @@ -334,7 +333,8 @@ mod tests { AccountId::max_encoded_len() as u32 + Balance::max_encoded_len() as u32; // We only account for the key length as the deposit base. - assert_eq!(deposit(1, max_size - value_size), NftsAttributeDepositBase::get()); + assert_eq!(deposit(1, max_size - value_size) / 100, NftsAttributeDepositBase::get()); + println!("{:?}", NftsAttributeDepositBase::get()); } #[test] @@ -343,16 +343,17 @@ mod tests { .first() .and_then(|info| info.max_size) .unwrap_or_default(); - assert_eq!(deposit(1, max_size), NftsCollectionApprovalDeposit::get()); + assert_eq!(deposit(1, max_size) / 100, NftsCollectionApprovalDeposit::get()); } #[test] fn ensure_account_balance_deposit() { + // src: https://github.com/r0gue-io/pop-node/pull/413 let max_size = pallet_nfts::AccountBalance::::storage_info() .first() .and_then(|info| info.max_size) .unwrap_or_default(); - assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + assert_eq!(deposit(1, max_size) / 100, NftsCollectionBalanceDeposit::get()); } #[test] @@ -383,7 +384,6 @@ mod tests { max_collection_role_size + max_collection_config_size + max_collection_account_size; - println!("{:?}", deposit(4, total_collection_size)); // 4 different storage items means 4 different keys. assert_eq!(deposit(4, total_collection_size), NftsCollectionDeposit::get()); } @@ -469,7 +469,7 @@ mod tests { .first() .and_then(|info| info.max_size) .unwrap_or_default(); - assert_eq!(deposit(1, max_size), NftsItemDeposit::get()); + assert_eq!(deposit(1, max_size) / 100, NftsItemDeposit::get()); assert_eq!( TypeId::of::<::ItemDeposit>(), TypeId::of::(), @@ -528,7 +528,7 @@ mod tests { // We use max of both key sizes and add size_of(Balance) which is always written. let base_size = item_metadata_key_size.max(collection_metadata_key_size) + Balance::max_encoded_len(); - assert_eq!(NftsMetadataDepositBase::get(), deposit(1, base_size as u32)); + assert_eq!(NftsMetadataDepositBase::get(), deposit(1, base_size as u32) / 100); assert_eq!( TypeId::of::<::MetadataDepositBase>(), TypeId::of::(), From 84790c19c28da515163237138907a57d990b63f9 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 16:12:58 +0100 Subject: [PATCH 19/25] chore(assets): reduced deposit cost for AssetAccountDeposit --- runtime/mainnet/src/config/assets.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 5f085450..1daa59b1 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -18,8 +18,8 @@ pub type AssetsForceOrigin = EnsureRoot; parameter_types! { // Accounts for `Asset` max size. pub const AssetDeposit: Balance = deposit(1, 210); - // Enough to keep the balance in state. - pub const AssetAccountDeposit: Balance = deposit(1, 16); + // Enough to keep the balance in state / 100. + pub const AssetAccountDeposit: Balance = deposit(1, 16) / 100; pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); pub const AssetsStringLimit: u32 = 50; // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 18 bytes (16+1+1) @@ -135,7 +135,10 @@ mod tests { #[test] fn ensure_asset_account_deposit() { // Provide a deposit enough to keep the balance in state. - assert_eq!(deposit(1, Balance::max_encoded_len() as u32), AssetAccountDeposit::get()); + assert_eq!( + deposit(1, Balance::max_encoded_len() as u32) / 100, + AssetAccountDeposit::get() + ); assert_eq!( TypeId::of::<>::AssetAccountDeposit>(), TypeId::of::(), From b332ba105509808cde96f523e765ed43b20fef2a Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 18:55:55 +0100 Subject: [PATCH 20/25] chore(assets): use SDK's pallet_nfts --- Cargo.lock | 23 +++++++---------------- Cargo.toml | 4 ++-- runtime/mainnet/src/config/assets.rs | 28 ---------------------------- 3 files changed, 9 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6860cf4d..c38b7209 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8777,7 +8777,7 @@ dependencies = [ "log", "pallet-assets 41.0.0", "pallet-balances 40.0.0", - "pallet-nfts 31.0.0", + "pallet-nfts 33.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -10203,15 +10203,6 @@ dependencies = [ "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "pallet-nfts-runtime-api" -version = "23.0.0" -dependencies = [ - "pallet-nfts 31.0.0", - "parity-scale-codec", - "sp-api 35.0.0", -] - [[package]] name = "pallet-nfts-runtime-api" version = "25.0.0" @@ -13671,8 +13662,8 @@ dependencies = [ "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 23.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-scheduler 40.0.0", @@ -13745,8 +13736,8 @@ dependencies = [ "pallet-collator-selection 20.0.0", "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", - "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 23.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", @@ -13825,8 +13816,8 @@ dependencies = [ "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", - "pallet-nfts-runtime-api 23.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-scheduler 40.0.0", diff --git a/Cargo.toml b/Cargo.toml index e19de606..2ff17c28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,8 +68,6 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b # Local pallet-api = { path = "pallets/api", default-features = false } -pallet-nfts = { path = "pallets/nfts", default-features = false } -pallet-nfts-runtime-api = { path = "pallets/nfts/runtime-api", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } @@ -95,6 +93,8 @@ pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk", branch pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } 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 = { 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-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/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 1daa59b1..ce9bee4e 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -54,18 +54,12 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); - // Accounts for `AccountBalance` max size. - // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) - pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120) / 100; // Accounts for state from `Collection` + // `CollectionRoleOf` + // `CollectionConfigOf` + // `CollectionAccount` // Refer to `ensure_collection_deposit` test for specifics. pub const NftsCollectionDeposit: Balance = deposit(4, 294); - // Accounts for `CollectionApprovals` max size. - // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137) / 100; // Accounts for `Item` storage item max size. pub const NftsItemDeposit: Balance = deposit(1, 861) / 100; // Key = max(size_of(item_metadata_key), size_of(collection_metadata_key)) + Balance: 16 bytes @@ -79,8 +73,6 @@ parameter_types! { impl pallet_nfts::Config for Runtime { type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; - type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; - type CollectionBalanceDeposit = NftsCollectionBalanceDeposit; type CollectionDeposit = NftsCollectionDeposit; type CollectionId = CollectionId; type CreateOrigin = AsEnsureOriginWithArg>; @@ -337,26 +329,6 @@ mod tests { Balance::max_encoded_len() as u32; // We only account for the key length as the deposit base. assert_eq!(deposit(1, max_size - value_size) / 100, NftsAttributeDepositBase::get()); - println!("{:?}", NftsAttributeDepositBase::get()); - } - - #[test] - fn ensure_collection_approval_deposit() { - let max_size = pallet_nfts::CollectionApprovals::::storage_info() - .first() - .and_then(|info| info.max_size) - .unwrap_or_default(); - assert_eq!(deposit(1, max_size) / 100, NftsCollectionApprovalDeposit::get()); - } - - #[test] - fn ensure_account_balance_deposit() { - // src: https://github.com/r0gue-io/pop-node/pull/413 - let max_size = pallet_nfts::AccountBalance::::storage_info() - .first() - .and_then(|info| info.max_size) - .unwrap_or_default(); - assert_eq!(deposit(1, max_size) / 100, NftsCollectionBalanceDeposit::get()); } #[test] From 759e51ae16478465c36b618c57d466d828de934e Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:40:41 +0100 Subject: [PATCH 21/25] chore(assets): better deposits & fmt Cargo --- Cargo.lock | 6 +++--- Cargo.toml | 9 +++++---- runtime/mainnet/Cargo.toml | 10 +++++----- runtime/mainnet/src/config/assets.rs | 22 +++++++++------------- runtime/mainnet/src/lib.rs | 1 + 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c38b7209..42b1d13c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8777,7 +8777,7 @@ dependencies = [ "log", "pallet-assets 41.0.0", "pallet-balances 40.0.0", - "pallet-nfts 33.0.0", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -13662,7 +13662,7 @@ dependencies = [ "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", "pallet-nft-fractionalization", - "pallet-nfts 33.0.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api 25.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", @@ -13816,7 +13816,7 @@ dependencies = [ "pallet-message-queue 42.0.0", "pallet-multisig 39.0.0", "pallet-nft-fractionalization", - "pallet-nfts 33.0.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api 25.0.0", "pallet-preimage 39.0.0", "pallet-proxy 39.0.0", diff --git a/Cargo.toml b/Cargo.toml index 2ff17c28..4a9c4b83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,12 +68,13 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b # Local pallet-api = { path = "pallets/api", default-features = false } +pallet-nfts = { path = "pallets/nfts", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } -pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds -pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-devnet = { path = "runtime/devnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-mainnet = { path = "runtime/mainnet", default-features = true } # default-features=true required for `-p pop-node` builds +pop-runtime-testnet = { path = "runtime/testnet", default-features = true } # default-features=true required for `-p pop-node` builds # Substrate frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } @@ -93,8 +94,8 @@ pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk", branch pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false } 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 = { 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/runtime/mainnet/Cargo.toml b/runtime/mainnet/Cargo.toml index 50ac9890..eebb4a95 100644 --- a/runtime/mainnet/Cargo.toml +++ b/runtime/mainnet/Cargo.toml @@ -22,8 +22,6 @@ scale-info.workspace = true smallvec.workspace = true # Local -pallet-nfts.workspace = true -pallet-nfts-runtime-api.workspace = true pop-runtime-common = { workspace = true, default-features = false } # Substrate @@ -41,6 +39,8 @@ 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 @@ -125,7 +125,7 @@ std = [ "pallet-message-queue/std", "pallet-multisig/std", "pallet-nfts-runtime-api/std", - "pallet-nfts/std", + "pallet-nfts-sdk/std", "pallet-preimage/std", "pallet-proxy/std", "pallet-revive/std", @@ -177,7 +177,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", - "pallet-nfts/runtime-benchmarks", + "pallet-nfts-sdk/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-revive/runtime-benchmarks", @@ -214,7 +214,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", - "pallet-nfts/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/config/assets.rs b/runtime/mainnet/src/config/assets.rs index ce9bee4e..f1798abb 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -4,6 +4,7 @@ use frame_support::{ }; 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; @@ -65,7 +66,7 @@ parameter_types! { // Key = max(size_of(item_metadata_key), size_of(collection_metadata_key)) + Balance: 16 bytes pub const NftsMetadataDepositBase: Balance = deposit(1, 56) / 100; // Accounts for key size of `Attribute`. - pub const NftsAttributeDepositBase: Balance = deposit(1, 175) / 100; + pub const NftsAttributeDepositBase: Balance = deposit(1, 89) / 100; pub const NftsDepositPerByte: Balance = deposit(0, 1); pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } @@ -306,7 +307,7 @@ mod tests { } mod nfts { - use pallet_nfts::PalletFeature::*; + use pallet_nfts::{AttributeNamespace, PalletFeature::*}; use sp_runtime::{MultiSignature, MultiSigner}; use super::*; @@ -318,17 +319,12 @@ mod tests { #[test] fn ensure_attribute_deposit_base() { - // Max possible size of Attribute. - let max_size = pallet_nfts::Attribute::::storage_info() - .first() - .and_then(|info| info.max_size) - .unwrap_or_default(); - // Size of Attribute value: `(BoundedVec, AttributeDepositOf)`. - let value_size = <::ValueLimit as Get>::get() + - AccountId::max_encoded_len() as u32 + - Balance::max_encoded_len() as u32; - // We only account for the key length as the deposit base. - assert_eq!(deposit(1, max_size - value_size) / 100, NftsAttributeDepositBase::get()); + // 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!(deposit(1, key_size as u32) / 100, NftsAttributeDepositBase::get()); } #[test] diff --git a/runtime/mainnet/src/lib.rs b/runtime/mainnet/src/lib.rs index 5ef966f9..4f4e7838 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; From f10ccd8c2acc139798d28ddbd103be589bfd0081 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:51:08 +0100 Subject: [PATCH 22/25] chore(assets): better comments --- runtime/mainnet/src/config/assets.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index f1798abb..7e3dc089 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -252,7 +252,9 @@ mod tests { #[test] fn ensure_metadata_deposit_base() { - // Size doesn't include metadata name and symbol, which are accounted per byte. + // 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. let max_size = Blake2_128Concat::max_len::< >::AssetId, From 645fb3d3e3ccbd869eefd5c95399ab8012ae6a93 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Fri, 14 Feb 2025 09:36:59 +0100 Subject: [PATCH 23/25] chore(assets): more explicit comments for deposits --- runtime/mainnet/src/config/assets.rs | 34 +++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 7e3dc089..2d31662a 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -18,13 +18,15 @@ 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; - // Key = AssetId 4 bytes + Hash length 16 bytes; Value = 18 bytes (16+1+1) - // https://github.com/paritytech/polkadot-sdk/blob/7a7e016a1da297adc13f855979232e0059df258a/substrate/frame/assets/src/types.rs#L188 + // 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); } @@ -54,18 +56,19 @@ impl pallet_assets::Config for Runtime { } parameter_types! { + // All features enabled. pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); - // Accounts for state from `Collection` + - // `CollectionRoleOf` + - // `CollectionConfigOf` + - // `CollectionAccount` - // Refer to `ensure_collection_deposit` test for specifics. + // 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 `Item` storage item max size. + // 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; - // Key = max(size_of(item_metadata_key), size_of(collection_metadata_key)) + Balance: 16 bytes + // 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 key size of `Attribute`. + // 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; @@ -128,10 +131,12 @@ mod tests { #[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::(), @@ -144,6 +149,7 @@ mod tests { >::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::< @@ -256,6 +262,7 @@ mod tests { // 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() + @@ -326,6 +333,7 @@ mod tests { 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()); } @@ -357,6 +365,7 @@ mod tests { 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()); } @@ -438,10 +447,12 @@ mod tests { #[test] fn ensure_item_deposit_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>(), @@ -498,9 +509,10 @@ mod tests { 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 written. + // 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>(), From 08b33691ef206895bb367320ce7b97a5535b7702 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Fri, 14 Feb 2025 09:42:05 +0100 Subject: [PATCH 24/25] chore(assets): provide src for NftsCollectionDeposit deposit --- runtime/mainnet/src/config/assets.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 2d31662a..0d4f8b08 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -339,6 +339,9 @@ mod tests { #[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) From 098a03598ecfb78a68cd129b0284d6c4a58bbae4 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Fri, 14 Feb 2025 09:59:54 +0100 Subject: [PATCH 25/25] chore(assets): apply feedback --- runtime/mainnet/src/config/assets.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/runtime/mainnet/src/config/assets.rs b/runtime/mainnet/src/config/assets.rs index 0d4f8b08..7029206f 100644 --- a/runtime/mainnet/src/config/assets.rs +++ b/runtime/mainnet/src/config/assets.rs @@ -410,17 +410,15 @@ mod tests { } #[test] - fn all_feature_are_active() { + fn all_features_are_active() { assert_eq!( TypeId::of::<::Features>(), TypeId::of::(), ); - let features = [Trading, Attributes, Approvals, Swaps]; - - for feat in features { - assert!(::Features::get().is_enabled(feat)); - } + assert!([Trading, Attributes, Approvals, Swaps] + .iter() + .all(|feat| ::Features::get().is_enabled(*feat))); } #[test] @@ -449,7 +447,7 @@ mod tests { } #[test] - fn ensure_item_deposit_deposit() { + fn ensure_item_deposit() { // Accounts for `Item` storage item max size. let max_size = pallet_nfts::Item::::storage_info() .first()