瀏覽代碼

runtime: utilities: add pallet

conectado 4 年之前
父節點
當前提交
d870d5ad48

+ 26 - 0
Cargo.lock

@@ -2380,6 +2380,7 @@ dependencies = [
  "pallet-timestamp",
  "pallet-transaction-payment",
  "pallet-transaction-payment-rpc-runtime-api",
+ "pallet-utilities",
  "pallet-utility",
  "pallet-working-group",
  "parity-scale-codec",
@@ -4294,6 +4295,31 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-utilities"
+version = "1.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-council",
+ "pallet-membership",
+ "pallet-referendum",
+ "pallet-staking-handler",
+ "pallet-timestamp",
+ "pallet-working-group",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "strum 0.19.5",
+]
+
 [[package]]
 name = "pallet-utility"
 version = "2.0.0"

+ 1 - 0
Cargo.toml

@@ -17,6 +17,7 @@ members = [
 	"runtime-modules/constitution",
 	"runtime-modules/staking-handler",
     "runtime-modules/blog",
+    "runtime-modules/utilities",
 	"node",
 	"utils/chain-spec-builder/"
 ]

+ 10 - 0
runtime-modules/common/src/lib.rs

@@ -71,6 +71,16 @@ pub struct FundingRequestParameters<Balance, AccountId> {
     pub amount: Balance,
 }
 
+/// Kind of Balance for `Update Working Group Budget`.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug, Eq)]
+pub enum BalanceKind {
+    /// Increasing Working Group budget decreasing Council budget
+    Positive,
+    /// Decreasing Working Group budget increasing Council budget
+    Negative,
+}
+
 /// Gathers current block and time information for the runtime.
 /// If this function is used inside a config() at genesis the timestamp will be 0
 /// because the timestamp is actually produced by validators.

+ 5 - 4
runtime-modules/proposals/codex/Cargo.toml

@@ -14,15 +14,15 @@ sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://
 frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 staking = { package = 'pallet-staking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 working-group = { package = 'pallet-working-group', default-features = false, path = '../../working-group'}
 common = { package = 'pallet-common', default-features = false, path = '../../common'}
 proposals-engine = { package = 'pallet-proposals-engine', default-features = false, path = '../engine'}
 proposals-discussion = { package = 'pallet-proposals-discussion', default-features = false, path = '../discussion'}
 constitution = { package = 'pallet-constitution', default-features = false, path = '../../constitution'}
 membership = { package = 'pallet-membership', default-features = false, path = '../../membership'}
-council = { package = 'pallet-council', default-features = false, path = '../../council'}
 blog = { package = 'pallet-blog', default-features = false, path = '../../blog'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
+council = { package = 'pallet-council', default-features = false, path = '../../council', optional = true}
 
 # Benchmarking dependencies
 frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
@@ -35,10 +35,12 @@ pallet-staking-reward-curve = { package = 'pallet-staking-reward-curve', default
 strum = {version = "0.19", default-features = false}
 staking-handler = { package = 'pallet-staking-handler', default-features = false, path = '../../staking-handler'}
 referendum = { package = 'pallet-referendum', default-features = false, path = '../../referendum'}
+council = { package = 'pallet-council', default-features = false, path = '../../council'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 [features]
 default = ['std']
-runtime-benchmarks = ['frame-benchmarking']
+runtime-benchmarks = ['frame-benchmarking', 'balances', 'council']
 std = [
     'serde',
     'codec/std',
@@ -49,7 +51,6 @@ std = [
     'frame-system/std',
     'staking/std',
     'pallet-timestamp/std',
-    'balances/std',
     'working-group/std',
     'common/std',
     'proposals-engine/std',

+ 3 - 200
runtime-modules/proposals/codex/src/benchmarking.rs

@@ -2,6 +2,8 @@
 use super::*;
 use crate::Module as Codex;
 use balances::Module as Balances;
+use common::working_group::WorkingGroup;
+use common::BalanceKind;
 use frame_benchmarking::{account, benchmarks};
 use frame_support::sp_runtime::traits::Bounded;
 use frame_support::traits::Currency;
@@ -159,54 +161,13 @@ fn create_proposal_verify<T: Trait>(
     );
 }
 
-fn set_wg_and_council_budget<T: Trait>(budget: u32, group: WorkingGroup) {
-    Council::<T>::set_budget(RawOrigin::Root.into(), BalanceOf::<T>::from(budget)).unwrap();
-
-    T::set_working_group_budget(group, BalanceOf::<T>::from(budget));
-
-    assert_eq!(
-        Council::<T>::budget(),
-        BalanceOf::<T>::from(budget),
-        "Council budget not updated"
-    );
-
-    assert_eq!(
-        T::get_working_group_budget(group),
-        BalanceOf::<T>::from(budget),
-        "Working Group budget not updated"
-    );
-}
-
-fn assert_new_budgets<T: Trait>(
-    new_budget_council: u32,
-    new_budget_working_group: u32,
-    group: WorkingGroup,
-) {
-    assert_eq!(
-        Council::<T>::budget(),
-        BalanceOf::<T>::from(new_budget_council),
-        "Council budget not updated"
-    );
-
-    assert_eq!(
-        T::get_working_group_budget(group),
-        BalanceOf::<T>::from(new_budget_working_group),
-        "Working Group budget not updated"
-    );
-}
-
 benchmarks! {
-    where_clause { where T: membership::Trait }
+    where_clause { where T: membership::Trait, T: council::Trait }
     _ {
         let t in 1 .. T::TitleMaxLength::get() => ();
         let d in 1 .. T::DescriptionMaxLength::get() => ();
     }
 
-    // Note: No verify since there is no side effect to test
-    execute_signal_proposal {
-        let i in 1 .. MAX_BYTES;
-    }: _(RawOrigin::Root, vec![0u8; i.try_into().unwrap()])
-
     create_proposal_signal {
         let i in 1 .. MAX_BYTES;
         let t in ...;
@@ -823,97 +784,6 @@ benchmarks! {
         );
     }
 
-    update_working_group_budget_positive_forum {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Forum);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Forum,
-        One::one(),
-        BalanceKind::Positive
-    )
-    verify {
-        assert_new_budgets::<T>(99, 101, WorkingGroup::Forum);
-    }
-
-    update_working_group_budget_negative_forum {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Forum);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Forum,
-        One::one(),
-        BalanceKind::Negative
-    )
-    verify{
-        assert_new_budgets::<T>(101, 99, WorkingGroup::Forum);
-    }
-
-    update_working_group_budget_positive_storage {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Storage);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Storage,
-        One::one(),
-        BalanceKind::Positive
-    )
-    verify {
-        assert_new_budgets::<T>(99, 101, WorkingGroup::Storage);
-    }
-
-    update_working_group_budget_negative_storage {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Storage);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Storage,
-        One::one(),
-        BalanceKind::Negative
-    )
-    verify {
-        assert_new_budgets::<T>(101, 99, WorkingGroup::Storage);
-    }
-
-    update_working_group_budget_positive_content {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Content);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Content,
-        One::one(),
-        BalanceKind::Positive
-    )
-    verify {
-        assert_new_budgets::<T>(99, 101, WorkingGroup::Content);
-    }
-
-    update_working_group_budget_negative_content {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Content);
-    }: update_working_group_budget(RawOrigin::Root, WorkingGroup::Content, One::one(),
-    BalanceKind::Negative)
-    verify {
-        assert_new_budgets::<T>(101, 99, WorkingGroup::Content);
-    }
-
-    update_working_group_budget_positive_membership {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Membership);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Membership,
-        One::one(),
-        BalanceKind::Positive
-    )
-    verify {
-        assert_new_budgets::<T>(99, 101, WorkingGroup::Membership);
-    }
-
-    update_working_group_budget_negative_membership {
-        set_wg_and_council_budget::<T>(100, WorkingGroup::Membership);
-    }: update_working_group_budget(
-        RawOrigin::Root,
-        WorkingGroup::Membership,
-        One::one(),
-        BalanceKind::Negative
-    )
-    verify {
-        assert_new_budgets::<T>(101, 99, WorkingGroup::Membership);
-    }
 }
 
 #[cfg(test)]
