Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dispatch as Treasury or AAVEManager from OpenGov #973

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pallet-collator-rewards = { path = "pallets/collator-rewards", default-features
pallet-currencies = { path = "pallets/currencies", default-features = false }
pallet-currencies-rpc-runtime-api = { path = "pallets/currencies/rpc/runtime-api", default-features = false }
pallet-dca = { path = "pallets/dca", default-features = false }
pallet-dispatcher = { path = "pallets/dispatcher", default-features = false }
pallet-duster = { path = "pallets/duster", default-features = false }
pallet-dynamic-fees = { path = "pallets/dynamic-fees", default-features = false }
pallet-dynamic-evm-fee = { path = "pallets/dynamic-evm-fee", default-features = false }
Expand Down
56 changes: 56 additions & 0 deletions pallets/dispatcher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[package]
name = "pallet-dispatcher"
version = "1.0.0"
authors = ['GalacticCouncil']
edition = "2021"
license = "Apache-2.0"
homepage = 'https://github.com/galacticcouncil/hydration-node'
repository = 'https://github.com/galacticcouncil/hydration-node'
description = "Pallet for dispatching calls as specific origins"
readme = "README.md"

[dependencies]
# parity
codec = { workspace = true, features = ["derive", "max-encoded-len"] }
scale-info = { workspace = true }

# primitives
sp-runtime = { workspace = true }
sp-std = { workspace = true }
sp-core = { workspace = true }

# FRAME
frame-support = { workspace = true }
frame-system = { workspace = true }

# Optional imports for benchmarking
frame-benchmarking = { workspace = true, optional = true }

[dev-dependencies]
sp-io = { workspace = true }
hydradx-traits = { workspace = true }
orml-tokens = { workspace = true }
orml-traits = { workspace = true }
test-utils = { workspace = true }

[features]
default = ['std']
std = [
'codec/std',
'scale-info/std',
'sp-runtime/std',
'sp-core/std',
'sp-io/std',
'sp-std/std',
'frame-benchmarking/std',
'hydradx-traits/std',
'orml-tokens/std',
'orml-traits/std',
]

runtime-benchmarks = [
"frame-benchmarking",
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
]
try-runtime = ["frame-support/try-runtime"]
6 changes: 6 additions & 0 deletions pallets/dispatcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Dispatcher Pallet
This pallet enables specific OpenGov tracks to dispatch Runtime calls as predefined origins.

The pallet supports the following dispatchables:
* `dispatch_as_treasury` - allows the `Treasury` track to dispatch calls as the Treasury account on Hydration (`7L53bUTBopuwFt3mKUfmkzgGLayYa1Yvn1hAg9v5UMrQzTfh`)
* `dispatch_as_aave_manager` - allows the `EconomicParameters` track to dispatch calls as the Money Market authority on Hydration (`add addr`)
54 changes: 54 additions & 0 deletions pallets/dispatcher/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// This file is part of https://github.com/galacticcouncil/*
//
// $$$$$$$ Licensed under the Apache License, Version 2.0 (the "License")
// $$$$$$$$$$$$$ you may only use this file in compliance with the License
// $$$$$$$$$$$$$$$$$$$
// $$$$$$$$$ Copyright (C) 2021-2024 Intergalactic, Limited (GIB)
// $$$$$$$$$$$ $$$$$$$$$$ SPDX-License-Identifier: Apache-2.0
// $$$$$$$$$$$$$$$$$$$$$$$$$$
// $$$$$$$$$$$$$$$$$$$$$$$ $ Built with <3 for decentralisation
// $$$$$$$$$$$$$$$$$$$ $$$$$$$
// $$$$$$$ $$$$$$$$$$$$$$$$$$ Unless required by applicable law or agreed to in
// $ $$$$$$$$$$$$$$$$$$$$$$$ writing, software distributed under the License is
// $$$$$$$$$$$$$$$$$$$$$$$$$$ distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
// $$$$$$$$$ $$$$$$$$$$$ OR CONDITIONS OF ANY KIND, either express or implied.
// $$$$$$$$
// $$$$$$$$$$$$$$$$$$ See the License for the specific language governing
// $$$$$$$$$$$$$ permissions and limitations under the License.
// $$$$$$$
// $$
// $$$$$ $$$$$ $$ $
// $$$ $$$ $$$ $$ $$$$$ $$ $$$ $$$$ $$$$$$$ $$$$ $$$ $$$$$$ $$ $$$$$$
// $$$ $$$ $$$ $$ $$$ $$$ $$$ $ $$ $$ $$ $$ $$ $$ $$$ $$$
// $$$$$$$$$$$ $$ $$ $$$ $$ $$ $$$$$$$ $$ $$ $$ $$$ $$ $$
// $$$ $$$ $$$$ $$$ $$ $$ $$$ $$ $$ $$ $$ $$ $$ $$
// $$$$$ $$$$$ $$ $$$$$$$$ $ $$$ $$$$$$$$ $$$ $$$$ $$$$$$$ $$$$ $$$$
// $$$

use super::*;

use frame_benchmarking::benchmarks;
use frame_system::RawOrigin;
use sp_std::boxed::Box;

benchmarks! {
where_clause { where
T: crate::Config,
}

dispatch_as_treasury {
let n in 1 .. 10_000;
let remark = sp_std::vec![1u8; n as usize];

let call: <T as pallet::Config>::RuntimeCall = frame_system::Call::remark { remark }.into();
}: _(RawOrigin::Root, Box::new(call))

dispatch_as_aave_manager {
let n in 1 .. 10_000;
let remark = sp_std::vec![1u8; n as usize];

let call: <T as pallet::Config>::RuntimeCall = frame_system::Call::remark { remark }.into();
}: _(RawOrigin::Root, Box::new(call))

impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Test);
}
173 changes: 173 additions & 0 deletions pallets/dispatcher/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// This file is part of https://github.com/galacticcouncil/*
//
// $$$$$$$ Licensed under the Apache License, Version 2.0 (the "License")
// $$$$$$$$$$$$$ you may only use this file in compliance with the License
// $$$$$$$$$$$$$$$$$$$
// $$$$$$$$$ Copyright (C) 2021-2024 Intergalactic, Limited (GIB)
// $$$$$$$$$$$ $$$$$$$$$$ SPDX-License-Identifier: Apache-2.0
// $$$$$$$$$$$$$$$$$$$$$$$$$$
// $$$$$$$$$$$$$$$$$$$$$$$ $ Built with <3 for decentralisation
// $$$$$$$$$$$$$$$$$$$ $$$$$$$
// $$$$$$$ $$$$$$$$$$$$$$$$$$ Unless required by applicable law or agreed to in
// $ $$$$$$$$$$$$$$$$$$$$$$$ writing, software distributed under the License is
// $$$$$$$$$$$$$$$$$$$$$$$$$$ distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
// $$$$$$$$$ $$$$$$$$$$$ OR CONDITIONS OF ANY KIND, either express or implied.
// $$$$$$$$
// $$$$$$$$$$$$$$$$$$ See the License for the specific language governing
// $$$$$$$$$$$$$ permissions and limitations under the License.
// $$$$$$$
// $$
// $$$$$ $$$$$ $$ $
// $$$ $$$ $$$ $$ $$$$$ $$ $$$ $$$$ $$$$$$$ $$$$ $$$ $$$$$$ $$ $$$$$$
// $$$ $$$ $$$ $$ $$$ $$$ $$$ $ $$ $$ $$ $$ $$ $$ $$$ $$$
// $$$$$$$$$$$ $$ $$ $$$ $$ $$ $$$$$$$ $$ $$ $$ $$$ $$ $$
// $$$ $$$ $$$$ $$$ $$ $$ $$$ $$ $$ $$ $$ $$ $$ $$
// $$$$$ $$$$$ $$ $$$$$$$$ $ $$$ $$$$$$$$ $$$ $$$$ $$$$$$$ $$$$ $$$$
// $$$

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
pub mod mock;
#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

