Skip to content

Commit

Permalink
feat: impl governance pallet (#11)
Browse files Browse the repository at this point in the history
closes CHAIN-18
  • Loading branch information
devwckd committed Dec 20, 2024
1 parent 90231b7 commit d44f85a
Show file tree
Hide file tree
Showing 14 changed files with 980 additions and 130 deletions.
1 change: 1 addition & 0 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 @@ -18,6 +18,7 @@ test-utils.path = "./test-utils"
# Substrate
codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false }
scale-info = { version = "2.11.1", default-features = false }

polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "stable2409", default-features = false }

# Frontier
Expand Down
10 changes: 8 additions & 2 deletions pallets/governance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ edition.workspace = true

[features]
default = ["std"]
std = ["codec/std", "polkadot-sdk/std", "scale-info/std"]
std = ["codec/std", "polkadot-sdk/std", "scale-info/std", "substrate-fixed/std"]
runtime-benchmarks = ["polkadot-sdk/runtime-benchmarks"]
try-runtime = ["polkadot-sdk/try-runtime"]

[dependencies]
codec = { workspace = true, features = ["derive"] }
pallet-torus0 = { workspace = true }
polkadot-sdk = { workspace = true, features = ["experimental", "runtime"] }
polkadot-sdk = { workspace = true, features = [
"experimental",
"runtime",
"pallet-sudo",
"sc-telemetry",
] }
scale-info = { workspace = true, features = ["derive"] }
substrate-fixed = { workspace = true }
109 changes: 90 additions & 19 deletions pallets/governance/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,114 @@
use crate::frame::traits::ExistenceRequirement;
use crate::{whitelist, AccountIdOf, BalanceOf, Block};
use codec::{Decode, Encode, MaxEncodedLen};
use polkadot_sdk::frame_election_provider_support::Get;
use polkadot_sdk::frame_support::dispatch::DispatchResult;
use polkadot_sdk::frame_support::traits::Currency;
use polkadot_sdk::frame_support::traits::WithdrawReasons;
use polkadot_sdk::frame_support::DebugNoBound;
use polkadot_sdk::polkadot_sdk_frame::prelude::OriginFor;
use polkadot_sdk::sp_core::ConstU32;
use polkadot_sdk::sp_runtime::BoundedVec;
use polkadot_sdk::sp_std::vec::Vec;
use scale_info::TypeInfo;

use crate::{AccountIdOf, BalanceOf, Block};

#[derive(DebugNoBound, TypeInfo, Decode, Encode, MaxEncodedLen)]
#[scale_info(skip_type_params(T))]
pub struct AgentApplication<T: crate::Config> {
pub id: u32,
pub payer_key: AccountIdOf<T>,
pub agent_key: AccountIdOf<T>,
pub data: BoundedVec<u8, ConstU32<256>>,
pub data: BoundedVec<u8, T::MaxApplicationDataLength>,
pub cost: BalanceOf<T>,
pub expires_at: Block,
}

pub fn submit_application<T: crate::Config>(
_origin: OriginFor<T>,
_agent_key: AccountIdOf<T>,
_data: Vec<u8>,
payer: AccountIdOf<T>,
agent_key: AccountIdOf<T>,
data: Vec<u8>,
) -> DispatchResult {
todo!()
if whitelist::is_whitelisted::<T>(&agent_key) {
return Err(crate::Error::<T>::AlreadyWhitelisted.into());
}

let config = crate::GlobalGovernanceConfig::<T>::get();
let cost = config.agent_application_cost;

let _ = <T as crate::Config>::Currency::withdraw(
&payer,
cost,
WithdrawReasons::except(WithdrawReasons::TIP),
ExistenceRequirement::KeepAlive,
)
.map_err(|_| crate::Error::<T>::NotEnoughBalanceToApply)?;

let data_len: u32 = data
.len()
.try_into()
.map_err(|_| crate::Error::<T>::InvalidApplicationDataLength)?;

let data_range = T::MinApplicationDataLength::get()..T::MaxApplicationDataLength::get();
if !data_range.contains(&data_len) {
return Err(crate::Error::<T>::InvalidApplicationDataLength.into());
}

let current_block: u64 =
TryInto::try_into(<polkadot_sdk::frame_system::Pallet<T>>::block_number())
.ok()
.expect("blockchain will not exceed 2^64 blocks; QED.");

let expires_at = current_block + config.agent_application_expiration;

let application_id: u32 = crate::AgentApplicationId::<T>::mutate(|id| {
let last_id = *id;
*id = id.saturating_add(1);
last_id
});

let application = AgentApplication::<T> {
id: application_id,
payer_key: payer,
agent_key,
data: BoundedVec::truncate_from(data),
cost,
expires_at,
};

crate::AgentApplications::<T>::insert(application_id, application);
crate::Pallet::<T>::deposit_event(crate::Event::<T>::ApplicationCreated(application_id));

Ok(())
}