@@ -922,13 +792,6 @@ mod tests {
     use crate::tests::{initial_test_ext, Test};
     use frame_support::assert_ok;
 
-    #[test]
-    fn test_execute_signal_proposal() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_execute_signal_proposal::<Test>());
-        });
-    }
-
     #[test]
     fn test_create_proposal_signal() {
         initial_test_ext().execute_with(|| {
@@ -1066,66 +929,6 @@ mod tests {
         });
     }
 
-    #[test]
-    fn test_update_working_group_budget_positive_forum() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_positive_forum::<
-                Test,
-            >());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_negative_forum() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_negative_forum::<
-                Test,
-            >());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_positive_storage() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_positive_storage::<Test>());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_negative_storage() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_negative_storage::<Test>());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_positive_content() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_positive_content::<Test>());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_negative_content() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_negative_content::<Test>());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_positive_membership() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_positive_membership::<Test>());
-        });
-    }
-
-    #[test]
-    fn test_update_working_group_budget_negative_membership() {
-        initial_test_ext().execute_with(|| {
-            assert_ok!(test_benchmark_update_working_group_budget_negative_membership::<Test>());
-        });
-    }
-
     #[test]
     fn test_create_blog_post() {
         initial_test_ext().execute_with(|| {

+ 6 - 175
runtime-modules/proposals/codex/src/lib.rs

@@ -54,29 +54,23 @@ mod benchmarking;
 
 use frame_support::dispatch::DispatchResult;
 use frame_support::traits::Get;
-use frame_support::weights::{DispatchClass, Weight};
-use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure, print};
-use frame_system::ensure_root;
+use frame_support::weights::Weight;
+use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure};
 use sp_arithmetic::traits::Zero;
-use sp_runtime::traits::Saturating;
 use sp_runtime::SaturatedConversion;
 use sp_std::clone::Clone;
 use sp_std::collections::btree_set::BTreeSet;
-use sp_std::vec::Vec;
 
-pub use crate::types::{
-    BalanceKind, CreateOpeningParameters, FillOpeningParameters, GeneralProposalParams,
-    ProposalDetails, ProposalDetailsOf, ProposalEncoder, TerminateRoleParameters,
-};
 use common::origin::MemberOriginValidator;
 use common::MemberId;
-use council::Module as Council;
 use proposals_discussion::ThreadMode;
 use proposals_engine::{
     BalanceOf, ProposalCreationParameters, ProposalObserver, ProposalParameters,
 };
-
-use common::working_group::WorkingGroup;
+pub use types::{
+    CreateOpeningParameters, FillOpeningParameters, GeneralProposalParams, ProposalDetails,
+    ProposalDetailsOf, ProposalEncoder, TerminateRoleParameters,
+};
 
 // Max allowed value for 'Funding Request' proposal
 const MAX_SPENDING_PROPOSAL_VALUE: u32 = 5_000_000_u32;
@@ -88,7 +82,6 @@ const MAX_FUNDING_REQUEST_ACCOUNTS: usize = 100;
 /// Proposal codex WeightInfo.
 /// Note: This was auto generated through the benchmark CLI using the `--weight-trait` flag
 pub trait WeightInfo {
-    fn execute_signal_proposal(i: u32) -> Weight;
     fn create_proposal_signal(i: u32, t: u32, d: u32) -> Weight;
     fn create_proposal_runtime_upgrade(i: u32, t: u32, d: u32) -> Weight;
     fn create_proposal_funding_request(i: u32, d: u32) -> Weight;
@@ -114,14 +107,6 @@ pub trait WeightInfo {
     fn create_proposal_lock_blog_post(t: u32, d: u32) -> Weight;
     fn create_proposal_unlock_blog_post(t: u32, d: u32) -> Weight;
     fn create_proposal_veto_proposal(t: u32, d: u32) -> Weight;
-    fn update_working_group_budget_positive_forum() -> Weight;
-    fn update_working_group_budget_negative_forum() -> Weight;
-    fn update_working_group_budget_positive_storage() -> Weight;
-    fn update_working_group_budget_negative_storage() -> Weight;
-    fn update_working_group_budget_positive_content() -> Weight;
-    fn update_working_group_budget_negative_content() -> Weight;
-    fn update_working_group_budget_positive_membership() -> Weight;
-    fn update_working_group_budget_negative_membership() -> Weight;
 }
 
 type WeightInfoCodex<T> = <T as Trait>::WeightInfo;
@@ -132,7 +117,6 @@ pub trait Trait:
     + proposals_engine::Trait
     + proposals_discussion::Trait
     + common::Trait
-    + council::Trait
     + staking::Trait
     + proposals_engine::Trait
 {
@@ -268,12 +252,6 @@ pub trait Trait:
 
     /// `Veto Proposal` proposal parameters
     type VetoProposalProposalParameters: Get<ProposalParameters<Self::BlockNumber, BalanceOf<Self>>>;
-
-    /// Gets the budget of the given WorkingGroup
-    fn get_working_group_budget(working_group: WorkingGroup) -> BalanceOf<Self>;
-
-    /// Sets the budget for the given WorkingGroup
-    fn set_working_group_budget(working_group: WorkingGroup, budget: BalanceOf<Self>);
 }
 
 /// Specialized alias of GeneralProposalParams
@@ -287,33 +265,12 @@ decl_event! {
     pub enum Event<T> where
         GeneralProposalParameters = GeneralProposalParameters<T>,
         ProposalDetailsOf = ProposalDetailsOf<T>,
-        WorkingGroup = WorkingGroup,
-        Balance = BalanceOf<T>,
-        BalanceKind = BalanceKind
     {
         /// A proposal was created
         /// Params:
         /// - General proposal parameter. Parameters shared by all proposals
         /// - Proposal Details. Parameter of proposal with a variant for each kind of proposal
         ProposalCreated(GeneralProposalParameters, ProposalDetailsOf),
-
-        /// A signal proposal was executed
-        /// Params:
-        /// - Signal given when creating the corresponding proposal
-        Signaled(Vec<u8>),
-
-        /// A runtime upgrade was executed
-        /// Params:
-        /// - New code encoded in bytes
-        RuntimeUpgraded(Vec<u8>),
-
-        /// An `Update Working Group Budget` proposal was executed
-        /// Params:
-        /// - Working group which budget is being updated
-        /// - Amount of balance being moved
-        /// - Enum variant with positive indicating funds moved torwards working group and negative
-        /// and negative funds moving from the working group
-        UpdatedWorkingGroupBudget(WorkingGroup, Balance, BalanceKind),
     }
 }
 
@@ -563,95 +520,6 @@ decl_module! {
 
             Self::deposit_event(RawEvent::ProposalCreated(general_proposal_parameters, proposal_details));
         }
-
-// *************** Extrinsic to execute
-
-        /// Signal proposal extrinsic. Should be used as callable object to pass to the `engine` module.
-        ///
-        /// <weight>
-        ///
-        /// ## Weight
-        /// `O (S)` where:
-        /// - `S` is the length of the signal
-        /// - DB:
-        ///    - O(1) doesn't depend on the state or parameters
-        /// # </weight>
-        #[weight = WeightInfoCodex::<T>::execute_signal_proposal(signal.len().saturated_into())]
-        pub fn execute_signal_proposal(
-            origin,
-            signal: Vec<u8>,
-        ) {
-            ensure_root(origin)?;
-
-            // Signal proposal stub: no code implied.
-
-            Self::deposit_event(RawEvent::Signaled(signal));
-        }
-
-        /// Runtime upgrade proposal extrinsic.
-        /// Should be used as callable object to pass to the `engine` module.
-        /// <weight>
-        ///
-        /// ## Weight
-        /// `O (C)` where:
-        /// - `C` is the length of `wasm`
-        /// However, we treat this as a full block as `frame_system::Module::set_code` does
-        /// # </weight>
-        #[weight = (T::MaximumBlockWeight::get(), DispatchClass::Operational)]
-        pub fn execute_runtime_upgrade_proposal(
-            origin,
-            wasm: Vec<u8>,
-        ) {
-            ensure_root(origin.clone())?;
-
-            print("Runtime upgrade proposal execution started.");
-
-            <frame_system::Module<T>>::set_code(origin, wasm.clone())?;
-
-            print("Runtime upgrade proposal execution finished.");
-
-            Self::deposit_event(RawEvent::RuntimeUpgraded(wasm));
-        }
-
-        /// Update working group budget
-        /// <weight>
-        ///
-        /// ## Weight
-        /// `O (1)` Doesn't depend on the state or parameters
-        /// - DB:
-        ///    - O(1) doesn't depend on the state or parameters
-        /// # </weight>
-        #[weight = Module::<T>::get_update_working_group_budget_weight(&working_group, &balance_kind)]
-        pub fn update_working_group_budget(
-            origin,
-            working_group: WorkingGroup,
-            amount: BalanceOf<T>,
-            balance_kind: BalanceKind,
-        ) {
-            ensure_root(origin.clone())?;
-
-
-            let wg_budget = T::get_working_group_budget(working_group);
-            let current_budget = Council::<T>::budget();
-
-            match balance_kind {
-                BalanceKind::Positive => {
-                    ensure!(amount<=current_budget, Error::<T>::InsufficientFundsForBudgetUpdate);
-
-                    T::set_working_group_budget(working_group, wg_budget.saturating_add(amount));
-                    Council::<T>::set_budget(origin, current_budget - amount)?;
-                },
-                BalanceKind::Negative => {
-                    ensure!(amount <= wg_budget, Error::<T>::InsufficientFundsForBudgetUpdate);
-
-                    T::set_working_group_budget(working_group, wg_budget - amount);
-                    Council::<T>::set_budget(origin, current_budget.saturating_add(amount))?;
-                }
-            }
-
-            Self::deposit_event(RawEvent::UpdatedWorkingGroupBudget(working_group, amount, balance_kind));
-        }
-
     }
 }
 
@@ -849,43 +717,6 @@ impl<T: Trait> Module<T> {
         }
     }
 