pub mod weights;

use frame_support::dispatch::PostDispatchInfo;
use sp_runtime::{traits::Dispatchable, DispatchResultWithInfo};
pub use weights::WeightInfo;

// Re-export pallet items so that they can be accessed from the crate namespace.
use frame_support::pallet_prelude::Weight;
pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use codec::FullCodec;
use frame_support::{
dispatch::{GetDispatchInfo, PostDispatchInfo},
pallet_prelude::*,
};
use frame_system::pallet_prelude::*;
use sp_runtime::traits::{Dispatchable, Hash};
use sp_std::boxed::Box;

pub type AccountId = u64;

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The overarching call type.
type RuntimeCall: IsType<<Self as frame_system::Config>::RuntimeCall>
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
+ GetDispatchInfo
+ FullCodec
+ TypeInfo
+ From<frame_system::Call<Self>>
+ Parameter;

type TreasuryManagerOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type AaveManagerOrigin: EnsureOrigin<Self::RuntimeOrigin>;

type TreasuryAccount: Get<Self::AccountId>;
type AaveManagerAccount: Get<Self::AccountId>;

/// The weight information for this pallet.
type WeightInfo: WeightInfo;
}

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
TreasuryManagerCallDispatched {
call_hash: T::Hash,
result: DispatchResultWithPostInfo,
},
AaveManagerCallDispatched {
call_hash: T::Hash,
result: DispatchResultWithPostInfo,
},
}

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight({
let call_weight = call.get_dispatch_info().weight;
let call_len = call.encoded_size() as u32;

T::WeightInfo::dispatch_as_treasury(call_len)
.saturating_add(call_weight)
})]
pub fn dispatch_as_treasury(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
T::TreasuryManagerOrigin::ensure_origin(origin)?;

let call_hash = T::Hashing::hash_of(&call).into();
let call_len = call.encoded_size() as u32;

let (result, actual_weight) = Self::do_dispatch(T::TreasuryAccount::get(), *call);
actual_weight.map(|w| w.saturating_add(T::WeightInfo::dispatch_as_treasury(call_len)));

Self::deposit_event(Event::<T>::TreasuryManagerCallDispatched { call_hash, result });

Ok(actual_weight.into())
}

