difftreelog
feat add financial council
in: master
8 files changed
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Foreign Assets18//!19//! ## Overview20//!21//! The Foreign Assets is a proxy that maps XCM operations to the Unique Network's pallets logic.2223#![cfg_attr(not(feature = "std"), no_std)]24#![allow(clippy::unused_unit)]2526use core::ops::Deref;2728use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};29use frame_system::pallet_prelude::*;30use pallet_common::{31 dispatch::CollectionDispatch, erc::CrossAccountId, XcmExtensions, NATIVE_FUNGIBLE_COLLECTION_ID,32};33use sp_runtime::traits::AccountIdConversion;34use sp_std::{boxed::Box, vec, vec::Vec};35use staging_xcm::{v4::prelude::*, VersionedAssetId};36use staging_xcm_executor::{37 traits::{ConvertLocation, Error as XcmExecutorError, TransactAsset, WeightTrader},38 AssetsInHolding,39};40use up_data_structs::{41 budget::ZeroBudget, CollectionId, CollectionMode, CollectionName, CollectionTokenPrefix,42 CreateCollectionData, CreateFungibleData, CreateItemData, TokenId,43};4445pub mod weights;4647#[cfg(feature = "runtime-benchmarks")]48mod benchmarking;4950pub use module::*;51pub use weights::WeightInfo;5253#[frame_support::pallet]54pub mod module {55 use pallet_common::CollectionIssuer;56 use up_data_structs::CollectionDescription;5758 use super::*;5960 #[pallet::config]61 pub trait Config:62 frame_system::Config63 + pallet_common::Config64 + pallet_fungible::Config65 + pallet_balances::Config66 {67 /// The overarching event type.68 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;6970 /// Origin for force registering of a foreign asset.71 type ForceRegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;7273 /// The ID of the foreign assets pallet.74 type PalletId: Get<PalletId>;7576 /// Self-location of this parachain.77 type SelfLocation: Get<Location>;7879 /// The converter from a Location to a CrossAccountId.80 type LocationToAccountId: ConvertLocation<Self::CrossAccountId>;8182 /// Weight information for the extrinsics in this module.83 type WeightInfo: WeightInfo;84 }8586 #[pallet::error]87 pub enum Error<T> {88 /// The foreign asset is already registered.89 ForeignAssetAlreadyRegistered,9091 /// The given asset ID could not be converted into the current XCM version.92 BadForeignAssetId,93 }9495 #[pallet::event]96 #[pallet::generate_deposit(fn deposit_event)]97 pub enum Event<T: Config> {98 /// The foreign asset registered.99 ForeignAssetRegistered {100 collection_id: CollectionId,101 asset_id: Box<VersionedAssetId>,102 },103 }104105 /// The corresponding collections of foreign assets.106 #[pallet::storage]107 #[pallet::getter(fn foreign_asset_to_collection)]108 pub type ForeignAssetToCollection<T: Config> =109 StorageMap<_, Twox64Concat, staging_xcm::v4::AssetId, CollectionId, OptionQuery>;110111 /// The corresponding foreign assets of collections.112 #[pallet::storage]113 #[pallet::getter(fn collection_to_foreign_asset)]114 pub type CollectionToForeignAsset<T: Config> =115 StorageMap<_, Twox64Concat, CollectionId, staging_xcm::v4::AssetId, OptionQuery>;116117 /// The correponding NFT token id of reserve NFTs118 #[pallet::storage]119 #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]120 pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<121 Hasher1 = Twox64Concat,122 Key1 = CollectionId,123 Hasher2 = Blake2_128Concat,124 // Key2 = staging_xcm::v3::AssetInstance,125 Key2 = staging_xcm::v4::AssetInstance,126 Value = TokenId,127 QueryKind = OptionQuery,128 >;129130 /// The correponding reserve NFT of a token ID131 #[pallet::storage]132 #[pallet::getter(fn token_id_to_foreign_reserve_asset_instance)]133 pub type TokenIdToForeignReserveAssetInstance<T: Config> = StorageDoubleMap<134 Hasher1 = Twox64Concat,135 Key1 = CollectionId,136 Hasher2 = Blake2_128Concat,137 Key2 = TokenId,138 // Value = staging_xcm::v3::AssetInstance,139 Value = staging_xcm::v4::AssetInstance,140 QueryKind = OptionQuery,141 >;142143 #[pallet::pallet]144 pub struct Pallet<T>(_);145146 #[pallet::call]147 impl<T: Config> Pallet<T> {148 #[pallet::call_index(0)]149 #[pallet::weight(<T as Config>::WeightInfo::force_register_foreign_asset())]150 pub fn force_register_foreign_asset(151 origin: OriginFor<T>,152 versioned_asset_id: Box<VersionedAssetId>,153 name: CollectionName,154 token_prefix: CollectionTokenPrefix,155 mode: ForeignCollectionMode,156 ) -> DispatchResult {157 T::ForceRegisterOrigin::ensure_origin(origin.clone())?;158159 let asset_id: AssetId = versioned_asset_id160 .as_ref()161 .clone()162 .try_into()163 .map_err(|()| Error::<T>::BadForeignAssetId)?;164165 ensure!(166 !<ForeignAssetToCollection<T>>::contains_key(&asset_id),167 <Error<T>>::ForeignAssetAlreadyRegistered,168 );169170 let foreign_collection_owner = Self::pallet_account();171172 let description: CollectionDescription = "Foreign Assets Collection"173 .encode_utf16()174 .collect::<Vec<_>>()175 .try_into()176 .expect("description length < max description length; qed");177178 let collection_id = T::CollectionDispatch::create(179 foreign_collection_owner,180 CollectionIssuer::Internals,181 CreateCollectionData {182 name,183 token_prefix,184 description,185 mode: mode.into(),186 ..Default::default()187 },188 )?;189190 <ForeignAssetToCollection<T>>::insert(&asset_id, collection_id);191 <CollectionToForeignAsset<T>>::insert(collection_id, asset_id);192193 Self::deposit_event(Event::<T>::ForeignAssetRegistered {194 collection_id,195 asset_id: versioned_asset_id,196 });197198 Ok(())199 }200 }201}202203impl<T: Config> Pallet<T> {204 fn pallet_account() -> T::CrossAccountId {205 let owner: T::AccountId = T::PalletId::get().into_account_truncating();206 T::CrossAccountId::from_sub(owner)207 }208209 /// Converts a concrete asset ID (the asset multilocation) to a local collection on Unique Network.210 ///211 /// The multilocation corresponds to a local collection if:212 /// * It is `Here` location that corresponds to the native token of this parachain.213 /// * It is `../Parachain(<Unique Network Para ID>)` that also corresponds to the native token of this parachain.214 /// * It is `../Parachain(<Unique Network Para ID>)/GeneralIndex(<Collection ID>)` that corresponds215 /// to the collection with the ID equal to `<Collection ID>`. The `<Collection ID>` must be in the valid range,216 /// otherwise `None` is returned.217 /// * It is `GeneralIndex(<Collection ID>)`. Same as the last one above.218 ///219 /// If the multilocation doesn't match the patterns listed above,220 /// or the `<Collection ID>` points to a foreign collection,221 /// `None` is returned, identifying that the given multilocation doesn't correspond to a local collection.222 fn local_asset_id_to_collection(223 AssetId(asset_location): &AssetId,224 ) -> Option<CollectionLocality> {225 let self_location = T::SelfLocation::get();226227 if *asset_location == Here.into() || *asset_location == self_location {228 return Some(CollectionLocality::Local(NATIVE_FUNGIBLE_COLLECTION_ID));229 }230231 let prefix = if asset_location.parents == 0 {232 &Here233 } else if asset_location.parents == self_location.parents {234 &self_location.interior235 } else {236 return None;237 };238239 let GeneralIndex(collection_id) = asset_location.interior.match_and_split(prefix)? else {240 return None;241 };242243 let collection_id = CollectionId((*collection_id).try_into().ok()?);244245 Self::collection_to_foreign_asset(collection_id)246 .is_none()247 .then_some(CollectionLocality::Local(collection_id))248 }249250 /// Converts an asset ID to a Unique Network's collection locality (either foreign or a local one).251 ///252 /// The function will check if the asset's reserve location has the corresponding253 /// foreign collection on Unique Network,254 /// and will return the "foreign" locality containing the collection ID if found.255 ///256 /// If no corresponding foreign collection is found, the function will check257 /// if the asset's reserve location corresponds to a local collection.258 /// If the local collection is found, the "local" locality with the collection ID is returned.259 ///260 /// If all of the above have failed, the `AssetIdConversionFailed` error will be returned.261 fn asset_to_collection(asset_id: &AssetId) -> Result<CollectionLocality, XcmError> {262 Self::foreign_asset_to_collection(asset_id)263 .map(CollectionLocality::Foreign)264 .or_else(|| Self::local_asset_id_to_collection(asset_id))265 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())266 }267268 /// Converts an XCM asset instance of local collection to the Unique Network's token ID.269 ///270 /// The asset instance corresponds to the Unique Network's token ID if it is in the following format:271 /// `AssetInstance::Index(<token ID>)`.272 ///273 /// If the asset instance is not in the valid format or the `<token ID>` can't fit into the valid token ID,274 /// `None` will be returned.275 ///276 /// Note: this function can return `Some` containing the token ID of a non-existing NFT.277 /// It returns `None` when it failed to convert the `asset_instance` to a local ID.278 fn local_asset_instance_to_token_id(asset_instance: &AssetInstance) -> Option<TokenId> {279 match asset_instance {280 AssetInstance::Index(token_id) => Some(TokenId((*token_id).try_into().ok()?)),281 _ => None,282 }283 }284285 /// Obtains the token ID of the `asset_instance` in the collection.286 ///287 /// Note: this function can return `Some` containing the token ID of a non-existing NFT.288 /// It returns `None` when it failed to convert the `asset_instance` to a local ID.289 fn asset_instance_to_token_id(290 collection_locality: CollectionLocality,291 asset_instance: &AssetInstance,292 ) -> Option<TokenId> {293 match collection_locality {294 CollectionLocality::Local(_) => Self::local_asset_instance_to_token_id(asset_instance),295 CollectionLocality::Foreign(collection_id) => {296 Self::foreign_reserve_asset_instance_to_token_id(collection_id, asset_instance)297 }298 }299 }300301 /// Creates a foreign item in the the collection.302 fn create_foreign_asset_instance(303 xcm_ext: &dyn XcmExtensions<T>,304 collection_id: CollectionId,305 asset_instance: &AssetInstance,306 to: T::CrossAccountId,307 ) -> DispatchResult {308 let derivative_token_id = xcm_ext.create_item(309 &Self::pallet_account(),310 to,311 CreateItemData::NFT(Default::default()),312 &ZeroBudget,313 )?;314315 <ForeignReserveAssetInstanceToTokenId<T>>::insert(316 collection_id,317 asset_instance,318 derivative_token_id,319 );320321 <TokenIdToForeignReserveAssetInstance<T>>::insert(322 collection_id,323 derivative_token_id,324 asset_instance,325 );326327 Ok(())328 }329330 /// Deposits an asset instance to the `to` account.331 ///332 /// Either transfers an existing item from the pallet's account333 /// or creates a foreign item.334 fn deposit_asset_instance(335 xcm_ext: &dyn XcmExtensions<T>,336 collection_locality: CollectionLocality,337 asset_instance: &AssetInstance,338 to: T::CrossAccountId,339 ) -> XcmResult {340 let token_id = Self::asset_instance_to_token_id(collection_locality, asset_instance);341342 let deposit_result = match (collection_locality, token_id) {343 (_, Some(token_id)) => {344 let depositor = &Self::pallet_account();345 let from = depositor;346 let amount = 1;347348 xcm_ext.transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)349 }350 (CollectionLocality::Foreign(collection_id), None) => {351 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)352 }353 (CollectionLocality::Local(_), None) => {354 return Err(XcmExecutorError::InstanceConversionFailed.into());355 }356 };357358 deposit_result359 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))360 }361362 /// Withdraws an asset instance from the `from` account.363 ///364 /// Transfers the asset instance to the pallet's account.365 fn withdraw_asset_instance(366 xcm_ext: &dyn XcmExtensions<T>,367 collection_locality: CollectionLocality,368 asset_instance: &AssetInstance,369 from: T::CrossAccountId,370 ) -> XcmResult {371 let token_id = Self::asset_instance_to_token_id(collection_locality, asset_instance)372 .ok_or(XcmExecutorError::InstanceConversionFailed)?;373374 let depositor = &from;375 let to = Self::pallet_account();376 let amount = 1;377 xcm_ext378 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)379 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item withdraw failed"))?;380381 Ok(())382 }383}384385// #[derive()]386// pub enum Migration {387388// }389390impl<T: Config> TransactAsset for Pallet<T> {391 fn can_check_in(_origin: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {392 Err(XcmError::Unimplemented)393 }394395 fn check_in(_origin: &Location, _what: &Asset, _context: &XcmContext) {}396397 fn can_check_out(_dest: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {398 Err(XcmError::Unimplemented)399 }400401 fn check_out(_dest: &Location, _what: &Asset, _context: &XcmContext) {}402403 fn deposit_asset(what: &Asset, to: &Location, _context: Option<&XcmContext>) -> XcmResult {404 let to = T::LocationToAccountId::convert_location(to)405 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;406407 let collection_locality = Self::asset_to_collection(&what.id)?;408 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)409 .map_err(|_| XcmExecutorError::AssetIdConversionFailed)?;410411 let collection = dispatch.as_dyn();412 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;413414 match what.fun {415 Fungibility::Fungible(amount) => xcm_ext416 .create_item(417 &Self::pallet_account(),418 to,419 CreateItemData::Fungible(CreateFungibleData { value: amount }),420 &ZeroBudget,421 )422 .map(|_| ())423 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),424425 Fungibility::NonFungible(asset_instance) => {426 Self::deposit_asset_instance(xcm_ext, collection_locality, &asset_instance, to)427 }428 }429 }430431 fn withdraw_asset(432 what: &Asset,433 from: &Location,434 _maybe_context: Option<&XcmContext>,435 ) -> Result<AssetsInHolding, XcmError> {436 let from = T::LocationToAccountId::convert_location(from)437 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;438439 let collection_locality = Self::asset_to_collection(&what.id)?;440 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)441 .map_err(|_| XcmExecutorError::AssetIdConversionFailed)?;442443 let collection = dispatch.as_dyn();444 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;445446 match what.fun {447 Fungibility::Fungible(amount) => xcm_ext448 .burn_item(from, TokenId::default(), amount)449 .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?,450451 Fungibility::NonFungible(asset_instance) => {452 Self::withdraw_asset_instance(xcm_ext, collection_locality, &asset_instance, from)?;453 }454 }455456 Ok(what.clone().into())457 }458459 fn internal_transfer_asset(460 what: &Asset,461 from: &Location,462 to: &Location,463 _context: &XcmContext,464 ) -> Result<AssetsInHolding, XcmError> {465 let from = T::LocationToAccountId::convert_location(from)466 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;467468 let to = T::LocationToAccountId::convert_location(to)469 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;470471 let collection_locality = Self::asset_to_collection(&what.id)?;472473 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)474 .map_err(|_| XcmExecutorError::AssetIdConversionFailed)?;475 let collection = dispatch.as_dyn();476 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;477478 let depositor = &from;479480 let token_id;481 let amount;482 let map_error: fn(DispatchError) -> XcmError;483484 match what.fun {485 Fungibility::Fungible(fungible_amount) => {486 token_id = TokenId::default();487 amount = fungible_amount;488 map_error = |_| XcmError::FailedToTransactAsset("fungible item transfer failed");489 }490491 Fungibility::NonFungible(asset_instance) => {492 token_id = Self::asset_instance_to_token_id(collection_locality, &asset_instance)493 .ok_or(XcmExecutorError::InstanceConversionFailed)?;494495 amount = 1;496 map_error = |_| XcmError::FailedToTransactAsset("non-fungible item transfer failed")497 }498 }499500 xcm_ext501 .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget)502 .map_err(map_error)?;503504 Ok(what.clone().into())505 }506}507508#[derive(Clone, Copy)]509pub enum CollectionLocality {510 Local(CollectionId),511 Foreign(CollectionId),512}513514impl Deref for CollectionLocality {515 type Target = CollectionId;516517 fn deref(&self) -> &Self::Target {518 match self {519 Self::Local(id) => id,520 Self::Foreign(id) => id,521 }522 }523}524525pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);526impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<Location>>527 for CurrencyIdConvert<T>528{529 fn convert(collection_id: CollectionId) -> Option<Location> {530 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {531 Some(T::SelfLocation::get())532 } else {533 <Pallet<T>>::collection_to_foreign_asset(collection_id)534 .map(|AssetId(location)| location)535 .or_else(|| {536 T::SelfLocation::get()537 .pushed_with_interior(GeneralIndex(collection_id.0.into()))538 .ok()539 })540 }541 }542}543544#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]545pub enum ForeignCollectionMode {546 NFT,547 Fungible(u8),548}549550impl From<ForeignCollectionMode> for CollectionMode {551 fn from(value: ForeignCollectionMode) -> Self {552 match value {553 ForeignCollectionMode::NFT => Self::NFT,554 ForeignCollectionMode::Fungible(decimals) => Self::Fungible(decimals),555 }556 }557}558559pub struct FreeForAll;560561impl WeightTrader for FreeForAll {562 fn new() -> Self {563 Self564 }565566 fn buy_weight(567 &mut self,568 weight: Weight,569 payment: AssetsInHolding,570 _xcm: &XcmContext,571 ) -> Result<AssetsInHolding, XcmError> {572 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);573 Ok(payment)574 }575}runtime/common/config/governance/financial_council.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/governance/financial_council.rs
@@ -0,0 +1,56 @@
+use super::*;
+
+parameter_types! {
+ pub FinancialCouncilMaxProposals: u32 = 100;
+ pub FinancialCouncilMaxMembers: u32 = 100;
+}
+
+#[cfg(not(feature = "gov-test-timings"))]
+use crate::governance_timings::financial_council as financial_council_timings;
+
+#[cfg(feature = "gov-test-timings")]
+pub mod financial_council_timings {
+ use super::*;
+
+ parameter_types! {
+ pub FinancialCouncilMotionDuration: BlockNumber = 35;
+ }
+}
+
+pub type FinancialCollective = pallet_collective::Instance3;
+impl pallet_collective::Config<FinancialCollective> for Runtime {
+ type RuntimeOrigin = RuntimeOrigin;
+ type Proposal = RuntimeCall;
+ type RuntimeEvent = RuntimeEvent;
+ type MotionDuration = financial_council_timings::FinancialCouncilMotionDuration;
+ type MaxProposals = FinancialCouncilMaxProposals;
+ type MaxMembers = FinancialCouncilMaxMembers;
+ type DefaultVote = pallet_collective::PrimeDefaultVote;
+ type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
+ type SetMembersOrigin = EnsureRoot<AccountId>;
+ type MaxProposalWeight = MaxCollectivesProposalWeight;
+}
+
+pub type FinancialCollectiveMembership = pallet_membership::Instance3;
+impl pallet_membership::Config<FinancialCollectiveMembership> for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type AddOrigin = RootOrMoreThanHalfCouncil;
+ type RemoveOrigin = RootOrMoreThanHalfCouncil;
+ type SwapOrigin = RootOrMoreThanHalfCouncil;
+ type ResetOrigin = EnsureRoot<AccountId>;
+ type PrimeOrigin = RootOrMoreThanHalfCouncil;
+ type MembershipInitialized = TechnicalCommittee;
+ type MembershipChanged = TechnicalCommittee;
+ type MaxMembers = FinancialCouncilMaxMembers;
+ type WeightInfo = pallet_membership::weights::SubstrateWeight<Runtime>;
+}
+
+pub type FinancialCouncilMember = pallet_collective::EnsureMember<AccountId, FinancialCollective>;
+
+pub type RootOrFinancialCouncilMember =
+ EitherOfDiverse<EnsureRoot<AccountId>, FinancialCouncilMember>;
+
+pub type AllFinancialCouncil =
+ pallet_collective::EnsureProportionAtLeast<AccountId, FinancialCollective, 1, 1>;
+
+pub type RootOrAllFinancialCouncil = EitherOfDiverse<EnsureRoot<AccountId>, AllFinancialCouncil>;
runtime/common/config/governance/mod.rsdiffbeforeafterboth--- a/runtime/common/config/governance/mod.rs
+++ b/runtime/common/config/governance/mod.rs
@@ -49,6 +49,9 @@
pub mod technical_committee;
pub use technical_committee::*;
+pub mod financial_council;
+pub use financial_council::*;
+
pub mod fellowship;
pub use fellowship::*;
runtime/common/config/pallets/foreign_asset.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/foreign_asset.rs
+++ b/runtime/common/config/pallets/foreign_asset.rs
@@ -40,10 +40,10 @@
type RuntimeEvent = RuntimeEvent;
#[cfg(feature = "governance")]
- type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember;
+ type ManagerOrigin = governance::RootOrFinancialCouncilMember;
#[cfg(not(feature = "governance"))]
- type ForceRegisterOrigin = EnsureRoot<Self::AccountId>;
+ type ManagerOrigin = EnsureRoot<Self::AccountId>;
type PalletId = ForeignAssetPalletId;
type SelfLocation = SelfLocation;
runtime/common/construct_runtime.rsdiffbeforeafterboth--- a/runtime/common/construct_runtime.rs
+++ b/runtime/common/construct_runtime.rs
@@ -81,6 +81,12 @@
Scheduler: pallet_scheduler = 49,
#[cfg(feature = "governance")]
+ FinancialCouncil: pallet_collective::<Instance3> = 97,
+
+ #[cfg(feature = "governance")]
+ FinancialCouncilMembership: pallet_membership::<Instance3> = 98,
+
+ #[cfg(feature = "governance")]
Origins: pallet_gov_origins = 99,
// XCM helpers.
runtime/opal/src/governance_timings.rsdiffbeforeafterboth--- a/runtime/opal/src/governance_timings.rs
+++ b/runtime/opal/src/governance_timings.rs
@@ -52,3 +52,11 @@
pub TechnicalMotionDuration: BlockNumber = 15 * MINUTES;
}
}
+
+pub mod financial_council {
+ use super::*;
+
+ parameter_types! {
+ pub FinancialCouncilMotionDuration: BlockNumber = 15 * MINUTES;
+ }
+}
runtime/quartz/src/governance_timings.rsdiffbeforeafterboth--- a/runtime/quartz/src/governance_timings.rs
+++ b/runtime/quartz/src/governance_timings.rs
@@ -52,3 +52,11 @@
pub TechnicalMotionDuration: BlockNumber = 3 * DAYS;
}
}
+
+pub mod financial_council {
+ use super::*;
+
+ parameter_types! {
+ pub FinancialCouncilMotionDuration: BlockNumber = 3 * DAYS;
+ }
+}
runtime/unique/src/governance_timings.rsdiffbeforeafterboth--- a/runtime/unique/src/governance_timings.rs
+++ b/runtime/unique/src/governance_timings.rs
@@ -52,3 +52,11 @@
pub TechnicalMotionDuration: BlockNumber = 3 * DAYS;
}
}
+
+pub mod financial_council {
+ use super::*;
+
+ parameter_types! {
+ pub FinancialCouncilMotionDuration: BlockNumber = 3 * DAYS;
+ }
+}