-    // Returns the weigt for update_working_group_budget extrinsic according to parameters
-    fn get_update_working_group_budget_weight(
-        group: &WorkingGroup,
-        balance_kind: &BalanceKind,
-    ) -> Weight {
-        match balance_kind {
-            BalanceKind::Positive => match group {
-                WorkingGroup::Forum => {
-                    WeightInfoCodex::<T>::update_working_group_budget_positive_forum()
-                }
-                WorkingGroup::Storage => {
-                    WeightInfoCodex::<T>::update_working_group_budget_positive_storage()
-                }
-                WorkingGroup::Content => {
-                    WeightInfoCodex::<T>::update_working_group_budget_positive_content()
-                }
-                WorkingGroup::Membership => {
-                    WeightInfoCodex::<T>::update_working_group_budget_positive_membership()
-                }
-            },
-            BalanceKind::Negative => match group {
-                WorkingGroup::Forum => {
-                    WeightInfoCodex::<T>::update_working_group_budget_negative_forum()
-                }
-                WorkingGroup::Storage => {
-                    WeightInfoCodex::<T>::update_working_group_budget_negative_storage()
-                }
-                WorkingGroup::Membership => {
-                    WeightInfoCodex::<T>::update_working_group_budget_negative_membership()
-                }
-                WorkingGroup::Content => {
-                    WeightInfoCodex::<T>::update_working_group_budget_negative_content()
-                }
-            },
-        }
-    }
-
     // Returns weight for the proposal creation according to parameters
     fn get_create_proposal_weight(
         general: &GeneralProposalParameters<T>,

+ 0 - 55
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -16,9 +16,7 @@ use sp_runtime::{
 use sp_staking::SessionIndex;
 use staking_handler::{LockComparator, StakingManager};
 
-use crate::BalanceOf;
 use crate::{ProposalDetailsOf, ProposalEncoder, ProposalParameters};
-use common::working_group::{WorkingGroup, WorkingGroupBudgetHandler};
 use frame_support::dispatch::DispatchError;
 use proposals_engine::VotersParameters;
 use sp_runtime::testing::TestXt;
@@ -548,24 +546,6 @@ pub(crate) fn default_proposal_parameters() -> ProposalParameters<u64, u64> {
     }
 }
 
-macro_rules! call_wg {
-    ($working_group:ident<$T:ty>, $function:ident $(,$x:expr)*) => {{
-        match $working_group {
-            WorkingGroup::Content =>
-                <working_group::Module::<$T, ContentDirectoryWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
-
-            WorkingGroup::Storage =>
-                <working_group::Module::<$T, StorageWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
-
-            WorkingGroup::Forum =>
-                <working_group::Module::<$T, ForumWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
-
-            WorkingGroup::Membership =>
-                <working_group::Module::<$T, MembershipWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
-        }
-    }};
-}
-
 impl crate::Trait for Test {
     type Event = TestEvent;
     type MembershipOriginValidator = ();
@@ -596,14 +576,6 @@ impl crate::Trait for Test {
     type LockBlogPostProposalParameters = DefaultProposalParameters;
     type UnlockBlogPostProposalParameters = DefaultProposalParameters;
     type VetoProposalProposalParameters = DefaultProposalParameters;
-
-    fn get_working_group_budget(working_group: WorkingGroup) -> BalanceOf<Test> {
-        call_wg!(working_group<Test>, get_budget)
-    }
-
-    fn set_working_group_budget(working_group: WorkingGroup, budget: BalanceOf<Test>) {
-        call_wg!(working_group<Test>, set_budget, budget)
-    }
 }
 
 parameter_types! {
@@ -798,9 +770,6 @@ impl referendum::WeightInfo for ReferendumWeightInfo {
 }
 
 impl crate::WeightInfo for () {
-    fn execute_signal_proposal(_: u32) -> Weight {
-        0
-    }
     fn create_proposal_signal(_: u32, _: u32, _: u32) -> Weight {
         0
     }
@@ -876,30 +845,6 @@ impl crate::WeightInfo for () {
     fn create_proposal_veto_proposal(_: u32, _: u32) -> Weight {
         0
     }
-    fn update_working_group_budget_positive_forum() -> Weight {
-        0
-    }
-    fn update_working_group_budget_negative_forum() -> Weight {
-        0
-    }
-    fn update_working_group_budget_positive_storage() -> Weight {
-        0
-    }
-    fn update_working_group_budget_negative_storage() -> Weight {
-        0
-    }
-    fn update_working_group_budget_positive_content() -> Weight {
-        0
-    }
-    fn update_working_group_budget_negative_content() -> Weight {
-        0
-    }
-    fn update_working_group_budget_positive_membership() -> Weight {
-        0
-    }
-    fn update_working_group_budget_negative_membership() -> Weight {
-        0
-    }
 }
 
 impl ProposalEncoder<Test> for () {

+ 1 - 170
runtime-modules/proposals/codex/src/tests/mod.rs

@@ -5,10 +5,10 @@ use frame_support::storage::StorageMap;
 use frame_support::traits::Currency;
 use frame_support::traits::{OnFinalize, OnInitialize};
 use frame_system::{EventRecord, RawOrigin};
-use sp_arithmetic::traits::One;
 use sp_std::convert::TryInto;
 
 use common::working_group::WorkingGroup;
+use common::BalanceKind;
 use proposals_engine::ProposalParameters;
 use referendum::ReferendumManager;
 
@@ -419,175 +419,6 @@ fn create_funding_request_proposal_call_fails_with_incorrect_number_of_accounts(
     });
 }
 
-#[test]
-fn execute_signal_proposal_fails() {
-    initial_test_ext().execute_with(|| {
-        assert_eq!(
-            ProposalCodex::execute_signal_proposal(RawOrigin::Signed(0).into(), vec![0]),
-            Err(DispatchError::BadOrigin)
-        );
-    });
-}
-
-#[test]
-fn execute_signal_proposal_succeds() {
-    initial_test_ext().execute_with(|| {
-        let signal = vec![0];
-        assert_eq!(
-            ProposalCodex::execute_signal_proposal(RawOrigin::Root.into(), signal.clone()),
-            Ok(())
-        );
-
-        assert_last_event(RawEvent::Signaled(signal).into());
-    });
-}
-
-#[test]
-fn execute_runtime_upgrade_proposal_fails() {
-    initial_test_ext().execute_with(|| {
-        assert_eq!(
-            ProposalCodex::execute_runtime_upgrade_proposal(RawOrigin::Signed(0).into(), vec![0]),
-            Err(DispatchError::BadOrigin)
-        );
-    });
-}
-
-#[test]
-fn update_working_group_budget_fails_permissions() {
-    for wg in WorkingGroup::iter() {
-        run_update_working_group_budget_fails_permissions(wg);
-    }
-}
-
-fn run_update_working_group_budget_fails_permissions(wg: WorkingGroup) {
-    initial_test_ext().execute_with(|| {
-        assert_eq!(
-            ProposalCodex::update_working_group_budget(
-                RawOrigin::Signed(0).into(),
-                wg,
-                Zero::zero(),
-                BalanceKind::Positive
-            ),
-            Err(DispatchError::BadOrigin)
-        );
-    });
-}
-
-#[test]
-fn update_working_group_budget_fails_positive() {
-    for wg in WorkingGroup::iter() {
-        run_update_working_group_budget_fails_positive(wg);
-    }
-}
-
-fn run_update_working_group_budget_fails_positive(wg: WorkingGroup) {
-    initial_test_ext().execute_with(|| {
-        assert_eq!(council::Module::<Test>::budget(), 0);
-        assert_eq!(
-            ProposalCodex::update_working_group_budget(
-                RawOrigin::Root.into(),
-                wg,
-                One::one(),
-                BalanceKind::Positive
-            ),
-            Err(Error::<Test>::InsufficientFundsForBudgetUpdate.into())
-        );
-    });
-}
-
-#[test]
-fn update_working_group_budget_fails_negative() {
-    for wg in WorkingGroup::iter() {
-        run_update_working_group_budget_fails_negative(wg);
-    }
-}
-
-fn run_update_working_group_budget_fails_negative(wg: WorkingGroup) {
-    initial_test_ext().execute_with(|| {
-        assert_eq!(<Test as Trait>::get_working_group_budget(wg), 0);
-        assert_eq!(
-            ProposalCodex::update_working_group_budget(
-                RawOrigin::Root.into(),
-                wg,
-                One::one(),
-                BalanceKind::Negative
-            ),
-            Err(Error::<Test>::InsufficientFundsForBudgetUpdate.into())
-        );
-    });
-}
-
-#[test]
-fn update_working_group_budget_succeeds_positive() {
-    for wg in WorkingGroup::iter() {
-        run_update_working_group_budget_succeeds_positive(wg);
-    }
-}
-
-fn run_update_working_group_budget_succeeds_positive(wg: WorkingGroup) {
-    initial_test_ext().execute_with(|| {
-        let budget = 100000;
-        let funding_amount = 1;
-        council::Module::<Test>::set_budget(RawOrigin::Root.into(), budget).unwrap();
-        assert_eq!(council::Module::<Test>::budget(), budget);
-        assert_eq!(<Test as Trait>::get_working_group_budget(wg), 0);
-        assert_eq!(
-            ProposalCodex::update_working_group_budget(
-                RawOrigin::Root.into(),
-                wg,
-                funding_amount,
-                BalanceKind::Positive
-            ),
-            Ok(())
-        );
-
-        assert_eq!(council::Module::<Test>::budget(), budget - funding_amount);
-        assert_eq!(
-            <Test as Trait>::get_working_group_budget(wg),
-            funding_amount
-        );
-        assert_last_event(
-            RawEvent::UpdatedWorkingGroupBudget(wg, funding_amount, BalanceKind::Positive).into(),
-        );
-    });
-}
-
-#[test]
-fn update_working_group_budget_succeeds_negative() {
-    for wg in WorkingGroup::iter() {
-        run_update_working_group_budget_succeeds_negative(wg);
-    }
-}
-
-fn run_update_working_group_budget_succeeds_negative(wg: WorkingGroup) {
-    initial_test_ext().execute_with(|| {
-        let budget = 100000;
-        let funding_amount = 1;
-        <Test as Trait>::set_working_group_budget(wg, budget);
-        assert_eq!(council::Module::<Test>::budget(), 0);
-        assert_eq!(<Test as Trait>::get_working_group_budget(wg), budget);
-
-        assert_eq!(
-            ProposalCodex::update_working_group_budget(
-                RawOrigin::Root.into(),
-                wg,
-                funding_amount,
-                BalanceKind::Negative,
-            ),
-            Ok(())
-        );
-
-        assert_eq!(council::Module::<Test>::budget(), funding_amount);
-        assert_eq!(
-            <Test as Trait>::get_working_group_budget(wg),
-            budget - funding_amount
-        );
-        assert_last_event(
-            RawEvent::UpdatedWorkingGroupBudget(wg, funding_amount, BalanceKind::Negative).into(),
-        );
-    });
-}
-
 #[test]
 fn create_funding_request_proposal_call_fails_repeated_account() {
     initial_test_ext().execute_with(|| {

+ 1 - 10
runtime-modules/proposals/codex/src/types.rs

@@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
 use sp_std::vec::Vec;
 
 use common::working_group::WorkingGroup;
+use common::BalanceKind;
 use common::FundingRequestParameters;
 
 use working_group::StakePolicy;
@@ -27,16 +28,6 @@ pub type ProposalDetailsOf<T> = ProposalDetails<
     <T as proposals_engine::Trait>::ProposalId,
 >;
 
-/// Kind of Balance for `Update Working Group Budget`.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug, Eq)]
-pub enum BalanceKind {
-    /// Increasing Working Group budget decreasing Council budget
-    Positive,
-    /// Decreasing Working Group budget increasing Council budget
-    Negative,
-}
-
 /// Proposal details provide voters the information required for the perceived voting.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Debug, Eq)]

+ 44 - 0
runtime-modules/utilities/Cargo.toml

@@ -0,0 +1,44 @@
+[package]
+name = 'pallet-utilities'
+version = '1.0.0'
+authors = ['Joystream contributors']
+edition = '2018'
+
+[dependencies]
+serde = { version = "1.0.101", optional = true, features = ["derive"] }
+codec = { package = 'parity-scale-codec', version = '1.3.1', default-features = false, features = ['derive'] }
+sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+frame_system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
+council = { package = 'pallet-council', default-features = false, path = '../council'}
+common = { package = 'pallet-common', default-features = false, path = '../common'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+
+[dev-dependencies]
+sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+working-group = { package = 'pallet-working-group', default-features = false, path = '../working-group'}
+staking-handler = { package = 'pallet-staking-handler', default-features = false, path = '../staking-handler'}
+referendum = { package = 'pallet-referendum', default-features = false, path = '../referendum'}
+membership = { package = 'pallet-membership', default-features = false, path = '../membership'}
+pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+strum = {version = "0.19", default-features = false}
+
+[features]
+default = ['std']
+runtime-benchmarks = ["frame-benchmarking"]
+std = [
+    'serde',
+    'codec/std',
+    'sp-std/std',
+    'frame-support/std',
+    'frame_system/std',
+    'sp-runtime/std',
+    'common/std',
+    'council/std',
+    'balances/std',
+    'sp-arithmetic/std',
+]

+ 262 - 0
runtime-modules/utilities/src/benchmarking.rs

@@ -0,0 +1,262 @@
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+use frame_benchmarking::{account, benchmarks};
+use frame_system::Module as System;
+use frame_system::{EventRecord, RawOrigin};
+use sp_runtime::traits::One;
+use sp_std::boxed::Box;
+use sp_std::convert::TryInto;
+use sp_std::vec;
+use sp_std::vec::Vec;
+
+fn assert_last_event<T: Trait>(generic_event: <T as Trait>::Event) {
+    let events = System::<T>::events();
+    let system_event: <T as frame_system::Trait>::Event = generic_event.into();
+    // compare to the last event record
+    let EventRecord { event, .. } = &events[events.len() - 1];
+    assert_eq!(event, &system_event);
+}
+
+fn set_wg_and_council_budget<T: Trait>(budget: u32, group: WorkingGroup) {
+    Council::<T>::set_budget(RawOrigin::Root.into(), BalanceOf::<T>::from(budget)).unwrap();
+
+    T::set_working_group_budget(group, BalanceOf::<T>::from(budget));
+
+    assert_eq!(
+        Council::<T>::budget(),
+        BalanceOf::<T>::from(budget),
+        "Council budget not updated"
+    );
+
+    assert_eq!(
+        T::get_working_group_budget(group),
+        BalanceOf::<T>::from(budget),
+        "Working Group budget not updated"
+    );
+}
+
+fn assert_new_budgets<T: Trait>(
+    new_budget_council: u32,
+    new_budget_working_group: u32,
+    group: WorkingGroup,
+    amount: u32,
+    balance_kind: BalanceKind,
+) {
+    assert_eq!(
+        Council::<T>::budget(),
+        BalanceOf::<T>::from(new_budget_council),
+        "Council budget not updated"
+    );
+
+    assert_eq!(
+        T::get_working_group_budget(group),
+        BalanceOf::<T>::from(new_budget_working_group),
+        "Working Group budget not updated"
+    );
+
+    assert_last_event::<T>(
+        RawEvent::UpdatedWorkingGroupBudget(group, BalanceOf::<T>::from(amount), balance_kind)
+            .into(),
+    );
+}
+
+const MAX_BYTES: u32 = 50000;
+
+benchmarks! {
+    _{ }
+
+    execute_signal_proposal {
+        let i in 1 .. MAX_BYTES;
+        let signal = vec![0u8; i.try_into().unwrap()];
+    }: _(RawOrigin::Root, signal.clone())
+    verify {
+        assert_last_event::<T>(RawEvent::Signaled(signal).into());
+    }
+
+    update_working_group_budget_positive_forum {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Forum);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Forum,
+        One::one(),
+        BalanceKind::Positive
+    )
+    verify {
+        assert_new_budgets::<T>(99, 101, WorkingGroup::Forum, 1, BalanceKind::Positive);
+    }
+
+    update_working_group_budget_negative_forum {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Forum);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Forum,
+        One::one(),
+        BalanceKind::Negative
+    )
+    verify{
+        assert_new_budgets::<T>(101, 99, WorkingGroup::Forum, 1, BalanceKind::Negative);
+    }
+
+    update_working_group_budget_positive_storage {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Storage);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Storage,
+        One::one(),
+        BalanceKind::Positive
+    )
+    verify {
+        assert_new_budgets::<T>(99, 101, WorkingGroup::Storage, 1, BalanceKind::Positive);
+    }
+
+    update_working_group_budget_negative_storage {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Storage);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Storage,
+        One::one(),
+        BalanceKind::Negative
+    )
+    verify {
+        assert_new_budgets::<T>(101, 99, WorkingGroup::Storage, 1, BalanceKind::Negative);
+    }
+
+    update_working_group_budget_positive_content {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Content);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Content,
+        One::one(),
+        BalanceKind::Positive
+    )
+    verify {
+        assert_new_budgets::<T>(99, 101, WorkingGroup::Content, 1, BalanceKind::Positive);
+    }
+
+    update_working_group_budget_negative_content {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Content);
+    }: update_working_group_budget(RawOrigin::Root, WorkingGroup::Content, One::one(),
+    BalanceKind::Negative)
+    verify {
+        assert_new_budgets::<T>(101, 99, WorkingGroup::Content, 1, BalanceKind::Negative);
+    }
+
+    update_working_group_budget_positive_membership {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Membership);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Membership,
+        One::one(),
+        BalanceKind::Positive
+    )
+    verify {
+        assert_new_budgets::<T>(99, 101, WorkingGroup::Membership, 1, BalanceKind::Positive);
+    }
+
+    update_working_group_budget_negative_membership {
+        set_wg_and_council_budget::<T>(100, WorkingGroup::Membership);
+    }: update_working_group_budget(
+        RawOrigin::Root,
+        WorkingGroup::Membership,
+        One::one(),
+        BalanceKind::Negative
+    )
+    verify {
+        assert_new_budgets::<T>(101, 99, WorkingGroup::Membership, 1, BalanceKind::Negative);
+    }
+
+    burn_account_tokens {
+        let account_id = account::<T::AccountId>("caller", 0, 0);
+        let initial_issuance = Balances::<T>::total_issuance();
+        let _ = Balances::<T>::make_free_balance_be(&account_id, One::one());
+
+        assert_eq!(Balances::<T>::free_balance(&account_id), One::one());
+        assert_eq!(Balances::<T>::total_issuance(), initial_issuance + One::one());
+    }: _ (RawOrigin::Signed(account_id.clone()), One::one())
+    verify {
+        assert_eq!(Balances::<T>::free_balance(&account_id), Zero::zero());
+        assert_eq!(Balances::<T>::total_issuance(),  initial_issuance);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::tests::mocks::{initial_test_ext, Test};
+    use frame_support::assert_ok;
+
+    #[test]
+    fn test_execute_signal_proposal() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_execute_signal_proposal::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_positive_forum() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_positive_forum::<
+                Test,
+            >());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_negative_forum() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_negative_forum::<
+                Test,
+            >());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_positive_storage() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_positive_storage::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_negative_storage() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_negative_storage::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_positive_content() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_positive_content::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_negative_content() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_negative_content::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_positive_membership() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_positive_membership::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_working_group_budget_negative_membership() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_working_group_budget_negative_membership::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_burn_tokens() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_burn_account_tokens::<Test>());
+        });
+    }
+}