#[pallet::call_index(1)]
#[pallet::weight({
let call_weight = call.get_dispatch_info().weight;
let call_len = call.encoded_size() as u32;

T::WeightInfo::dispatch_as_aave_manager(call_len)
.saturating_add(call_weight)
})]
pub fn dispatch_as_aave_manager(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
T::AaveManagerOrigin::ensure_origin(origin)?;

let call_hash = T::Hashing::hash_of(&call).into();
let call_len = call.encoded_size() as u32;

let (result, actual_weight) = Self::do_dispatch(T::AaveManagerAccount::get(), *call);
actual_weight.map(|w| w.saturating_add(T::WeightInfo::dispatch_as_aave_manager(call_len)));

Self::deposit_event(Event::<T>::AaveManagerCallDispatched { call_hash, result });

Ok(actual_weight.into())
}
}
}

impl<T: Config> Pallet<T> {
/// Dispatch the call from the specified account as Signed Origin.
///
/// Return the result and the actual weight of the dispatched call if there is some.
fn do_dispatch(
account: T::AccountId,
call: <T as Config>::RuntimeCall,
) -> (DispatchResultWithInfo<PostDispatchInfo>, Option<Weight>) {
let result = call.dispatch(frame_system::Origin::<T>::Signed(account).into());

let call_actual_weight = match result {
Ok(call_post_info) => call_post_info.actual_weight.clone(),
Err(call_err) => call_err.post_info.actual_weight,
};

(result, call_actual_weight)
}
}
Loading
Loading