Skip to content

Commit

Permalink
feat: new fee structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Honza committed Nov 14, 2024
1 parent e1f26d3 commit a4a78c4
Show file tree
Hide file tree
Showing 23 changed files with 286 additions and 129 deletions.
6 changes: 4 additions & 2 deletions pallets/governance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ pub mod pallet {
max_allowed_modules: u16,
max_registrations_per_block: u16,
max_allowed_weights: u16,
floor_delegation_fee: Percent,
floor_stake_delegation_fee: Percent,
floor_validator_weight_fee: Percent,
floor_founder_share: u8,
min_weight_stake: u64,
curator: T::AccountId,
Expand All @@ -212,7 +213,8 @@ pub mod pallet {
params.max_allowed_modules = max_allowed_modules;
params.max_registrations_per_block = max_registrations_per_block;
params.max_allowed_weights = max_allowed_weights;
params.floor_delegation_fee = floor_delegation_fee;
params.floor_stake_delegation_fee = floor_stake_delegation_fee;
params.floor_validator_weight_fee = floor_validator_weight_fee;
params.floor_founder_share = floor_founder_share;
params.min_weight_stake = min_weight_stake;
params.curator = curator;
Expand Down
10 changes: 6 additions & 4 deletions pallets/offworker/src/dispatches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ pub mod dispatches {
let epoch_count = ConsensusParameters::<T>::iter_prefix(subnet_id).count();

// Check if the length matches
ensure!(
decrypted_weights.len() == epoch_count,
Error::<T>::DecryptedWeightsLengthMismatch
);

// TODO: get this back to life later
// ensure!(
// decrypted_weights.len() == epoch_count,
// Error::<T>::DecryptedWeightsLengthMismatch
// );

let has_weights = decrypted_weights.iter().any(|(_, inner_vec)| {
inner_vec.iter().any(|(_, weight_vec, _)| !weight_vec.is_empty())
Expand Down
2 changes: 1 addition & 1 deletion pallets/offworker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use sp_std::collections::btree_map::BTreeMap;
use pallet_subnet_emission::{ConsensusParameters, Weights};
use pallet_subspace::{
math::{inplace_normalize_64, vec_fixed64_to_fixed32},
Consensus, CopierMargin, FloorDelegationFee, MaxEncryptionPeriod,
Consensus, CopierMargin, MaxEncryptionPeriod, MinFees,
};
use parity_scale_codec::{Decode, Encode};
use scale_info::prelude::marker::PhantomData;
Expand Down
2 changes: 1 addition & 1 deletion pallets/offworker/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub fn should_decrypt_weights<T: Config>(
};

// Get delegation fee (this is not a Result type)
let delegation_fee = FloorDelegationFee::<T>::get();
let delegation_fee = MinFees::<T>::get().stake_delegation_fee;

// Update simulation result
simulation_result.update(simulation_yuma_output, copier_uid, delegation_fee);
Expand Down
10 changes: 5 additions & 5 deletions pallets/subnet_emission/src/distribute_emission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ fn run_yuma_consensus<T: Config>(netuid: u16, emission_to_drain: u64) -> Result<
}
// This means, that subnet uses weight encryption. Create the parameters, only if subnet has
// some encrypted weights present
// let encrypted_weights = WeightEncryptionData::<T>::iter_prefix(netuid).collect::<Vec<_>>();
let encrypted_weights = WeightEncryptionData::<T>::iter_prefix(netuid).collect::<Vec<_>>();

// if encrypted_weights.is_empty() {
// log::warn!("No encrypted weights found for subnet {netuid}");
// return Ok(());
// }
if encrypted_weights.is_empty() {
log::warn!("No encrypted weights found for subnet {netuid}");
return Ok(());
}

// If subnet has some weights, create the parameters
let mut params = ConsensusParams::<T>::new(netuid, emission_to_drain)?;
Expand Down
1 change: 1 addition & 0 deletions pallets/subnet_emission/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ pub mod pallet {
netuid,
encrypted_weights,
decrypted_weights_hash,
true,
)
}

Expand Down
8 changes: 6 additions & 2 deletions pallets/subnet_emission/src/set_weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ impl<T: Config> Pallet<T> {
fee_percentage: pallet_subspace::Pallet::<T>::module_params(
netuid, &target, target_uid,
)
.delegation_fee,
.fees
.validator_weight_fee,
}),
);

Expand Down Expand Up @@ -344,6 +345,7 @@ impl<T: Config> Pallet<T> {
netuid: u16,
encrypted_weights: Vec<u8>,
decrypted_weights_hash: Vec<u8>,
set_last_updated: bool,
) -> DispatchResult {
let key = ensure_signed(origin.clone())?;

Expand Down Expand Up @@ -377,7 +379,9 @@ impl<T: Config> Pallet<T> {

let current_block = pallet_subspace::Pallet::<T>::get_current_block_number();
pallet_subspace::WeightSetAt::<T>::insert(netuid, uid, current_block);
pallet_subspace::Pallet::<T>::set_last_update_for_uid(netuid, uid, current_block);
if set_last_updated {
pallet_subspace::Pallet::<T>::set_last_update_for_uid(netuid, uid, current_block);
}
pallet_subspace::Pallet::<T>::deposit_event(pallet_subspace::Event::WeightsSet(
netuid, uid,
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn calculate_final_emissions<T: Config>(
if validator_emission > 0 {
let ownership_vector =
PalletSubspace::<T>::get_ownership_ratios(subnet_id, &module_key.0);
let delegation_fee = PalletSubspace::<T>::get_delegation_fee(&module_key.0);
let delegation_fee = PalletSubspace::<T>::get_stake_delegation_fee(&module_key.0);

let total_validator_emission = I64F64::from_num(validator_emission);
for (delegate_key, delegate_ratio) in ownership_vector {
Expand Down
116 changes: 94 additions & 22 deletions pallets/subspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ pub mod pallet {
},
// Put here every module-related double map, that has no uid association. first key is netuid, second key is key of module (not uid!)
key_only_storages: {
Metadata: Vec<u8>
Metadata: Vec<u8>,
WeightSettingDelegation: DelegationInfo<T::AccountId>
}
);

Expand Down Expand Up @@ -384,16 +385,6 @@ pub mod pallet {
#[pallet::storage]
pub type MaxAllowedModules<T: Config> = StorageValue<_, u16, ValueQuery, ConstU16<10_000>>;

#[pallet::type_value]
pub fn DefaultFloorDelegationFee<T: Config>() -> Percent {
Percent::from_percent(5)
}

/// Minimum delegation fee
#[pallet::storage]
pub type FloorDelegationFee<T> =
StorageValue<_, Percent, ValueQuery, DefaultFloorDelegationFee<T>>;

/// Minimum stake weight
#[pallet::storage]
pub type MinWeightStake<T> = StorageValue<_, u64, ValueQuery>;
Expand Down Expand Up @@ -476,24 +467,105 @@ pub mod pallet {
#[pallet::storage]
pub type SubnetImmunityPeriod<T: Config> = StorageValue<_, u64, ValueQuery, ConstU64<32400>>;

#[pallet::type_value]
pub fn DefaultDelegationFee<T: Config>() -> Percent {
Percent::from_percent(5u8)
}

/// Delegation fee per account
#[pallet::storage]
pub type DelegationFee<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, Percent, ValueQuery, DefaultDelegationFee<T>>;

/// Control delegation per account
#[pallet::storage]
pub type WeightSettingDelegation<T: Config> =
StorageDoubleMap<_, Identity, u16, Identity, T::AccountId, DelegationInfo<T::AccountId>>;

#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug)]
pub struct DelegationInfo<AccountId> {
pub delegate: AccountId,
pub fee_percentage: Percent,
}

// --- Module Fees ---

/// Default values for fees used throughout the module
pub struct FeeDefaults;
impl FeeDefaults {
pub const STAKE_DELEGATION: Percent = Percent::from_percent(5);
pub const VALIDATOR_WEIGHT: Percent = Percent::from_percent(4);
}

/// Contains the minimum allowed values for delegation fees
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug, Eq)]
pub struct MinimumFees {
/// Minimum fee for stake delegation
pub stake_delegation_fee: Percent,
/// Minimum fee for validator weight delegation
pub validator_weight_fee: Percent,
}

#[pallet::type_value]
pub fn DefaultMinimumFees<T: Config>() -> MinimumFees {
MinimumFees {
stake_delegation_fee: FeeDefaults::STAKE_DELEGATION,
validator_weight_fee: FeeDefaults::VALIDATOR_WEIGHT,
}
}

/// Storage for minimum fees that can be updated via runtime
#[pallet::storage]
pub type MinFees<T> = StorageValue<_, MinimumFees, ValueQuery, DefaultMinimumFees<T>>;

/// A fee structure containing delegation fees for both stake and validator weight
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug, Eq)]
pub struct ValidatorFees {
/// Fee charged when delegators delegate their stake
pub stake_delegation_fee: Percent,
/// Fee charged when validators delegate their weight-setting authority
pub validator_weight_fee: Percent,
}

impl Default for ValidatorFees {
fn default() -> Self {
Self {
stake_delegation_fee: FeeDefaults::STAKE_DELEGATION,
validator_weight_fee: FeeDefaults::VALIDATOR_WEIGHT,
}
}
}

#[pallet::type_value]
pub fn DefaultValidatorFees<T: Config>() -> ValidatorFees {
ValidatorFees::default()
}

/// Maps validator accounts to their fee configuration
#[pallet::storage]
pub type ValidatorFeeConfig<T: Config> =
StorageMap<_, Identity, T::AccountId, ValidatorFees, ValueQuery, DefaultValidatorFees<T>>;

impl ValidatorFees {
/// Creates a new ValidatorFees instance with validation against minimum fees
pub fn new<T: Config>(
stake_delegation_fee: Percent,
validator_weight_fee: Percent,
) -> Result<Self, &'static str> {
let min_fees = MinFees::<T>::get();
if stake_delegation_fee < min_fees.stake_delegation_fee {
return Err("Stake delegation fee is below minimum threshold");
}
if validator_weight_fee < min_fees.validator_weight_fee {
return Err("Validator weight fee is below minimum threshold");
}

Ok(Self {
stake_delegation_fee,
validator_weight_fee,
})
}

/// Validates that the fees meet minimum requirements
pub fn validate<T: Config>(&self) -> Result<(), &'static str> {
let min_fees = MinFees::<T>::get();
if self.stake_delegation_fee < min_fees.stake_delegation_fee {
return Err("Stake delegation fee is below minimum threshold");
}
if self.validator_weight_fee < min_fees.validator_weight_fee {
return Err("Validator weight fee is below minimum threshold");
}
Ok(())
}
}
}
27 changes: 5 additions & 22 deletions pallets/subspace/src/network/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ impl<T: Config> Pallet<T> {
pub fn do_update_module(
origin: T::RuntimeOrigin,
netuid: u16,
changeset: ModuleChangeset,
changeset: ModuleChangeset<T>,
) -> DispatchResult {
let key = ensure_signed(origin)?;
let uid: u16 = Self::get_uid_for_key(netuid, &key).ok_or(Error::<T>::ModuleDoesNotExist)?;
changeset.apply::<T>(netuid, key, uid)?;
changeset.apply(netuid, key, uid)?;
Ok(())
}

pub fn append_module(
netuid: u16,
key: &T::AccountId,
changeset: ModuleChangeset,
changeset: ModuleChangeset<T>,
) -> Result<u16, sp_runtime::DispatchError> {
// --- Get The Next Uid ---
let uid: u16 = N::<T>::get(netuid);
Expand All @@ -28,7 +28,7 @@ impl<T: Config> Pallet<T> {
// -- Initialize All Storages ---
StorageHandler::initialize_all::<T>(netuid, uid, key)?;
// Make sure this overwrites the defaults (keep it second)
changeset.apply::<T>(netuid, key.clone(), uid)?;
changeset.apply(netuid, key.clone(), uid)?;

// --- Update The Network Module Size ---
N::<T>::mutate(netuid, |n| *n = n.saturating_add(1));
Expand Down Expand Up @@ -80,7 +80,7 @@ impl<T: Config> Pallet<T> {
// So the values are not "just hanging around" in the storage. Without module actually being
// registered on any subnet.
if Uids::<T>::iter().all(|(_, key, _)| key != module_key) {
DelegationFee::<T>::remove(&module_key);
ValidatorFeeConfig::<T>::remove(&module_key);
Self::remove_stake_from_storage(&module_key);
}

Expand All @@ -90,28 +90,11 @@ impl<T: Config> Pallet<T> {
*v
});

// 10. Handle rootnet deregistration
if let Some(key) = Self::get_key_for_uid(uid, netuid) {
Self::handle_weight_setting_delegation(key, netuid);
}

// 11. Remove subnet if empty
if deregister_subnet_if_empty && module_count == 0 {
Self::remove_subnet(netuid);
}

Ok(())
}

fn handle_weight_setting_delegation(key: T::AccountId, netuid: u16) {
WeightSettingDelegation::<T>::remove(netuid, &key);

WeightSettingDelegation::<T>::translate(|nuid, _, v: DelegationInfo<T::AccountId>| {
if nuid == netuid && v.delegate == key {
None
} else {
Some(v)
}
});
}
}
4 changes: 2 additions & 2 deletions pallets/subspace/src/network/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ impl<T: Config> Pallet<T> {
address: Vec<u8>,
metadata: Option<Vec<u8>>,
) -> Result<u16, DispatchError> {
let fee = DefaultDelegationFee::<T>::get();
let module_changeset = ModuleChangeset::new(name, address, fee, metadata);
let fees = DefaultValidatorFees::<T>::get();
let module_changeset = ModuleChangeset::new(name, address, fees, metadata, None);
Self::append_module(netuid, module_key, module_changeset)
}

Expand Down
14 changes: 8 additions & 6 deletions pallets/subspace/src/network/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,14 @@ impl<T: Config> Pallet<T> {
.sum()
}

// Returns the delegation fee of a module
pub fn get_delegation_fee(module_key: &T::AccountId) -> Percent {
let min_deleg_fee_global = FloorDelegationFee::<T>::get();
let delegation_fee = DelegationFee::<T>::get(module_key);

delegation_fee.max(min_deleg_fee_global)
/// Returns staking delegation fee of a module
pub fn get_stake_delegation_fee(module_key: &T::AccountId) -> Percent {
// Get the validator's fee configuration
let validator_fees = ValidatorFeeConfig::<T>::get(module_key);

// Return the stake delegation fee, which will already be at or above
// MIN_STAKE_DELEGATION_FEE due to the ValidatorFees validation
validator_fees.stake_delegation_fee
}

pub fn has_enough_stake(key: &T::AccountId, module_key: &T::AccountId, amount: u64) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions pallets/subspace/src/network/subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ impl<T: Config> Pallet<T> {
.map(|(_, account, _)| account)
.collect();

// Clear delegation fees for accounts that exist only in this subnet
// Clear validator fees for accounts that exist only in this subnet
Uids::<T>::iter_prefix(subnet_id)
.map(|(account, _)| account)
.filter(|account| !accounts_in_other_subnets.contains(account))
.for_each(|subnet_only_account| DelegationFee::<T>::remove(&subnet_only_account));
.for_each(|subnet_only_account| ValidatorFeeConfig::<T>::remove(&subnet_only_account));
}

pub fn get_total_subnets() -> u16 {
Expand Down
Loading

0 comments on commit a4a78c4

Please sign in to comment.