diff --git a/Cargo.lock b/Cargo.lock index b3e31df..e554d5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2558,6 +2558,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", "pallet-utility", "pallet-xcm", "parity-scale-codec", @@ -5366,6 +5367,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", "pallet-utility", "pallet-xcm", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index 27b2953..3ffec3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ pallet-timestamp = { version = "23.0.0", default-features = false } pallet-transaction-payment = { version = "24.0.0", default-features = false } pallet-transaction-payment-rpc = { version = "26.0.0" } pallet-transaction-payment-rpc-runtime-api = { version = "24.0.0", default-features = false } +pallet-treasury = { version = "23.0.0", default-features = false} pallet-utility = { version = "24.0.0", default-features = false } sc-basic-authorship = { version = "0.30.0" } sc-chain-spec = { version = "23.0.0" } @@ -136,8 +137,5 @@ xcm = { package = "staging-xcm", version = "3.0.0", default-features = false } xcm-builder = { package = "staging-xcm-builder", version = "3.0.0", default-features = false } xcm-executor = { package = "staging-xcm-executor", version = "3.0.0", default-features = false } -# SBP-M1 review: as noted, the template used for this project is based on the `substrate-node-template` which is for building a solo chain rather than a parachain. -# SBP-M1 review: Cumulus (https://github.com/paritytech/polkadot-sdk/tree/master/cumulus) is the parachain SDK which should be used instead to build a parachain, with a starter template available at https://github.com/substrate-developer-hub/substrate-parachain-template -# SBP-M1 review: finally, the Extended Parachain Template (https://github.com/paritytech/extended-parachain-template) builds on the above and is recommended for a new parachain project. - # SBP-M1 review: add integration tests to ensure runtime functionality works as expected. Suggested tools include zombienet, parachains-integration-tests, chopsticks as applicable. +# TODO (@khssnv): zombienet added, consider parachains-integration-tests and chopsticks diff --git a/README.md b/README.md index e009122..c22ca8c 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,3 @@ -# Extended Parachain Template +# Metaquity Network -The **Extended Parachain Template** is a ready-to-use parachain template, pre-configured with the [Assets](https://paritytech.github.io/substrate/master/pallet_assets/index.html) pallet, a simple Governance system ([Collective](https://paritytech.github.io/substrate/master/pallet_collective/index.html) & [Motion](https://github.com/paritytech/extended-parachain-template/tree/main/pallets/motion) pallets), and other useful base features. - -This is a solid starting point for most Parachain projects as it is a more feature-rich alternative to the base [Substrate Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template) (which it is derived from). - -This template is maintained by the **Delivery Services** team at **Parity**. - -## Getting Started - -### Rust Setup - -First, complete the [basic Rust setup instructions](./docs/rust-setup.md). - -### Build - -Clone the extended parachain template repository: - -```sh -git clone https://github.com/paritytech/extended-parachain-template -``` - -Use the following command to build the node without launching it: - -```sh -cargo build --release -``` - -Next you will need a compatible release of [Polkadot](https://github.com/paritytech/polkadot) to run a testnet. You may also want to use [Zombienet (available for Linux and MacOS)](https://github.com/paritytech/zombienet/releases) for spinning up a testnet: - - -You can find linux and macOS executables of the Zombienet CLI here: - -https://github.com/paritytech/zombienet/releases -Download the Zombienet CLI according to your operating system. - -Tip: If you want the executable to be available system-wide then you can follow these steps (otherwise just download the executable to your working directory): -```sh -wget https://github.com/paritytech/zombienet/releases/download/v1.3.30/zombienet-macos -chmod +x zombienet-macos -cp zombienet-macos /usr/local/bin -``` -Make sure Zombienet CLI is installed correctly: -```sh -./zombienet-macos --help -``` -You should see some similar output: -```sh -Usage: zombienet [options] [command] - -Options: - -c, --spawn-concurrency Number of concurrent spawning process to launch, default is 1 - -p, --provider Override provider to use (choices: "podman", "kubernetes", "native") - -m, --monitor Start as monitor, do not auto cleanup network - -h, --help display help for command - -Commands: - spawn [creds] Spawn the network defined in the config - test [runningNetworkSpec] Run tests on the network defined - setup Setup is meant for downloading and making dev environment of Zombienet ready - version Prints zombienet version - help [command] display help for command - -``` - -### Setting up Zombienet config - -You may use a reference implementation from the folder `zombienet-config` or make your own. More instructions here: [Simulate parachains in a test network -](https://docs.substrate.io/test/simulate-parachains/) - -👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains), and -parathreads [here](https://wiki.polkadot.network/docs/learn-parathreads). - - -🧙 Learn about how to use this template and run your own parachain testnet for it in the -[Devhub Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/). \ No newline at end of file +The World's First Permissioned Blockchain Network and DeFi Protocol for Real World Assets (RWA). diff --git a/node/Cargo.toml b/node/Cargo.toml index 72258c8..afc9711 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -16,7 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] [[bin]] name = "metaquity-network" -# SBP-M1 review: consider updating dependencies to new monorepo at https://github.com/paritytech/polkadot-sdk (where applicable, and when ready to move to 1.0) [dependencies] clap = { workspace = true } color-print = { workspace = true } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index dabb658..15aecfc 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -264,6 +264,7 @@ pub mod devnet { ..Default::default() }, transaction_payment: Default::default(), + treasury: Default::default(), } } } @@ -461,6 +462,7 @@ pub mod mainnet { ..Default::default() }, transaction_payment: Default::default(), + treasury: Default::default(), } } } diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 1fd0a9f..8d28f05 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -19,9 +19,6 @@ pub type Nonce = u32; /// up by `pallet_aura` to implement `fn slot_duration()`. /// /// Change this to adjust the block time. -// SBP-M1 review: consider effects of block time increasing when migrating from solo chain to parachain (if applicable): https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/common/src/lib.rs#L22 -// SBP-M1 review: note also that `asynchronous backing` is set to reduce parachain block times to 6 -// seconds once available pub const MILLISECS_PER_BLOCK: u64 = 12000; // NOTE: Currently it is not possible to change the slot duration after the chain has started. diff --git a/runtime/devnet/Cargo.toml b/runtime/devnet/Cargo.toml index bf22f19..e2b5020 100644 --- a/runtime/devnet/Cargo.toml +++ b/runtime/devnet/Cargo.toml @@ -26,7 +26,7 @@ scale-info = { workspace = true, default-features = false, features = [ smallvec = { workspace = true } # Local -runtime-common = { path = "../common", default-features = false } +runtime-common = { workspace = true, default-features = false } # Substrate frame-benchmarking = { workspace = true, default-features = false, optional = true } @@ -52,6 +52,7 @@ pallet-sudo = { workspace = true, default-features = false } pallet-timestamp = { workspace = true, default-features = false } pallet-transaction-payment = { workspace = true, default-features = false } pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = false } +pallet-treasury = { workspace = true, default-features = false } pallet-utility = { workspace = true, default-features = false } sp-api = { workspace = true, default-features = false } sp-block-builder = { workspace = true, default-features = false } @@ -123,6 +124,7 @@ std = [ "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", + "pallet-treasury/std", "pallet-utility/std", "pallet-xcm/std", "parachain-info/std", @@ -167,6 +169,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -198,6 +201,7 @@ try-runtime = [ "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", + "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 6c73107..c6c5cef 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -11,7 +11,6 @@ pub mod xcm_config; pub use fee::WeightToFee; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use sp_api::impl_runtime_apis; use sp_core::{ConstBool, OpaqueMetadata}; use sp_inherents::InherentData; @@ -32,7 +31,7 @@ use frame_support::{ dispatch::DispatchClass, parameter_types, traits::{ - fungible::HoldConsideration, AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, + fungible::HoldConsideration, AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, LinearStoragePrice, }, weights::{ConstantMultiplier, Weight}, @@ -40,7 +39,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, + EnsureRoot, EnsureSigned, EnsureWithSuccess, }; use pallet_nfts::PalletFeatures; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; @@ -49,7 +48,7 @@ pub use runtime_common::{ NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; +pub use sp_runtime::{MultiAddress, Perbill, Percent, Permill}; use xcm_config::{RelayLocation, XcmConfig, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] @@ -221,17 +220,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { pub const MICROMQTY: Balance = 1_000_000_000_000; pub const MILLIMQTY: Balance = 1_000 * MICROMQTY; -// SBP-M1 review: is 14 decimal places intentional? 18 is specified at https://github.com/paritytech/ss58-registry/blob/main/ss58-registry.json#L882. Suggest setting UNITS/DOLLARS/MQTY to 18 decimal value and then divide accordingly for sub-units for clarity. Consider adding additional metadata in the chain_spec.rs as well - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/node/src/chain_spec.rs#L136 pub const MQTY: Balance = 1_000 * MILLIMQTY; -// SBP-M1 review: very small number for ED, especially for a chain with 18 decimals. Update to some fraction of a UNIT - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L220 -// SBP-M1 review: see https://wiki.polkadot.network/docs/build-protocol-info#existential-deposit for more information pub const EXISTENTIAL_DEPOSIT: Balance = MILLIMQTY; pub const fn deposit(items: u32, bytes: u32) -> Balance { - // SBP-M1 review: implementation may increase likelihood of chain storage bloat by returning a - // relatively small value for a deposit, based on the number of decimals currently used on the - // chain. SBP-M1 review: typical implementations include an additional multiplier. See deposit function implementations within runtimes at https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/runtime and https://github.com/paritytech/extended-parachain-template/blob/main/runtime/mainnet/src/lib.rs#L223 as examples. (items as Balance * 20 * MQTY + (bytes as Balance) * 100 * MICROMQTY) / 100 } @@ -274,7 +267,6 @@ parameter_types! { // Configure FRAME pallets to include in runtime. -// SBP-M1 review: consider matching member order with that of trait impl frame_system::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; @@ -322,7 +314,6 @@ impl frame_system::Config for Runtime { /// The action to take on a Runtime Upgrade type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; /// The maximum number of consumers allowed on a single account. - // SBP-M1 review: unnecessary qualification type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -347,7 +338,6 @@ parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; } -// SBP-M1 review: consider matching member order with that of trait impl pallet_balances::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; @@ -362,47 +352,35 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxLocks = ConstU32<50>; type MaxReserves = ConstU32<50>; - // SBP-M1 review: add comment noting why this is set to one - i.e. - // HoldReason::NftFractionalization - type MaxHolds = ConstU32<1>; + type MaxHolds = ConstU32<1>; // HoldReason::NftFractionalization type MaxFreezes = ConstU32<0>; } parameter_types! { - // SBP-M1 review: re-consider value after adjusting units mentioned above. pub const AssetDeposit: Balance = 10 * MQTY; - pub const AssetAccountDeposit: Balance = deposit(1, 16); - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const StringLimit: u32 = 50; - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const MetadataDepositBase: Balance = deposit(1, 68); - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const MetadataDepositPerByte: Balance = deposit(0, 1); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // SBP-M1 review: reuse Balance type rather than explicit u128? type Balance = Balance; - // SBP-M1 review: use separator for consistency - i.e. 1_000 - type RemoveItemsLimit = ConstU32<1000>; + type RemoveItemsLimit = ConstU32<1_000>; type AssetId = u32; type AssetIdParameter = parity_scale_codec::Compact; type Currency = Balances; // SBP-M1 review: consider whether anyone should be able to permissionlessly create an asset - // should probably be set to MQTY admin origin only. + // TODO (@khssnv): consider Asset originator or Verifier origin only type CreateOrigin = AsEnsureOriginWithArg>; // SBP-M1 review: may need to be root or MQTY admin origin to allow force_set_metadata for // fractionalised assets - see EitherOf. + // TODO (@khssnv): consider Verifier origin type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; - // SBP-M1 review: re-consider this after adjusting the units mentioned above - type AssetAccountDeposit = AssetAccountDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; + type AssetAccountDeposit = ConstU128<{ deposit(1, 16) }>; + type MetadataDepositBase = ConstU128<{ deposit(1, 68) }>; + type MetadataDepositPerByte = ConstU128<{ deposit(0, 1) }>; + type ApprovalDeposit = ConstU128; type StringLimit = StringLimit; type Freezer = (); type Extra = (); @@ -419,16 +397,11 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // SBP-M1 review: consider a mechanism for dealing with transaction fees - e.g. DealWithFees type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter>; type OperationalFeeMultiplier = ConstU8<5>; - // SBP-M1 review: consider non-default weight to fee mechanisms - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L126 type WeightToFee = WeightToFee; - // SBP-M1 review: consider non-default length to fee mechanisms type LengthToFee = ConstantMultiplier; - // SBP-M1 review: consider non-default fee multiplier update mechanisms - e.g. - // SlowAdjustingFeeUpdate type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; } @@ -594,7 +567,6 @@ impl pallet_preimage::Config for Runtime { >; } -// SBP-M1 review: consider matching member order with that of trait impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type MaxAuthorities = ConstU32<100_000>; @@ -634,173 +606,143 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = (); } -parameter_types! { - // Minimum 100bytes - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const BasicDeposit: Balance = 10 * MQTY; //258 bytes on-chain - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const FieldDeposit: Balance = 2 * MQTY; //66 bytes on-chain - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const SubAccountDeposit: Balance = 2 * MQTY; // 53 bytes on-chain - pub const MaxAdditionalFields: u32 = 100; - pub const MaxSubAccounts: u32 = 100; - pub const MaxRegistrars: u32= 20; -} - impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; - type MaxRegistrars = MaxRegistrars; - // SBP-M1 review: consider what happens with slashed funds - e.g. treasury - type Slashed = (); - // SBP-M1 review: should be EnsureRoot - type ForceOrigin = EnsureSigned; + type BasicDeposit = ConstU128<{ deposit(1, 258) }>; + type FieldDeposit = ConstU128<{ deposit(0, 66) }>; + type SubAccountDeposit = ConstU128<{ deposit(1, 53) }>; + type MaxSubAccounts = ConstU32<100>; + type MaxAdditionalFields = ConstU32<100>; + type MaxRegistrars = ConstU32<20>; + type Slashed = Treasury; + type ForceOrigin = EnsureRoot; // SBP-M1 review: should be EnsureRoot or MQTY admin origin to maintain registrar integrity - type RegistrarOrigin = EnsureSigned; + // TODO (@khssnv): consider Verifier origin + type RegistrarOrigin = EnsureRoot; type WeightInfo = (); } -// SBP-M1 review: pallet_uniques is not used, so these parameters can be removed, with values moved -// to Nfts* parameter types -parameter_types! { - // SBP-M1 review: UNITS is 1, resulting in deposit of zero. This needs to be fixed. - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesCollectionDeposit: Balance = MQTY / 10; - // SBP-M1 review: UNITS is 1, resulting in deposit of zero. This needs to be fixed. - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesItemDeposit: Balance = MQTY / 1_000; - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - // SBP-M1 review: provide justification as to how 129 is determined. I do see that it is configured this way on Asset Hub on Polkadot/Kusama though. - pub const UniquesMetadataDepositsBase: Balance = deposit(1, 129); - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - // SBP-M1 review: provide justification as to how 129 is determined. Asset Hub on Polkadot/Kusama has this configured as deposit(1, 0). - pub const UniquesAttributeDepositsBase: Balance = deposit(1, 129); - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesDepositPerByte: Balance = deposit(0, 1); -} - parameter_types! { - pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); - // SBP-M1 review: only used once, inline value via ConstU32 to remove this parameter - pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; - - // SBP-M1 review: typo - // reuse the unique deopsits - // SBP-M1 review: move impls from above for each of the following to eliminate Uniques* parameter types above - pub const NftsCollectionDeposit: Balance = UniquesCollectionDeposit::get(); - pub const NftsItemDeposit: Balance = UniquesItemDeposit::get(); - pub const NftsMetadataDepositsBase: Balance = UniquesMetadataDepositsBase::get(); - pub const NftsAttributeDepositsBase: Balance = UniquesAttributeDepositsBase::get(); - pub const NftsDepositPerByte: Balance = UniquesDepositPerByte::get(); + pub Features: PalletFeatures = PalletFeatures::all_enabled(); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_nfts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; - // SBP-M1 review: consider whether any user with access to public chain should be able to - // permissionlessly create collections, which is currently the case here. The use-case/UI - // screenshots imply that asset verification is required, so assume the onchain creation of - // collections should only be carried out by MQTY admin (e.g. configure CreateOrigin as MQTY - // admin) and then assets (NFTs) minted by the collection admin once verified. SBP-M1 review: - // unnecessary qualification (frame_system::) - type CreateOrigin = AsEnsureOriginWithArg>; - // SBP-M1 review: unnecessary qualification (frame_system::) - type ForceOrigin = frame_system::EnsureRoot; - type Locker = (); - type CollectionDeposit = NftsCollectionDeposit; - type ItemDeposit = NftsItemDeposit; - type MetadataDepositBase = NftsMetadataDepositsBase; - type AttributeDepositBase = NftsAttributeDepositsBase; - type DepositPerByte = NftsDepositPerByte; - type StringLimit = ConstU32<50>; - type KeyLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; - type ApprovalsLimit = ConstU32<10>; - type ItemAttributesApprovalsLimit = ConstU32<2>; + type ForceOrigin = EnsureRoot; + type CollectionDeposit = ConstU128<{ 100 * MQTY }>; + type ItemDeposit = ConstU128<{ 1 * MQTY }>; + // SBP-M1 review: provide justification as to how 10 is determined. + // TODO (@khssnv): reconsider + type MetadataDepositBase = ConstU128<{ 10 * MQTY }>; + // SBP-M1 review: provide justification as to how 10 is determined. + // TODO (@khssnv): reconsider + type AttributeDepositBase = ConstU128<{ 10 * MQTY }>; + type DepositPerByte = ConstU128<{ deposit(0, 1) }>; + type StringLimit = ConstU32<256>; + type KeyLimit = ConstU32<64>; + type ValueLimit = ConstU32<256>; + type ApprovalsLimit = ConstU32<20>; + type ItemAttributesApprovalsLimit = ConstU32<20>; type MaxTips = ConstU32<10>; - type MaxDeadlineDuration = NftsMaxDeadlineDuration; - type MaxAttributesPerCall = ConstU32<2>; - type Features = NftsPalletFeatures; - /// Off-chain = signature On-chain - therefore no conversion needed. - /// It needs to be From for benchmarking. + type MaxDeadlineDuration = ConstU32<{ 12 * 30 * DAYS }>; + type MaxAttributesPerCall = ConstU32<10>; + type Features = Features; type OffchainSignature = Signature; type OffchainPublic = ::Signer; type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); -} - -/// A reason for placing a hold on funds. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - MaxEncodedLen, - Debug, - scale_info::TypeInfo, -)] -pub enum HoldReason { - /// Used by the NFT Fractionalization Pallet. - NftFractionalization, + // SBP-M1 review: consider whether any user with access to public chain should be able to + // permissionlessly create collections, which is currently the case here. The use-case/UI + // screenshots imply that asset verification is required, so assume the onchain creation of + // collections should only be carried out by MQTY admin (e.g. configure CreateOrigin as MQTY + // admin) and then assets (NFTs) minted by the collection admin once verified. + // TODO (@khssnv): consider Asset originator or Verifier origin only + type CreateOrigin = AsEnsureOriginWithArg>; + type Locker = (); } parameter_types! { pub const NftFractionalizationPalletId: PalletId = PalletId(*b"fraction"); - // SBP-M1 review: consider BoundedVec::unchecked_from() or use .expect("reason") rather than .unwrap(). I see the Asset Hub on Kusama is configured this way though. - pub NewAssetSymbol: BoundedVec = (*b"FRAC").to_vec().try_into().unwrap(); + pub FractionalizedAssetSymbol: BoundedVec = (*b"FRAC").to_vec().try_into().expect("bad nft-fractionalization asset symbol"); // SBP-M1 review: consider something more informative like 'Fractionalized Asset'. May not matter though, as it will probably require an assets::force_set_metadata to customise the fractionalized asset metadata after the NFT has been fractionalized. - pub NewAssetName: BoundedVec = (*b"Frac").to_vec().try_into().unwrap(); + // TODO (@khssnv) + pub FractionalizedAssetName: BoundedVec = (*b"Frac").to_vec().try_into().expect("bad nft-fractionalization asset name"); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_nft_fractionalization::Config for Runtime { - // SBP-M1 review: whilst it resolves to the same type, consider using ::Balance as it would better align with AssetId and Assets type - // definitions below. I see the Asset Hub on Kusama is configured this way though. - type AssetBalance = ::Balance; - type AssetId = ::AssetId; - type Assets = Assets; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; // SBP-M1 review: uses AssetDeposit rather than NftsCollectionDeposit and cannot determine // whether this is intentional. I see the Asset Hub on Kusama is configured this way though. // Suggest adding NftFractionalizationDeposit alias to AssetDeposit or NftsCollectionDeposit // with a comment as to why it is being used in your runtime for clarity. + // TODO (@khssnv): reconsider type Deposit = AssetDeposit; - type NewAssetName = NewAssetName; - type NewAssetSymbol = NewAssetSymbol; type NftCollectionId = ::CollectionId; type NftId = ::ItemId; + type AssetBalance = ::Balance; + type AssetId = ::AssetId; + type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = RuntimeHoldReason; + type NewAssetSymbol = FractionalizedAssetSymbol; + type NewAssetName = FractionalizedAssetName; type StringLimit = StringLimit; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); + type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 1 * MQTY; + pub const SpendPeriod: BlockNumber = 1 * DAYS; + pub const Burn: Permill = Permill::from_percent(50); + pub const TipCountdown: BlockNumber = 1 * DAYS; + pub const TipFindersFee: Percent = Percent::from_percent(20); + pub const TipReportDepositBase: Balance = 1 * MQTY; + pub const DataDepositPerByte: Balance = deposit(0, 1); + pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const MaximumReasonLength: u32 = 300; + pub const MaxApprovals: u32 = 100; + pub const MaxBalance: Balance = Balance::max_value(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type RuntimeEvent = RuntimeEvent; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = (); + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = (); + type WeightInfo = pallet_treasury::weights::SubstrateWeight; + type MaxApprovals = MaxApprovals; + type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; } // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub struct Runtime { // System support stuff. - // SBP-M1 review: explicit pallet indices preferred - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L564 System: frame_system = 0, ParachainSystem: cumulus_pallet_parachain_system = 1, Timestamp: pallet_timestamp = 2, @@ -816,6 +758,7 @@ construct_runtime!( Balances: pallet_balances = 10, TransactionPayment: pallet_transaction_payment = 11, Assets: pallet_assets = 12, + Treasury: pallet_treasury = 13, // Governance Sudo: pallet_sudo = 15, @@ -855,8 +798,12 @@ mod benches { [pallet_collator_selection, CollatorSelection] [pallet_multisig, Multisig] [pallet_preimage, Preimage] + [pallet_utility, Utility] + [pallet_nfts, Nfts] + [pallet_nft_fractionalization, NftFractionalization] [cumulus_pallet_xcmp_queue, XcmpQueue] // SBP-M1 review: add missing pallets: benchmarks should be re-run on reference hardware based on how they are configured/used by your runtime + // TODO (@khssnv): consider reference hardware and re-run benchmarks ); } diff --git a/runtime/mainnet/Cargo.toml b/runtime/mainnet/Cargo.toml index 2829a30..3a4e949 100644 --- a/runtime/mainnet/Cargo.toml +++ b/runtime/mainnet/Cargo.toml @@ -52,6 +52,7 @@ pallet-sudo = { workspace = true, default-features = false } pallet-timestamp = { workspace = true, default-features = false } pallet-transaction-payment = { workspace = true, default-features = false } pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = false } +pallet-treasury = { workspace = true, default-features = false } pallet-utility = { workspace = true, default-features = false } sp-api = { workspace = true, default-features = false } sp-block-builder = { workspace = true, default-features = false } @@ -116,12 +117,14 @@ std = [ "pallet-multisig/std", "pallet-nft-fractionalization/std", "pallet-nfts/std", + "pallet-preimage/std", "pallet-scheduler/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", + "pallet-treasury/std", "pallet-utility/std", "pallet-xcm/std", "parachain-info/std", @@ -166,6 +169,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -197,6 +201,7 @@ try-runtime = [ "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", + "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", diff --git a/runtime/mainnet/src/lib.rs b/runtime/mainnet/src/lib.rs index 920130e..31ff6be 100644 --- a/runtime/mainnet/src/lib.rs +++ b/runtime/mainnet/src/lib.rs @@ -11,7 +11,6 @@ pub mod xcm_config; pub use fee::WeightToFee; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use sp_api::impl_runtime_apis; use sp_core::{ConstBool, OpaqueMetadata}; use sp_inherents::InherentData; @@ -32,7 +31,7 @@ use frame_support::{ dispatch::DispatchClass, parameter_types, traits::{ - fungible::HoldConsideration, AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, + fungible::HoldConsideration, AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, LinearStoragePrice, }, weights::{ConstantMultiplier, Weight}, @@ -40,7 +39,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, + EnsureRoot, EnsureSigned, EnsureWithSuccess, }; use pallet_nfts::PalletFeatures; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; @@ -49,7 +48,7 @@ pub use runtime_common::{ NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; +pub use sp_runtime::{MultiAddress, Perbill, Percent, Permill}; use xcm_config::{RelayLocation, XcmConfig, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] @@ -221,17 +220,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { pub const MICROMQTY: Balance = 1_000_000_000_000; pub const MILLIMQTY: Balance = 1_000 * MICROMQTY; -// SBP-M1 review: is 14 decimal places intentional? 18 is specified at https://github.com/paritytech/ss58-registry/blob/main/ss58-registry.json#L882. Suggest setting UNITS/DOLLARS/MQTY to 18 decimal value and then divide accordingly for sub-units for clarity. Consider adding additional metadata in the chain_spec.rs as well - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/node/src/chain_spec.rs#L136 pub const MQTY: Balance = 1_000 * MILLIMQTY; -// SBP-M1 review: very small number for ED, especially for a chain with 18 decimals. Update to some fraction of a UNIT - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L220 -// SBP-M1 review: see https://wiki.polkadot.network/docs/build-protocol-info#existential-deposit for more information pub const EXISTENTIAL_DEPOSIT: Balance = MILLIMQTY; pub const fn deposit(items: u32, bytes: u32) -> Balance { - // SBP-M1 review: implementation may increase likelihood of chain storage bloat by returning a - // relatively small value for a deposit, based on the number of decimals currently used on the - // chain. SBP-M1 review: typical implementations include an additional multiplier. See deposit function implementations within runtimes at https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/runtime and https://github.com/paritytech/extended-parachain-template/blob/main/runtime/mainnet/src/lib.rs#L223 as examples. (items as Balance * 20 * MQTY + (bytes as Balance) * 100 * MICROMQTY) / 100 } @@ -274,7 +267,6 @@ parameter_types! { // Configure FRAME pallets to include in runtime. -// SBP-M1 review: consider matching member order with that of trait impl frame_system::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; @@ -322,7 +314,6 @@ impl frame_system::Config for Runtime { /// The action to take on a Runtime Upgrade type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; /// The maximum number of consumers allowed on a single account. - // SBP-M1 review: unnecessary qualification type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -347,7 +338,6 @@ parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; } -// SBP-M1 review: consider matching member order with that of trait impl pallet_balances::Config for Runtime { /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; @@ -362,47 +352,35 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = (); type MaxLocks = ConstU32<50>; type MaxReserves = ConstU32<50>; - // SBP-M1 review: add comment noting why this is set to one - i.e. - // HoldReason::NftFractionalization - type MaxHolds = ConstU32<1>; + type MaxHolds = ConstU32<1>; // HoldReason::NftFractionalization type MaxFreezes = ConstU32<0>; } parameter_types! { - // SBP-M1 review: re-consider value after adjusting units mentioned above. pub const AssetDeposit: Balance = 10 * MQTY; - pub const AssetAccountDeposit: Balance = deposit(1, 16); - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const StringLimit: u32 = 50; - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const MetadataDepositBase: Balance = deposit(1, 68); - // SBP-M1 review: prefer inlining if type only used once - e.g. ConstU128. Also re-consider value after adjusting units mentioned above. - pub const MetadataDepositPerByte: Balance = deposit(0, 1); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // SBP-M1 review: reuse Balance type rather than explicit u128? type Balance = Balance; - // SBP-M1 review: use separator for consistency - i.e. 1_000 - type RemoveItemsLimit = ConstU32<1000>; + type RemoveItemsLimit = ConstU32<1_000>; type AssetId = u32; type AssetIdParameter = parity_scale_codec::Compact; type Currency = Balances; // SBP-M1 review: consider whether anyone should be able to permissionlessly create an asset - // should probably be set to MQTY admin origin only. + // TODO (@khssnv): consider Asset originator or Verifier origin only type CreateOrigin = AsEnsureOriginWithArg>; // SBP-M1 review: may need to be root or MQTY admin origin to allow force_set_metadata for // fractionalised assets - see EitherOf. + // TODO (@khssnv): consider Verifier origin type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; - // SBP-M1 review: re-consider this after adjusting the units mentioned above - type AssetAccountDeposit = AssetAccountDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; + type AssetAccountDeposit = ConstU128<{ deposit(1, 16) }>; + type MetadataDepositBase = ConstU128<{ deposit(1, 68) }>; + type MetadataDepositPerByte = ConstU128<{ deposit(0, 1) }>; + type ApprovalDeposit = ConstU128; type StringLimit = StringLimit; type Freezer = (); type Extra = (); @@ -419,16 +397,11 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // SBP-M1 review: consider a mechanism for dealing with transaction fees - e.g. DealWithFees type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter>; type OperationalFeeMultiplier = ConstU8<5>; - // SBP-M1 review: consider non-default weight to fee mechanisms - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L126 type WeightToFee = WeightToFee; - // SBP-M1 review: consider non-default length to fee mechanisms type LengthToFee = ConstantMultiplier; - // SBP-M1 review: consider non-default fee multiplier update mechanisms - e.g. - // SlowAdjustingFeeUpdate type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; } @@ -594,7 +567,6 @@ impl pallet_preimage::Config for Runtime { >; } -// SBP-M1 review: consider matching member order with that of trait impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type MaxAuthorities = ConstU32<100_000>; @@ -634,173 +606,143 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = (); } -parameter_types! { - // Minimum 100bytes - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const BasicDeposit: Balance = 10 * MQTY; //258 bytes on-chain - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const FieldDeposit: Balance = 2 * MQTY; //66 bytes on-chain - // SBP-M1 review: consider using deposit() function for consistency with other pallets deposits (and as per Polkadot runtime). - // @khssnv: ToDo: adjust - pub const SubAccountDeposit: Balance = 2 * MQTY; // 53 bytes on-chain - pub const MaxAdditionalFields: u32 = 100; - pub const MaxSubAccounts: u32 = 100; - pub const MaxRegistrars: u32= 20; -} - impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; - type MaxRegistrars = MaxRegistrars; - // SBP-M1 review: consider what happens with slashed funds - e.g. treasury - type Slashed = (); - // SBP-M1 review: should be EnsureRoot - type ForceOrigin = EnsureSigned; + type BasicDeposit = ConstU128<{ deposit(1, 258) }>; + type FieldDeposit = ConstU128<{ deposit(0, 66) }>; + type SubAccountDeposit = ConstU128<{ deposit(1, 53) }>; + type MaxSubAccounts = ConstU32<100>; + type MaxAdditionalFields = ConstU32<100>; + type MaxRegistrars = ConstU32<20>; + type Slashed = Treasury; + type ForceOrigin = EnsureRoot; // SBP-M1 review: should be EnsureRoot or MQTY admin origin to maintain registrar integrity - type RegistrarOrigin = EnsureSigned; + // TODO (@khssnv): consider Verifier origin + type RegistrarOrigin = EnsureRoot; type WeightInfo = (); } -// SBP-M1 review: pallet_uniques is not used, so these parameters can be removed, with values moved -// to Nfts* parameter types -parameter_types! { - // SBP-M1 review: UNITS is 1, resulting in deposit of zero. This needs to be fixed. - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesCollectionDeposit: Balance = MQTY / 10; - // SBP-M1 review: UNITS is 1, resulting in deposit of zero. This needs to be fixed. - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesItemDeposit: Balance = MQTY / 1_000; - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - // SBP-M1 review: provide justification as to how 129 is determined. I do see that it is configured this way on Asset Hub on Polkadot/Kusama though. - pub const UniquesMetadataDepositsBase: Balance = deposit(1, 129); - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - // SBP-M1 review: provide justification as to how 129 is determined. Asset Hub on Polkadot/Kusama has this configured as deposit(1, 0). - pub const UniquesAttributeDepositsBase: Balance = deposit(1, 129); - // SBP-M1 review: only used once, move implementation to usage to remove this parameter - pub const UniquesDepositPerByte: Balance = deposit(0, 1); -} - parameter_types! { - pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); - // SBP-M1 review: only used once, inline value via ConstU32 to remove this parameter - pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; - - // SBP-M1 review: typo - // reuse the unique deopsits - // SBP-M1 review: move impls from above for each of the following to eliminate Uniques* parameter types above - pub const NftsCollectionDeposit: Balance = UniquesCollectionDeposit::get(); - pub const NftsItemDeposit: Balance = UniquesItemDeposit::get(); - pub const NftsMetadataDepositsBase: Balance = UniquesMetadataDepositsBase::get(); - pub const NftsAttributeDepositsBase: Balance = UniquesAttributeDepositsBase::get(); - pub const NftsDepositPerByte: Balance = UniquesDepositPerByte::get(); + pub Features: PalletFeatures = PalletFeatures::all_enabled(); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_nfts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; - // SBP-M1 review: consider whether any user with access to public chain should be able to - // permissionlessly create collections, which is currently the case here. The use-case/UI - // screenshots imply that asset verification is required, so assume the onchain creation of - // collections should only be carried out by MQTY admin (e.g. configure CreateOrigin as MQTY - // admin) and then assets (NFTs) minted by the collection admin once verified. SBP-M1 review: - // unnecessary qualification (frame_system::) - type CreateOrigin = AsEnsureOriginWithArg>; - // SBP-M1 review: unnecessary qualification (frame_system::) - type ForceOrigin = frame_system::EnsureRoot; - type Locker = (); - type CollectionDeposit = NftsCollectionDeposit; - type ItemDeposit = NftsItemDeposit; - type MetadataDepositBase = NftsMetadataDepositsBase; - type AttributeDepositBase = NftsAttributeDepositsBase; - type DepositPerByte = NftsDepositPerByte; - type StringLimit = ConstU32<50>; - type KeyLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; - type ApprovalsLimit = ConstU32<10>; - type ItemAttributesApprovalsLimit = ConstU32<2>; + type ForceOrigin = EnsureRoot; + type CollectionDeposit = ConstU128<{ 100 * MQTY }>; + type ItemDeposit = ConstU128<{ 1 * MQTY }>; + // SBP-M1 review: provide justification as to how 10 is determined. + // TODO (@khssnv): reconsider + type MetadataDepositBase = ConstU128<{ 10 * MQTY }>; + // SBP-M1 review: provide justification as to how 10 is determined. + // TODO (@khssnv): reconsider + type AttributeDepositBase = ConstU128<{ 10 * MQTY }>; + type DepositPerByte = ConstU128<{ deposit(0, 1) }>; + type StringLimit = ConstU32<256>; + type KeyLimit = ConstU32<64>; + type ValueLimit = ConstU32<256>; + type ApprovalsLimit = ConstU32<20>; + type ItemAttributesApprovalsLimit = ConstU32<20>; type MaxTips = ConstU32<10>; - type MaxDeadlineDuration = NftsMaxDeadlineDuration; - type MaxAttributesPerCall = ConstU32<2>; - type Features = NftsPalletFeatures; - /// Off-chain = signature On-chain - therefore no conversion needed. - /// It needs to be From for benchmarking. + type MaxDeadlineDuration = ConstU32<{ 12 * 30 * DAYS }>; + type MaxAttributesPerCall = ConstU32<10>; + type Features = Features; type OffchainSignature = Signature; type OffchainPublic = ::Signer; type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); -} - -/// A reason for placing a hold on funds. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - MaxEncodedLen, - Debug, - scale_info::TypeInfo, -)] -pub enum HoldReason { - /// Used by the NFT Fractionalization Pallet. - NftFractionalization, + // SBP-M1 review: consider whether any user with access to public chain should be able to + // permissionlessly create collections, which is currently the case here. The use-case/UI + // screenshots imply that asset verification is required, so assume the onchain creation of + // collections should only be carried out by MQTY admin (e.g. configure CreateOrigin as MQTY + // admin) and then assets (NFTs) minted by the collection admin once verified. + // TODO (@khssnv): consider Asset originator or Verifier origin only + type CreateOrigin = AsEnsureOriginWithArg>; + type Locker = (); } parameter_types! { pub const NftFractionalizationPalletId: PalletId = PalletId(*b"fraction"); - // SBP-M1 review: consider BoundedVec::unchecked_from() or use .expect("reason") rather than .unwrap(). I see the Asset Hub on Kusama is configured this way though. - pub NewAssetSymbol: BoundedVec = (*b"FRAC").to_vec().try_into().unwrap(); + pub FractionalizedAssetSymbol: BoundedVec = (*b"FRAC").to_vec().try_into().expect("bad nft-fractionalization asset symbol"); // SBP-M1 review: consider something more informative like 'Fractionalized Asset'. May not matter though, as it will probably require an assets::force_set_metadata to customise the fractionalized asset metadata after the NFT has been fractionalized. - pub NewAssetName: BoundedVec = (*b"Frac").to_vec().try_into().unwrap(); + // TODO (@khssnv) + pub FractionalizedAssetName: BoundedVec = (*b"Frac").to_vec().try_into().expect("bad nft-fractionalization asset name"); } -// SBP-M1 review: consider matching member order with that of trait impl pallet_nft_fractionalization::Config for Runtime { - // SBP-M1 review: whilst it resolves to the same type, consider using ::Balance as it would better align with AssetId and Assets type - // definitions below. I see the Asset Hub on Kusama is configured this way though. - type AssetBalance = ::Balance; - type AssetId = ::AssetId; - type Assets = Assets; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; // SBP-M1 review: uses AssetDeposit rather than NftsCollectionDeposit and cannot determine // whether this is intentional. I see the Asset Hub on Kusama is configured this way though. // Suggest adding NftFractionalizationDeposit alias to AssetDeposit or NftsCollectionDeposit // with a comment as to why it is being used in your runtime for clarity. + // TODO (@khssnv): reconsider type Deposit = AssetDeposit; - type NewAssetName = NewAssetName; - type NewAssetSymbol = NewAssetSymbol; type NftCollectionId = ::CollectionId; type NftId = ::ItemId; + type AssetBalance = ::Balance; + type AssetId = ::AssetId; + type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = RuntimeHoldReason; + type NewAssetSymbol = FractionalizedAssetSymbol; + type NewAssetName = FractionalizedAssetName; type StringLimit = StringLimit; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); + type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 1 * MQTY; + pub const SpendPeriod: BlockNumber = 1 * DAYS; + pub const Burn: Permill = Permill::from_percent(50); + pub const TipCountdown: BlockNumber = 1 * DAYS; + pub const TipFindersFee: Percent = Percent::from_percent(20); + pub const TipReportDepositBase: Balance = 1 * MQTY; + pub const DataDepositPerByte: Balance = deposit(0, 1); + pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const MaximumReasonLength: u32 = 300; + pub const MaxApprovals: u32 = 100; + pub const MaxBalance: Balance = Balance::max_value(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type RuntimeEvent = RuntimeEvent; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = (); + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = (); + type WeightInfo = pallet_treasury::weights::SubstrateWeight; + type MaxApprovals = MaxApprovals; + type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; } // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub struct Runtime { // System support stuff. - // SBP-M1 review: explicit pallet indices preferred - e.g. https://github.com/paritytech/extended-parachain-template/blob/3bec37d7844880d13e0a1f3253d1402500f83789/runtime/mainnet/src/lib.rs#L564 System: frame_system = 0, ParachainSystem: cumulus_pallet_parachain_system = 1, Timestamp: pallet_timestamp = 2, @@ -816,6 +758,7 @@ construct_runtime!( Balances: pallet_balances = 10, TransactionPayment: pallet_transaction_payment = 11, Assets: pallet_assets = 12, + Treasury: pallet_treasury = 13, // Governance Sudo: pallet_sudo = 15, @@ -852,11 +795,16 @@ mod benches { [pallet_session, SessionBench::] [pallet_scheduler, Scheduler] [pallet_timestamp, Timestamp] + [pallet_treasury, Treasury] [pallet_collator_selection, CollatorSelection] [pallet_multisig, Multisig] [pallet_preimage, Preimage] + [pallet_utility, Utility] + [pallet_nfts, Nfts] + [pallet_nft_fractionalization, NftFractionalization] [cumulus_pallet_xcmp_queue, XcmpQueue] // SBP-M1 review: add missing pallets: benchmarks should be re-run on reference hardware based on how they are configured/used by your runtime + // TODO (@khssnv): consider reference hardware and re-run benchmarks ); }