+ 266 - 0
runtime-modules/utilities/src/lib.rs

@@ -0,0 +1,266 @@
+//! # Constitution pallet.
+//! `Constitution` pallet for the Joystream platform. Version 1.
+//! It contains current constitution text hash and amendment number in the storage and extrinsic for
+//! setting the new constitution.
+//!
+
+// Ensure we're `no_std` when compiling for Wasm.
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(test)]
+pub(crate) mod tests;
+
+mod benchmarking;
+
+use common::{working_group::WorkingGroup, BalanceKind};
+use council::Module as Council;
+use frame_support::traits::Currency;
+use frame_support::traits::Get;
+use frame_support::weights::{DispatchClass, Weight};
+use frame_support::{decl_error, decl_event, decl_module, ensure, print};
+use frame_system::{ensure_root, ensure_signed};
+use sp_arithmetic::traits::Zero;
+use sp_runtime::traits::Saturating;
+use sp_runtime::SaturatedConversion;
+use sp_std::vec::Vec;
+
+type BalanceOf<T> = <T as balances::Trait>::Balance;
+type Balances<T> = balances::Module<T>;
+
+pub trait Trait: frame_system::Trait + balances::Trait + council::Trait {
+    type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
+
+    /// Gets the budget of the given WorkingGroup
+    fn get_working_group_budget(working_group: WorkingGroup) -> BalanceOf<Self>;
+
+    /// Sets the budget for the given WorkingGroup
+    fn set_working_group_budget(working_group: WorkingGroup, budget: BalanceOf<Self>);
+
+    /// Weight information for extrinsics in this pallet.
+    type WeightInfo: WeightInfo;
+}
+
+/// Utilities WeightInfo.
+/// Note: This was auto generated through the benchmark CLI using the `--weight-trait` flag
+pub trait WeightInfo {
+    fn execute_signal_proposal(i: u32) -> Weight;
+    fn update_working_group_budget_positive_forum() -> Weight;
+    fn update_working_group_budget_negative_forum() -> Weight;
+    fn update_working_group_budget_positive_storage() -> Weight;
+    fn update_working_group_budget_negative_storage() -> Weight;
+    fn update_working_group_budget_positive_content() -> Weight;
+    fn update_working_group_budget_negative_content() -> Weight;
+    fn update_working_group_budget_positive_membership() -> Weight;
+    fn update_working_group_budget_negative_membership() -> Weight;
+    fn burn_account_tokens() -> Weight;
+}
+
+type WeightInfoUtilities<T> = <T as Trait>::WeightInfo;
+
+decl_error! {
+    /// Codex module predefined errors
+    pub enum Error for Module<T: Trait> {
+        /// Insufficient funds for 'Update Working Group Budget' proposal execution
+        InsufficientFundsForBudgetUpdate,
+
+        /// Trying to burn zero tokens
+        ZeroTokensBurn,
+
+        /// Insufficient funds for burning
+        InsufficientFundsForBurn,
+    }
+}
+
+decl_event!(
+    pub enum Event<T>
+    where
+        Balance = BalanceOf<T>,
+        AccountId = <T as frame_system::Trait>::AccountId,
+    {
+        /// A signal proposal was executed
+        /// Params:
+        /// - Signal given when creating the corresponding proposal
+        Signaled(Vec<u8>),
+
+        /// A runtime upgrade was executed
+        /// Params:
+        /// - New code encoded in bytes
+        RuntimeUpgraded(Vec<u8>),
+
+        /// An `Update Working Group Budget` proposal was executed
+        /// Params:
+        /// - Working group which budget is being updated
+        /// - Amount of balance being moved
+        /// - Enum variant with positive indicating funds moved torwards working group and negative
+        /// and negative funds moving from the working group
+        UpdatedWorkingGroupBudget(WorkingGroup, Balance, BalanceKind),
+
+        /// An account burned tokens
+        /// Params:
+        /// - Account Id of the burning tokens
+        /// - Balance burned from that account
+        AccountBurned(AccountId, Balance),
+    }
+);
+
+decl_module! {
+    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+        fn deposit_event() = default;
+
+        /// Predefined errors
+        type Error = Error<T>;
+
+        /// Signal proposal extrinsic. Should be used as callable object to pass to the `engine` module.
+        ///
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (S)` where:
+        /// - `S` is the length of the signal
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = WeightInfoUtilities::<T>::execute_signal_proposal(signal.len().saturated_into())] // TODO: adjust weight
+        pub fn execute_signal_proposal(
+            origin,
+            signal: Vec<u8>,
+        ) {
+            ensure_root(origin)?;
+
+            // Signal proposal stub: no code implied.
+
+            Self::deposit_event(RawEvent::Signaled(signal));
+        }
+
+        /// Runtime upgrade proposal extrinsic.
+        /// Should be used as callable object to pass to the `engine` module.
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (C)` where:
+        /// - `C` is the length of `wasm`
+        /// However, we treat this as a full block as `frame_system::Module::set_code` does
+        /// # </weight>
+        #[weight = (T::MaximumBlockWeight::get(), DispatchClass::Operational)]
+        pub fn execute_runtime_upgrade_proposal(
+            origin,
+            wasm: Vec<u8>,
+        ) {
+            ensure_root(origin.clone())?;
+
+            print("Runtime upgrade proposal execution started.");
+
+            <frame_system::Module<T>>::set_code(origin, wasm.clone())?;
+
+            print("Runtime upgrade proposal execution finished.");
+
+            Self::deposit_event(RawEvent::RuntimeUpgraded(wasm));
+        }
+
+        /// Update working group budget
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (1)` Doesn't depend on the state or parameters
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = Module::<T>::get_update_working_group_budget_weight(&working_group, &balance_kind)] // TODO: adjust weight
+        pub fn update_working_group_budget(
+            origin,
+            working_group: WorkingGroup,
+            amount: BalanceOf<T>,
+            balance_kind: BalanceKind,
+        ) {
+            ensure_root(origin.clone())?;
+
+
+            let wg_budget = T::get_working_group_budget(working_group);
+            let current_budget = Council::<T>::budget();
+
+            match balance_kind {
+                BalanceKind::Positive => {
+                    ensure!(amount<=current_budget, Error::<T>::InsufficientFundsForBudgetUpdate);
+
+                    T::set_working_group_budget(working_group, wg_budget.saturating_add(amount));
+                    Council::<T>::set_budget(origin, current_budget - amount)?;
+                },
+                BalanceKind::Negative => {
+                    ensure!(amount <= wg_budget, Error::<T>::InsufficientFundsForBudgetUpdate);
+
+                    T::set_working_group_budget(working_group, wg_budget - amount);
+                    Council::<T>::set_budget(origin, current_budget.saturating_add(amount))?;
+                }
+            }
+
+            Self::deposit_event(RawEvent::UpdatedWorkingGroupBudget(working_group, amount, balance_kind));
+        }
+
+        /// Burns token for caller account
+        /// <weight>
+        ///
+        /// ## Weight
+        /// `O (1)` Doesn't depend on the state or parameters
+        /// - DB:
+        ///    - O(1) doesn't depend on the state or parameters
+        /// # </weight>
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn burn_account_tokens(
+            origin,
+            amount: BalanceOf<T>
+        ) {
+            let account_id = ensure_signed(origin)?;
+            ensure!(amount > Zero::zero(), Error::<T>::ZeroTokensBurn);
+            ensure!(
+                Balances::<T>::can_slash(&account_id, amount),
+                Error::<T>::InsufficientFundsForBurn
+            );
+
+            // == Mutation Safe == //
+
+            let _ = Balances::<T>::slash(&account_id, amount);
+
+            Self::deposit_event(RawEvent::AccountBurned(account_id, amount));
+        }
+
+    }
+}
+
+impl<T: Trait> Module<T> {
+    // Returns the weigt for update_working_group_budget extrinsic according to parameters
+    fn get_update_working_group_budget_weight(
+        group: &WorkingGroup,
+        balance_kind: &BalanceKind,
+    ) -> Weight {
+        match balance_kind {
+            BalanceKind::Positive => match group {
+                WorkingGroup::Forum => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_positive_forum()
+                }
+                WorkingGroup::Storage => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_positive_storage()
+                }
+                WorkingGroup::Content => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_positive_content()
+                }
+                WorkingGroup::Membership => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_positive_membership()
+                }
+            },
+            BalanceKind::Negative => match group {
+                WorkingGroup::Forum => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_negative_forum()
+                }
+                WorkingGroup::Storage => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_negative_storage()
+                }
+                WorkingGroup::Membership => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_negative_membership()
+                }
+                WorkingGroup::Content => {
+                    WeightInfoUtilities::<T>::update_working_group_budget_negative_content()
+                }
+            },
+        }
+    }
+}

+ 733 - 0
runtime-modules/utilities/src/tests/mocks.rs

@@ -0,0 +1,733 @@
+#![cfg(test)]
+
+pub(crate) use crate::Module as Utilities;
+use crate::*;
+use common::working_group::{WorkingGroup, WorkingGroupBudgetHandler};
+use frame_support::dispatch::DispatchError;
+use frame_support::traits::{LockIdentifier, OnFinalize, OnInitialize};
+use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
+use frame_system::RawOrigin;
+use frame_system::{EnsureOneOf, EnsureRoot, EnsureSigned};
+use sp_core::H256;
+use sp_runtime::DispatchResult;
+use sp_runtime::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    Perbill,
+};
+use staking_handler::{LockComparator, StakingManager};
+
+impl_outer_origin! {
+    pub enum Origin for Test {}
+}
+
+mod utilities {
+    pub use crate::Event;
+}
+
+impl_outer_event! {
+    pub enum TestEvent for Test {
+        utilities<T>,
+        frame_system<T>,
+        balances<T>,
+        council<T>,
+        membership<T>,
+        referendum Instance0 <T>,
+        working_group Instance0 <T>,
+        working_group Instance1 <T>,
+        working_group Instance2 <T>,
+        working_group Instance3 <T>,
+        working_group Instance4 <T>,
+    }
+}
+
+pub struct ReferendumWeightInfo;
+impl referendum::WeightInfo for ReferendumWeightInfo {
+    fn on_initialize_revealing(_: u32) -> Weight {
+        0
+    }
+    fn on_initialize_voting() -> Weight {
+        0
+    }
+    fn vote() -> Weight {
+        0
+    }
+    fn reveal_vote_space_for_new_winner(_: u32) -> Weight {
+        0
+    }
+    fn reveal_vote_space_not_in_winners(_: u32) -> Weight {
+        0
+    }
+    fn reveal_vote_space_replace_last_winner(_: u32) -> Weight {
+        0
+    }
+    fn reveal_vote_already_existing(_: u32) -> Weight {
+        0
+    }
+    fn release_vote_stake() -> Weight {
+        0
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Test;
+
+parameter_types! {
+    pub const ExistentialDeposit: u32 = 0;
+}
+
+impl balances::Trait for Test {
+    type Balance = u64;
+    type DustRemoval = ();
+    type Event = TestEvent;
+    type ExistentialDeposit = ExistentialDeposit;
+    type AccountStore = System;
+    type WeightInfo = ();
+    type MaxLocks = ();
+}
+
+parameter_types! {
+    pub const BlockHashCount: u64 = 250;
+    pub const MaximumBlockWeight: u32 = 1024;
+    pub const MaximumBlockLength: u32 = 2 * 1024;
+    pub const AvailableBlockRatio: Perbill = Perbill::one();
+}
+
+macro_rules! call_wg {
+    ($working_group:ident<$T:ty>, $function:ident $(,$x:expr)*) => {{
+        match $working_group {
+            WorkingGroup::Content =>
+                <working_group::Module::<$T, ContentDirectoryWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
+
+            WorkingGroup::Storage =>
+                <working_group::Module::<$T, StorageWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
+
+            WorkingGroup::Forum =>
+                <working_group::Module::<$T, ForumWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
+
+            WorkingGroup::Membership =>
+                <working_group::Module::<$T, MembershipWorkingGroupInstance> as WorkingGroupBudgetHandler<Test>>::$function($($x,)*),
+        }
+    }};
+}
+
+// The forum working group instance alias.
+pub type ForumWorkingGroupInstance = working_group::Instance1;
+
+// The storage working group instance alias.
+pub type StorageWorkingGroupInstance = working_group::Instance2;
+
+// The content directory working group instance alias.
+pub type ContentDirectoryWorkingGroupInstance = working_group::Instance3;
+
+// The membership working group instance alias.
+pub type MembershipWorkingGroupInstance = working_group::Instance4;
+
+impl frame_system::Trait for Test {
+    type BaseCallFilter = ();
+    type Origin = Origin;
+    type Call = ();
+    type Index = u64;
+    type BlockNumber = u64;
+    type Hash = H256;
+    type Hashing = BlakeTwo256;
+    type AccountId = u64;
+    type Lookup = IdentityLookup<Self::AccountId>;
+    type Header = Header;
+    type Event = TestEvent;
+    type BlockHashCount = BlockHashCount;
+    type MaximumBlockWeight = MaximumBlockWeight;
+    type DbWeight = ();
+    type BlockExecutionWeight = ();
+    type ExtrinsicBaseWeight = ();
+    type MaximumExtrinsicWeight = ();
+    type MaximumBlockLength = MaximumBlockLength;
+    type AvailableBlockRatio = AvailableBlockRatio;
+    type Version = ();
+    type AccountData = balances::AccountData<u64>;
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+    type PalletInfo = ();
+    type SystemWeightInfo = ();
+}
+
+impl Trait for Test {
+    type Event = TestEvent;
+
+    type WeightInfo = ();
+
+    fn get_working_group_budget(working_group: WorkingGroup) -> BalanceOf<Test> {
+        call_wg!(working_group<Test>, get_budget)
+    }
+
+    fn set_working_group_budget(working_group: WorkingGroup, budget: BalanceOf<Test>) {
+        call_wg!(working_group<Test>, set_budget, budget)
+    }
+}
+
+impl WeightInfo for () {
+    fn execute_signal_proposal(_: u32) -> Weight {
+        0
+    }
+    fn update_working_group_budget_positive_forum() -> Weight {
+        0
+    }
+    fn update_working_group_budget_negative_forum() -> Weight {
+        0
+    }
+    fn update_working_group_budget_positive_storage() -> Weight {
+        0
+    }
+    fn update_working_group_budget_negative_storage() -> Weight {
+        0
+    }
+    fn update_working_group_budget_positive_content() -> Weight {
+        0
+    }
+    fn update_working_group_budget_negative_content() -> Weight {
+        0
+    }
+    fn update_working_group_budget_positive_membership() -> Weight {
+        0
+    }
+    fn update_working_group_budget_negative_membership() -> Weight {
+        0
+    }
+    fn burn_account_tokens() -> Weight {
+        0
+    }
+}
+
+parameter_types! {
+    pub const MinimumPeriod: u64 = 5;
+}
+
+impl pallet_timestamp::Trait for Test {
+    type Moment = u64;
+    type OnTimestampSet = ();
+    type MinimumPeriod = MinimumPeriod;
+    type WeightInfo = ();
+}
+
+parameter_types! {
+    pub const DefaultMembershipPrice: u64 = 100;
+    pub const InvitedMemberLockId: [u8; 8] = [2; 8];
+}
+
+impl membership::Trait for Test {
+    type Event = TestEvent;
+    type DefaultMembershipPrice = DefaultMembershipPrice;
+    type WorkingGroup = ();
+    type WeightInfo = Weights;
+    type DefaultInitialInvitationBalance = ();
+    type InvitedMemberStakingHandler = staking_handler::StakingManager<Self, InvitedMemberLockId>;
+}
+
+impl common::working_group::WorkingGroupBudgetHandler<Test> for () {
+    fn get_budget() -> u64 {
+        unimplemented!()
+    }
+
+    fn set_budget(_new_value: u64) {
+        unimplemented!()
+    }
+}
+
+impl common::working_group::WorkingGroupAuthenticator<Test> for () {
+    fn ensure_worker_origin(
+        _origin: <Test as frame_system::Trait>::Origin,
+        _worker_id: &<Test as common::Trait>::ActorId,
+    ) -> DispatchResult {
+        unimplemented!();
+    }
+
+    fn ensure_leader_origin(_origin: <Test as frame_system::Trait>::Origin) -> DispatchResult {
+        unimplemented!()
+    }
+
+    fn get_leader_member_id() -> Option<<Test as common::Trait>::MemberId> {
+        unimplemented!();
+    }
+
+    fn is_leader_account_id(_account_id: &<Test as frame_system::Trait>::AccountId) -> bool {
+        unimplemented!()
+    }
+
+    fn is_worker_account_id(
+        _account_id: &<Test as frame_system::Trait>::AccountId,
+        _worker_id: &<Test as common::Trait>::ActorId,
+    ) -> bool {
+        unimplemented!()
+    }
+}
+
+pub struct Weights;
+impl membership::WeightInfo for Weights {
+    fn buy_membership_without_referrer(_: u32, _: u32, _: u32, _: u32) -> Weight {
+        unimplemented!()
+    }
+    fn buy_membership_with_referrer(_: u32, _: u32, _: u32, _: u32) -> Weight {
+        unimplemented!()
+    }
+    fn update_profile(_: u32) -> Weight {
+        unimplemented!()
+    }
+    fn update_accounts_none() -> Weight {
+        unimplemented!()
+    }
+    fn update_accounts_root() -> Weight {
+        unimplemented!()
+    }
+    fn update_accounts_controller() -> Weight {
+        unimplemented!()
+    }
+    fn update_accounts_both() -> Weight {
+        unimplemented!()
+    }
+    fn set_referral_cut() -> Weight {
+        unimplemented!()
+    }
+    fn transfer_invites() -> Weight {
+        unimplemented!()
+    }
+    fn invite_member(_: u32, _: u32, _: u32, _: u32) -> Weight {
+        unimplemented!()
+    }
+    fn set_membership_price() -> Weight {
+        unimplemented!()
+    }
+    fn update_profile_verification() -> Weight {
+        unimplemented!()
+    }
+    fn set_leader_invitation_quota() -> Weight {
+        unimplemented!()
+    }
+    fn set_initial_invitation_balance() -> Weight {
+        unimplemented!()
+    }
+    fn set_initial_invitation_count() -> Weight {
+        unimplemented!()
+    }
+    fn add_staking_account_candidate() -> Weight {
+        unimplemented!()
+    }
+    fn confirm_staking_account() -> Weight {
+        unimplemented!()
+    }
+    fn remove_staking_account() -> Weight {
+        unimplemented!()
+    }
+}
+
+parameter_types! {
+    pub const MaxWorkerNumberLimit: u32 = 100;
+    pub const LockId1: [u8; 8] = [1; 8];
+    pub const LockId2: [u8; 8] = [2; 8];
+}
+
+pub struct WorkingGroupWeightInfo;
+impl working_group::Trait<ContentDirectoryWorkingGroupInstance> for Test {
+    type Event = TestEvent;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+    type StakingHandler = StakingManager<Self, LockId1>;
+    type StakingAccountValidator = membership::Module<Test>;
+    type MemberOriginValidator = ();
+    type MinUnstakingPeriodLimit = ();
+    type RewardPeriod = ();
+    type WeightInfo = WorkingGroupWeightInfo;
+}
+
+impl working_group::WeightInfo for WorkingGroupWeightInfo {
+    fn on_initialize_leaving(_: u32) -> Weight {
+        0
+    }
+    fn on_initialize_rewarding_with_missing_reward(_: u32) -> Weight {
+        0
+    }
+    fn on_initialize_rewarding_with_missing_reward_cant_pay(_: u32) -> Weight {
+        0
+    }
+    fn on_initialize_rewarding_without_missing_reward(_: u32) -> Weight {
+        0
+    }
+    fn apply_on_opening(_: u32) -> Weight {
+        0
+    }
+    fn fill_opening_lead() -> Weight {
+        0
+    }
+    fn fill_opening_worker(_: u32) -> Weight {
+        0
+    }
+    fn update_role_account() -> Weight {
+        0
+    }
+    fn cancel_opening() -> Weight {
+        0
+    }
+    fn withdraw_application() -> Weight {
+        0
+    }
+    fn slash_stake(_: u32) -> Weight {
+        0
+    }
+    fn terminate_role_worker(_: u32) -> Weight {
+        0
+    }
+    fn terminate_role_lead(_: u32) -> Weight {
+        0
+    }
+    fn increase_stake() -> Weight {
+        0
+    }
+    fn decrease_stake() -> Weight {
+        0
+    }
+    fn spend_from_budget() -> Weight {
+        0
+    }
+    fn update_reward_amount() -> Weight {
+        0
+    }
+    fn set_status_text(_: u32) -> Weight {
+        0
+    }
+    fn update_reward_account() -> Weight {
+        0
+    }
+    fn set_budget() -> Weight {
+        0
+    }
+    fn add_opening(_: u32) -> Weight {
+        0
+    }
+    fn leave_role_immediatly() -> Weight {
+        0
+    }
+    fn leave_role_later() -> Weight {
+        0
+    }
+}
+
+impl working_group::Trait<StorageWorkingGroupInstance> for Test {
+    type Event = TestEvent;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+    type StakingHandler = StakingManager<Self, LockId2>;
+    type StakingAccountValidator = membership::Module<Test>;
+    type MemberOriginValidator = ();
+    type MinUnstakingPeriodLimit = ();
+    type RewardPeriod = ();
+    type WeightInfo = WorkingGroupWeightInfo;
+}
+
+impl working_group::Trait<ForumWorkingGroupInstance> for Test {
+    type Event = TestEvent;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+    type StakingHandler = staking_handler::StakingManager<Self, LockId2>;
+    type StakingAccountValidator = membership::Module<Test>;
+    type MemberOriginValidator = ();
+    type MinUnstakingPeriodLimit = ();
+    type RewardPeriod = ();
+    type WeightInfo = WorkingGroupWeightInfo;
+}
+
+impl working_group::Trait<MembershipWorkingGroupInstance> for Test {
+    type Event = TestEvent;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+    type StakingHandler = StakingManager<Self, LockId2>;
+    type StakingAccountValidator = membership::Module<Test>;
+    type MemberOriginValidator = ();
+    type MinUnstakingPeriodLimit = ();
+    type RewardPeriod = ();
+    type WeightInfo = WorkingGroupWeightInfo;
+}
+
+parameter_types! {
+    pub const MinNumberOfExtraCandidates: u64 = 1;
+    pub const AnnouncingPeriodDuration: u64 = 15;
+    pub const IdlePeriodDuration: u64 = 27;
+    pub const CouncilSize: u64 = 3;
+    pub const MinCandidateStake: u64 = 11000;
+    pub const CandidacyLockId: LockIdentifier = *b"council1";
+    pub const CouncilorLockId: LockIdentifier = *b"council2";
+    pub const ElectedMemberRewardPeriod: u64 = 10;
+    pub const BudgetRefillAmount: u64 = 1000;
+    // intentionally high number that prevents side-effecting tests other than  budget refill tests
+    pub const BudgetRefillPeriod: u64 = 1000;
+}
+
+pub struct CouncilWeightInfo;
+impl council::WeightInfo for CouncilWeightInfo {
+    fn try_process_budget() -> Weight {
+        0
+    }
+    fn try_progress_stage_idle() -> Weight {
+        0
+    }
+    fn try_progress_stage_announcing_start_election(_: u32) -> Weight {
+        0
+    }
+    fn try_progress_stage_announcing_restart() -> Weight {
+        0
+    }
+    fn announce_candidacy() -> Weight {
+        0
+    }
+    fn release_candidacy_stake() -> Weight {
+        0
+    }
+    fn set_candidacy_note(_: u32) -> Weight {
+        0
+    }
+    fn withdraw_candidacy() -> Weight {
+        0
+    }
+    fn set_budget() -> Weight {
+        0
+    }
+    fn plan_budget_refill() -> Weight {
+        0
+    }
+    fn set_budget_increment() -> Weight {
+        0
+    }
+    fn set_councilor_reward() -> Weight {
+        0
+    }
+    fn funding_request(_: u32) -> Weight {
+        0
+    }
+}
+
+pub type ReferendumInstance = referendum::Instance0;
+
+parameter_types! {
+    pub const VoteStageDuration: u64 = 19;
+    pub const RevealStageDuration: u64 = 23;
+    pub const MinimumVotingStake: u64 = 10000;
+    pub const MaxSaltLength: u64 = 32; // use some multiple of 8 for ez testing
+    pub const VotingLockId: LockIdentifier = *b"referend";
+    pub const MaxWinnerTargetCount: u64 = 10;
+}
+
+impl referendum::Trait<ReferendumInstance> for Test {
+    type Event = TestEvent;
+
+    type MaxSaltLength = MaxSaltLength;
+
+    type StakingHandler = staking_handler::StakingManager<Self, VotingLockId>;
+    type ManagerOrigin =
+        EnsureOneOf<Self::AccountId, EnsureSigned<Self::AccountId>, EnsureRoot<Self::AccountId>>;
+
+    type VotePower = u64;
+
+    type VoteStageDuration = VoteStageDuration;
+    type RevealStageDuration = RevealStageDuration;
+
+    type MinimumStake = MinimumVotingStake;
+
+    type WeightInfo = ReferendumWeightInfo;
+
+    type MaxWinnerTargetCount = MaxWinnerTargetCount;
+
+    fn calculate_vote_power(
+        _: &<Self as frame_system::Trait>::AccountId,
+        _: &Self::Balance,
+    ) -> Self::VotePower {
+        1
+    }
+
+    fn can_unlock_vote_stake(
+        _: &referendum::CastVote<Self::Hash, Self::Balance, Self::MemberId>,
+    ) -> bool {
+        true
+    }
+
+    fn process_results(winners: &[referendum::OptionResult<Self::MemberId, Self::VotePower>]) {
+        let tmp_winners: Vec<referendum::OptionResult<Self::MemberId, Self::VotePower>> = winners
+            .iter()
+            .map(|item| referendum::OptionResult {
+                option_id: item.option_id,
+                vote_power: item.vote_power.into(),
+            })
+            .collect();
+        <council::Module<Test> as council::ReferendumConnection<Test>>::recieve_referendum_results(
+            tmp_winners.as_slice(),
+        );
+    }
+
+    fn is_valid_option_id(option_index: &u64) -> bool {
+        <council::Module<Test> as council::ReferendumConnection<Test>>::is_valid_candidate_id(
+            option_index,
+        )
+    }
+
+    fn get_option_power(option_id: &u64) -> Self::VotePower {
+        <council::Module<Test> as council::ReferendumConnection<Test>>::get_option_power(option_id)
+    }
+
+    fn increase_option_power(option_id: &u64, amount: &Self::VotePower) {
+        <council::Module<Test> as council::ReferendumConnection<Test>>::increase_option_power(
+            option_id, amount,
+        );
+    }
+}
+
+pub struct BurnTokensFixture {
+    account_id: u64,
+    account_initial_balance: u64,
+    burn_balance: u64,
+}
+
+impl Default for BurnTokensFixture {
+    fn default() -> Self {
+        BurnTokensFixture {
+            account_id: 0,
+            account_initial_balance: 1_000,
+            burn_balance: 100,
+        }
+    }
+}
+
+impl BurnTokensFixture {
+    pub fn with_account_initial_balance(mut self, balance: u64) -> Self {
+        self.account_initial_balance = balance;
+        self
+    }
+
+    pub fn with_burn_balance(mut self, balance: u64) -> Self {
+        self.burn_balance = balance;
+        self
+    }
+
+    pub fn execute_and_assert(&self, result: DispatchResult) {
+        let initial_balance: u64 = Balances::<Test>::total_issuance();
+
+        let _ = Balances::<Test>::deposit_creating(&self.account_id, self.account_initial_balance);
+        assert_eq!(
+            Balances::<Test>::total_issuance(),
+            initial_balance + self.account_initial_balance
+        );
+        assert_eq!(
+            Balances::<Test>::usable_balance(&self.account_id),
+            self.account_initial_balance
+        );
+        assert_eq!(
+            Utilities::<Test>::burn_account_tokens(
+                RawOrigin::Signed(self.account_id).into(),
+                self.burn_balance
+            ),
+            result
+        );
+        if result.is_ok() {
+            assert_eq!(
+                Balances::<Test>::usable_balance(&self.account_id),
+                self.account_initial_balance - self.burn_balance
+            );
+            assert_eq!(
+                Balances::<Test>::total_issuance(),
+                initial_balance + self.account_initial_balance - self.burn_balance
+            );
+        } else {
+            assert_eq!(
+                Balances::<Test>::usable_balance(&self.account_id),
+                self.account_initial_balance
+            );
+            assert_eq!(
+                Balances::<Test>::total_issuance(),
+                initial_balance + self.account_initial_balance
+            );
+        }
+    }
+}
+
+impl council::Trait for Test {
+    type Event = TestEvent;
+
+    type Referendum = referendum::Module<Test, ReferendumInstance>;
+
+    type MinNumberOfExtraCandidates = MinNumberOfExtraCandidates;
+    type CouncilSize = CouncilSize;
+    type AnnouncingPeriodDuration = AnnouncingPeriodDuration;
+    type IdlePeriodDuration = IdlePeriodDuration;
+    type MinCandidateStake = MinCandidateStake;
+
+    type CandidacyLock = StakingManager<Self, CandidacyLockId>;
+    type CouncilorLock = StakingManager<Self, CouncilorLockId>;
+
+    type ElectedMemberRewardPeriod = ElectedMemberRewardPeriod;
+
+    type BudgetRefillPeriod = BudgetRefillPeriod;
+
+    type StakingAccountValidator = ();
+    type WeightInfo = CouncilWeightInfo;
+
+    fn new_council_elected(_: &[council::CouncilMemberOf<Self>]) {}
+
+    type MemberOriginValidator = ();
+}
+
+impl common::StakingAccountValidator<Test> for () {
+    fn is_member_staking_account(_: &u64, _: &u64) -> bool {
+        true
+    }
+}
+
+impl common::origin::MemberOriginValidator<Origin, u64, u64> for () {
+    fn ensure_member_controller_account_origin(
+        origin: Origin,
+        _: u64,
+    ) -> Result<u64, DispatchError> {
+        let account_id = frame_system::ensure_signed(origin)?;
+
+        Ok(account_id)
+    }
+
+    fn is_member_controller_account(member_id: &u64, account_id: &u64) -> bool {
+        member_id == account_id
+    }
+}
+
+impl common::origin::CouncilOriginValidator<Origin, u64, u64> for () {
+    fn ensure_member_consulate(origin: Origin, _: u64) -> DispatchResult {
+        frame_system::ensure_signed(origin)?;
+
+        Ok(())
+    }
+}
+
+impl common::Trait for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
+impl LockComparator<<Test as balances::Trait>::Balance> for Test {
+    fn are_locks_conflicting(
+        _new_lock: &LockIdentifier,
+        _existing_locks: &[LockIdentifier],
+    ) -> bool {
+        false
+    }
+}
+
+pub fn initial_test_ext() -> sp_io::TestExternalities {
+    let t = frame_system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    let mut result = Into::<sp_io::TestExternalities>::into(t.clone());
+
+    // Make sure we are not in block 1 where no events are emitted
+    // see https://substrate.dev/recipes/2-appetizers/4-events.html#emitting-events
+    result.execute_with(|| {
+        let mut block_number = frame_system::Module::<Test>::block_number();
+        <System as OnFinalize<u64>>::on_finalize(block_number);
+        block_number = block_number + 1;
+        System::set_block_number(block_number);
+        <System as OnInitialize<u64>>::on_initialize(block_number);
+    });
+
+    result
+}
+
+pub type System = frame_system::Module<Test>;

+ 219 - 0
runtime-modules/utilities/src/tests/mod.rs

@@ -0,0 +1,219 @@
+#![cfg(test)]
+
+pub(crate) mod mocks;
+
+use crate::*;
+use frame_system::{EventRecord, RawOrigin};
+use mocks::{initial_test_ext, BurnTokensFixture, System, Test, Utilities};
+use sp_arithmetic::traits::{One, Zero};
+use sp_runtime::DispatchError;
+use strum::IntoEnumIterator;
+
+fn assert_last_event(generic_event: <Test as Trait>::Event) {
+    let events = System::events();
+    let system_event: <Test as frame_system::Trait>::Event = generic_event.into();
+    assert!(
+        events.len() > 0,
+        "If you are checking for last event there must be at least 1 event"
+    );
+
+    let EventRecord { event, .. } = &events[events.len() - 1];
+    assert_eq!(event, &system_event);
+}
+
+#[test]
+fn execute_signal_proposal_fails() {
+    initial_test_ext().execute_with(|| {
+        assert_eq!(
+            Utilities::<Test>::execute_signal_proposal(RawOrigin::Signed(0).into(), vec![0]),
+            Err(DispatchError::BadOrigin)
+        );
+    });
+}
+
+#[test]
+fn execute_signal_proposal_succeds() {
+    initial_test_ext().execute_with(|| {
+        let signal = vec![0];
+        assert_eq!(
+            Utilities::<Test>::execute_signal_proposal(RawOrigin::Root.into(), signal.clone()),
+            Ok(())
+        );
+
+        assert_last_event(RawEvent::Signaled(signal).into());
+    });
+}
+
+#[test]
+fn execute_runtime_upgrade_proposal_fails() {
+    initial_test_ext().execute_with(|| {
+        assert_eq!(
+            Utilities::<Test>::execute_runtime_upgrade_proposal(
+                RawOrigin::Signed(0).into(),
+                vec![0]
+            ),
+            Err(DispatchError::BadOrigin)
+        );
+    });
+}
+
+#[test]
+fn update_working_group_budget_fails_permissions() {
+    for wg in WorkingGroup::iter() {
+        run_update_working_group_budget_fails_permissions(wg);
+    }
+}
+
+fn run_update_working_group_budget_fails_permissions(wg: WorkingGroup) {
+    initial_test_ext().execute_with(|| {
+        assert_eq!(
+            Utilities::<Test>::update_working_group_budget(
+                RawOrigin::Signed(0).into(),
+                wg,
+                Zero::zero(),
+                BalanceKind::Positive
+            ),
+            Err(DispatchError::BadOrigin)
+        );
+    });
+}
+
+#[test]
+fn update_working_group_budget_fails_positive() {
+    for wg in WorkingGroup::iter() {
+        run_update_working_group_budget_fails_positive(wg);
+    }
+}
+
+fn run_update_working_group_budget_fails_positive(wg: WorkingGroup) {
+    initial_test_ext().execute_with(|| {
+        assert_eq!(council::Module::<Test>::budget(), 0);
+        assert_eq!(
+            Utilities::<Test>::update_working_group_budget(
+                RawOrigin::Root.into(),
+                wg,
+                One::one(),
+                BalanceKind::Positive
+            ),
+            Err(Error::<Test>::InsufficientFundsForBudgetUpdate.into())
+        );
+    });
+}
+
+#[test]
+fn update_working_group_budget_fails_negative() {
+    for wg in WorkingGroup::iter() {
+        run_update_working_group_budget_fails_negative(wg);
+    }
+}
+
+fn run_update_working_group_budget_fails_negative(wg: WorkingGroup) {
+    initial_test_ext().execute_with(|| {
+        assert_eq!(<Test as Trait>::get_working_group_budget(wg), 0);
+        assert_eq!(
+            Utilities::<Test>::update_working_group_budget(
+                RawOrigin::Root.into(),
+                wg,
+                One::one(),
+                BalanceKind::Negative
+            ),
+            Err(Error::<Test>::InsufficientFundsForBudgetUpdate.into())
+        );
+    });
+}
+
+#[test]
+fn update_working_group_budget_succeeds_positive() {
+    for wg in WorkingGroup::iter() {
+        run_update_working_group_budget_succeeds_positive(wg);
+    }
+}
+
+fn run_update_working_group_budget_succeeds_positive(wg: WorkingGroup) {
+    initial_test_ext().execute_with(|| {
+        let budget = 100000;
+        let funding_amount = 1;
+        council::Module::<Test>::set_budget(RawOrigin::Root.into(), budget).unwrap();
+        assert_eq!(council::Module::<Test>::budget(), budget);
+        assert_eq!(<Test as Trait>::get_working_group_budget(wg), 0);
+        assert_eq!(
+            Utilities::<Test>::update_working_group_budget(
+                RawOrigin::Root.into(),
+                wg,
+                funding_amount,
+                BalanceKind::Positive
+            ),
+            Ok(())
+        );
+
+        assert_eq!(council::Module::<Test>::budget(), budget - funding_amount);
+        assert_eq!(
+            <Test as Trait>::get_working_group_budget(wg),
+            funding_amount
+        );
+        assert_last_event(
+            RawEvent::UpdatedWorkingGroupBudget(wg, funding_amount, BalanceKind::Positive).into(),
+        );
+    });
+}
+
+#[test]
+fn update_working_group_budget_succeeds_negative() {
+    for wg in WorkingGroup::iter() {
+        run_update_working_group_budget_succeeds_negative(wg);
+    }
+}
+
+fn run_update_working_group_budget_succeeds_negative(wg: WorkingGroup) {
+    initial_test_ext().execute_with(|| {
+        let budget = 100000;
+        let funding_amount = 1;
+        <Test as Trait>::set_working_group_budget(wg, budget);
+        assert_eq!(council::Module::<Test>::budget(), 0);
+        assert_eq!(<Test as Trait>::get_working_group_budget(wg), budget);
+
+        assert_eq!(
+            Utilities::<Test>::update_working_group_budget(
+                RawOrigin::Root.into(),
+                wg,
+                funding_amount,
+                BalanceKind::Negative,
+            ),
+            Ok(())
+        );
+
+        assert_eq!(council::Module::<Test>::budget(), funding_amount);
+        assert_eq!(
+            <Test as Trait>::get_working_group_budget(wg),
+            budget - funding_amount
+        );
+        assert_last_event(
+            RawEvent::UpdatedWorkingGroupBudget(wg, funding_amount, BalanceKind::Negative).into(),
+        );
+    });
+}
+
+#[test]
+fn burn_account_tokens_succeeds() {
+    initial_test_ext().execute_with(|| {
+        BurnTokensFixture::default().execute_and_assert(Ok(()));
+    });
+}
+
+#[test]
+fn burn_account_tokens_fails_zero() {
+    initial_test_ext().execute_with(|| {
+        BurnTokensFixture::default()
+            .with_burn_balance(0)
+            .execute_and_assert(Err(Error::<Test>::ZeroTokensBurn.into()));
+    });
+}
+
+#[test]
+fn burn_account_tokens_fails_insufficient() {
+    initial_test_ext().execute_with(|| {
+        BurnTokensFixture::default()
+            .with_account_initial_balance(0)
+            .execute_and_assert(Err(Error::<Test>::InsufficientFundsForBurn.into()));
+    });
+}

+ 3 - 0
runtime/Cargo.toml

@@ -79,6 +79,7 @@ content-directory = { package = 'pallet-content-directory', default-features = f
 pallet_constitution = { package = 'pallet-constitution', default-features = false, path = '../runtime-modules/constitution' }
 staking-handler = { package = 'pallet-staking-handler', default-features = false, path = '../runtime-modules/staking-handler'}
 blog = { package = 'pallet-blog', default-features = false, path = '../runtime-modules/blog'}
+utilities = { package = 'pallet-utilities', default-features = false, path = '../runtime-modules/utilities'}
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
@@ -153,6 +154,7 @@ std = [
     'pallet_constitution/std',
     'staking-handler/std',
     'blog/std',
+    'utilities/std'
 ]
 runtime-benchmarks = [
     "frame-system/runtime-benchmarks",
@@ -169,6 +171,7 @@ runtime-benchmarks = [
     "proposals-discussion/runtime-benchmarks",
     "proposals-engine/runtime-benchmarks",
     "proposals-codex/runtime-benchmarks",
+    "utilities/runtime-benchmarks",
     "pallet_constitution/runtime-benchmarks",
     "working-group/runtime-benchmarks",
     "forum/runtime-benchmarks",

+ 5 - 5
runtime/src/integration/proposals/proposal_encoder.rs

@@ -34,7 +34,7 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
     fn encode_proposal(proposal_details: ProposalDetailsOf<Runtime>) -> Vec<u8> {
         let call = match proposal_details {
             ProposalDetails::Signal(signal) => {
-                Call::ProposalsCodex(proposals_codex::Call::execute_signal_proposal(signal))
+                Call::Utilities(utilities::Call::execute_signal_proposal(signal))
             }
             ProposalDetails::FundingRequest(params) => {
                 Call::Council(council::Call::funding_request(params))
@@ -42,9 +42,9 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
             ProposalDetails::SetMaxValidatorCount(new_validator_count) => Call::Staking(
                 pallet_staking::Call::set_validator_count(new_validator_count),
             ),
-            ProposalDetails::RuntimeUpgrade(blob) => Call::ProposalsCodex(
-                proposals_codex::Call::execute_runtime_upgrade_proposal(blob),
-            ),
+            ProposalDetails::RuntimeUpgrade(blob) => {
+                Call::Utilities(utilities::Call::execute_runtime_upgrade_proposal(blob))
+            }
             ProposalDetails::CreateWorkingGroupLeadOpening(create_opening_params) => {
                 wrap_working_group_call!(
                     create_opening_params.group,
@@ -58,7 +58,7 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
                 )
             }
             ProposalDetails::UpdateWorkingGroupBudget(amount, working_group, balance_kind) => {
-                Call::ProposalsCodex(proposals_codex::Call::update_working_group_budget(
+                Call::Utilities(utilities::Call::update_working_group_budget(
                     working_group,
                     amount,
                     balance_kind,

+ 25 - 17
runtime/src/lib.rs

@@ -806,6 +806,17 @@ parameter_types! {
     pub const MaxWhiteListSize: u32 = 20;
 }
 
+macro_rules! call_wg {
+    ($working_group:ident, $function:ident $(,$x:expr)*) => {{
+        match $working_group {
+            WorkingGroup::Content => <ContentDirectoryWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
+            WorkingGroup::Storage => <StorageWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
+            WorkingGroup::Forum => <ForumWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
+            WorkingGroup::Membership => <MembershipWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
+        }
+    }};
+}
+
 impl proposals_discussion::Trait for Runtime {
     type Event = Event;
     type AuthorOriginValidator = Members;
@@ -816,19 +827,21 @@ impl proposals_discussion::Trait for Runtime {
     type WeightInfo = weights::proposals_discussion::WeightInfo;
 }
 
-parameter_types! {
-    pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 3_000_000;
+impl utilities::Trait for Runtime {
+    type Event = Event;
+
+    type WeightInfo = weights::utilities::WeightInfo;
+
+    fn get_working_group_budget(working_group: WorkingGroup) -> Balance {
+        call_wg!(working_group, get_budget)
+    }
+    fn set_working_group_budget(working_group: WorkingGroup, budget: Balance) {
+        call_wg!(working_group, set_budget, budget)
+    }
 }
 
-macro_rules! call_wg {
-    ($working_group:ident, $function:ident $(,$x:expr)*) => {{
-        match $working_group {
-            WorkingGroup::Content => <ContentDirectoryWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
-            WorkingGroup::Storage => <StorageWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
-            WorkingGroup::Forum => <ForumWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
-            WorkingGroup::Membership => <MembershipWorkingGroup as WorkingGroupBudgetHandler<Runtime>>::$function($($x,)*),
-        }
-    }};
+parameter_types! {
+    pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 3_000_000;
 }
 
 impl proposals_codex::Trait for Runtime {
@@ -867,12 +880,6 @@ impl proposals_codex::Trait for Runtime {
     type UnlockBlogPostProposalParameters = UnlockBlogPostProposalParameters;
     type VetoProposalProposalParameters = VetoProposalProposalParameters;
     type WeightInfo = weights::proposals_codex::WeightInfo;
-    fn get_working_group_budget(working_group: WorkingGroup) -> Balance {
-        call_wg!(working_group, get_budget)
-    }
-    fn set_working_group_budget(working_group: WorkingGroup, budget: Balance) {
-        call_wg!(working_group, set_budget, budget)
-    }
 }
 
 impl pallet_constitution::Trait for Runtime {
@@ -950,6 +957,7 @@ construct_runtime!(
         ContentDirectory: content_directory::{Module, Call, Storage, Event<T>, Config<T>},
         Constitution: pallet_constitution::{Module, Call, Storage, Event},
         Blog: blog::<Instance1>::{Module, Call, Storage, Event<T>},
+        Utilities: utilities::{Module, Call, Event<T>},
         // --- Storage
         DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
         DataDirectory: data_directory::{Module, Call, Storage, Event<T>},

+ 2 - 0
runtime/src/runtime_api.rs

@@ -295,6 +295,7 @@ impl_runtime_apis! {
             use crate::Council;
             use crate::Referendum;
             use crate::Blog;
+            use crate::Utilities;
 
 
             // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency issues.
@@ -385,6 +386,7 @@ impl_runtime_apis! {
             add_benchmark!(params, batches, referendum, Referendum);
             add_benchmark!(params, batches, council, Council);
             add_benchmark!(params, batches, blog, Blog);
+            add_benchmark!(params, batches, utilities, Utilities);
 
             if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
             Ok(batches)

+ 1 - 1
runtime/src/tests/proposals_integration/mod.rs

@@ -120,7 +120,7 @@ impl Default for DummyProposalFixture {
         let title = b"title".to_vec();
         let description = b"description".to_vec();
         let dummy_proposal =
-            proposals_codex::Call::<Runtime>::execute_signal_proposal(b"signal".to_vec());
+            utilities::Call::<Runtime>::execute_signal_proposal(b"signal".to_vec());
 
         DummyProposalFixture {
             parameters: ProposalParameters {

+ 2 - 1
runtime/src/tests/proposals_integration/working_group_proposals.rs

@@ -4,8 +4,9 @@
 use super::*;
 
 use common::working_group::WorkingGroup;
+use common::BalanceKind;
 use frame_system::RawOrigin;
-use proposals_codex::{BalanceKind, CreateOpeningParameters};
+use proposals_codex::CreateOpeningParameters;
 use strum::IntoEnumIterator;
 use working_group::StakeParameters;
 

+ 1 - 0
runtime/src/weights/mod.rs

@@ -33,4 +33,5 @@ pub mod proposals_codex;
 pub mod proposals_discussion;
 pub mod proposals_engine;
 pub mod referendum;
+pub mod utilities;
 pub mod working_group;

+ 0 - 43
runtime/src/weights/proposals_codex.rs

@@ -7,9 +7,6 @@ use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
 
 pub struct WeightInfo;
 impl proposals_codex::WeightInfo for WeightInfo {
-    fn execute_signal_proposal(i: u32) -> Weight {
-        (84_026_000 as Weight).saturating_add((145_000 as Weight).saturating_mul(i as Weight))
-    }
     fn create_proposal_signal(i: u32, t: u32, d: u32) -> Weight {
         (0 as Weight)
             .saturating_add((376_000 as Weight).saturating_mul(i as Weight))
@@ -194,44 +191,4 @@ impl proposals_codex::WeightInfo for WeightInfo {
             .saturating_add(DbWeight::get().reads(6 as Weight))
             .saturating_add(DbWeight::get().writes(9 as Weight))
     }
-    fn update_working_group_budget_positive_forum() -> Weight {
-        (173_903_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_negative_forum() -> Weight {
-        (170_026_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_positive_storage() -> Weight {
-        (168_902_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_negative_storage() -> Weight {
-        (169_381_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_positive_content() -> Weight {
-        (169_707_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_negative_content() -> Weight {
-        (169_606_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_positive_membership() -> Weight {
-        (168_373_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
-    fn update_working_group_budget_negative_membership() -> Weight {
-        (169_063_000 as Weight)
-            .saturating_add(DbWeight::get().reads(2 as Weight))
-            .saturating_add(DbWeight::get().writes(2 as Weight))
-    }
 }

+ 56 - 0
runtime/src/weights/utilities.rs

@@ -0,0 +1,56 @@
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
+
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight};
+
+pub struct WeightInfo;
+impl utilities::WeightInfo for WeightInfo {
+    fn execute_signal_proposal(i: u32) -> Weight {
+        (81_623_000 as Weight).saturating_add((162_000 as Weight).saturating_mul(i as Weight))
+    }
+    fn update_working_group_budget_positive_forum() -> Weight {
+        (158_627_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_negative_forum() -> Weight {
+        (158_189_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_positive_storage() -> Weight {
+        (158_593_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_negative_storage() -> Weight {
+        (158_974_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_positive_content() -> Weight {
+        (158_706_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_negative_content() -> Weight {
+        (158_540_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_positive_membership() -> Weight {
+        (156_882_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn update_working_group_budget_negative_membership() -> Weight {
+        (157_833_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
+    fn burn_account_tokens() -> Weight {
+        (166_780_000 as Weight)
+    }
+}