pub fn accept_application<T: crate::Config>(
_origin: OriginFor<T>,
_application_id: u32,
) -> DispatchResult {
todo!()
pub fn accept_application<T: crate::Config>(application_id: u32) -> DispatchResult {
let application = crate::AgentApplications::<T>::get(application_id)
.ok_or(crate::Error::<T>::ApplicationNotFound)?;

crate::AgentApplications::<T>::remove(application.id);

whitelist::add_to_whitelist::<T>(application.agent_key.clone())?;
crate::Pallet::<T>::deposit_event(crate::Event::<T>::ApplicationAccepted(application.id));
crate::Pallet::<T>::deposit_event(crate::Event::<T>::WhitelistAdded(application.agent_key));

Ok(())
}

pub fn deny_application<T: crate::Config>(
_origin: OriginFor<T>,
_application_id: u32,
) -> DispatchResult {
todo!()
pub fn deny_application<T: crate::Config>(application_id: u32) -> DispatchResult {
let application = crate::AgentApplications::<T>::get(application_id)
.ok_or(crate::Error::<T>::ApplicationNotFound)?;

crate::AgentApplications::<T>::remove(application.id);
crate::Pallet::<T>::deposit_event(crate::Event::<T>::ApplicationDenied(application.id));

Ok(())
}

pub(crate) fn remove_expired_applications<T: crate::Config>(current_block: Block) {
for application in crate::AgentApplications::<T>::iter_values() {
if current_block < application.expires_at {
continue;
}

crate::AgentApplications::<T>::remove(application.id);
crate::Pallet::<T>::deposit_event(crate::Event::<T>::ApplicationExpired(application.id));
}
}
2 changes: 2 additions & 0 deletions pallets/governance/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct GovernanceConfiguration<T: crate::Config> {
pub proposal_cost: BalanceOf<T>,
pub proposal_expiration: BlockAmount,
pub agent_application_cost: BalanceOf<T>,
pub agent_application_expiration: BlockAmount,
pub proposal_reward_treasury_allocation: Percent,
pub max_proposal_reward_treasury_allocation: BalanceOf<T>,
pub proposal_reward_interval: BlockAmount,
Expand All @@ -21,6 +22,7 @@ impl<T: crate::Config> Default for GovernanceConfiguration<T> {
proposal_cost: 10_000_000_000_000,
proposal_expiration: 130_000,
agent_application_cost: 1_000_000_000_000,
agent_application_expiration: 2_000,
proposal_reward_treasury_allocation: Percent::from_percent(2),
max_proposal_reward_treasury_allocation: 10_000_000_000_000,
proposal_reward_interval: 75_600,
Expand Down
58 changes: 47 additions & 11 deletions pallets/governance/src/curator.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
use crate::AccountIdOf;
use polkadot_sdk::frame_election_provider_support::Get;
use polkadot_sdk::sp_runtime::{DispatchError, Percent};
use polkadot_sdk::{
frame_support::dispatch::DispatchResult, polkadot_sdk_frame::prelude::OriginFor,
frame_support::dispatch::DispatchResult, frame_system::ensure_signed,
polkadot_sdk_frame::prelude::OriginFor,
};

use crate::AccountIdOf;
pub fn add_curator<T: crate::Config>(key: AccountIdOf<T>) -> DispatchResult {
if crate::Curators::<T>::contains_key(&key) {
return Err(crate::Error::<T>::AlreadyCurator.into());
}

pub fn add_curator<T: crate::Config>(
_origin: OriginFor<T>,
_key: AccountIdOf<T>,
) -> DispatchResult {
todo!()
crate::Curators::<T>::insert(key, ());
Ok(())
}

pub fn remove_curator<T: crate::Config>(
_origin: OriginFor<T>,
_key: AccountIdOf<T>,
pub fn remove_curator<T: crate::Config>(key: AccountIdOf<T>) -> DispatchResult {
if !crate::Curators::<T>::contains_key(&key) {
return Err(crate::Error::<T>::NotCurator.into());
}

crate::Curators::<T>::remove(&key);
Ok(())
}

pub fn penalize_agent<T: crate::Config>(
agent_key: AccountIdOf<T>,
percentage: u8,
) -> DispatchResult {
todo!()
if percentage > T::MaxPenaltyPercentage::get() {
return Err(crate::Error::<T>::InvalidPenaltyPercentage.into());
}

pallet_torus0::Agents::<T>::try_mutate(&agent_key, |agent| {
let Some(agent) = agent else {
return Err(crate::Error::<T>::AgentNotFound.into());
};

agent.weight_factor = Percent::from_percent(100u8.saturating_sub(percentage));

Ok::<(), DispatchError>(())
})?;

Ok(())
}

pub fn ensure_curator<T: crate::Config>(origin: OriginFor<T>) -> DispatchResult {
let key: AccountIdOf<T> = ensure_signed(origin)?;
if !crate::Curators::<T>::contains_key(key) {
return Err(crate::Error::<T>::NotCurator.into());
}

Ok(())
}
Loading

0 comments on commit d44f85a

Please sign in to comment.