Skip to content

Commit

Permalink
stake: fix collator fee to 20% (paritytech#306)
Browse files Browse the repository at this point in the history
* done

* bump spec

* fix types
  • Loading branch information
4meta5 committed Mar 29, 2021
1 parent bbb5448 commit 82cc7ed
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 69 deletions.
2 changes: 0 additions & 2 deletions moonbeam-types-bundle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,12 @@ export const moonbeamDefinitions = {
OrderedSet: "Vec<Bond>",
Collator: {
id: "AccountId",
fee: "Perbill",
bond: "Balance",
nominators: "Vec<Bond>",
total: "Balance",
state: "CollatorStatus",
},
CollatorSnapshot: {
fee: "Perbill",
bond: "Balance",
nominators: "Vec<Bond>",
total: "Balance",
Expand Down
40 changes: 27 additions & 13 deletions pallets/parachain-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ pub mod pallet {
#[derive(Default, Encode, Decode, RuntimeDebug)]
/// Snapshot of collator state at the start of the round for which they are selected
pub struct CollatorSnapshot<AccountId, Balance> {
pub fee: Perbill,
pub bond: Balance,
pub nominators: Vec<Bond<AccountId, Balance>>,
pub total: Balance,
Expand All @@ -141,7 +140,6 @@ pub mod pallet {
/// Global collator state with commission fee, bonded stake, and nominations
pub struct Collator<AccountId, Balance> {
pub id: AccountId,
pub fee: Perbill,
pub bond: Balance,
pub nominators: OrderedSet<Bond<AccountId, Balance>>,
pub total: Balance,
Expand All @@ -153,11 +151,10 @@ pub mod pallet {
B: AtLeast32BitUnsigned + Ord + Copy + sp_std::ops::AddAssign + sp_std::ops::SubAssign,
> Collator<A, B>
{
pub fn new(id: A, fee: Perbill, bond: B) -> Self {
pub fn new(id: A, bond: B) -> Self {
let total = bond;
Collator {
id,
fee,
bond,
nominators: OrderedSet::new(),
total,
Expand Down Expand Up @@ -216,7 +213,6 @@ pub mod pallet {
impl<A: Clone, B: Copy> From<Collator<A, B>> for CollatorSnapshot<A, B> {
fn from(other: Collator<A, B>) -> CollatorSnapshot<A, B> {
CollatorSnapshot {
fee: other.fee,
bond: other.bond,
nominators: other.nominators.0,
total: other.total,
Expand Down Expand Up @@ -389,8 +385,8 @@ pub mod pallet {
type MaxNominatorsPerCollator: Get<u32>;
/// Maximum collators per nominator
type MaxCollatorsPerNominator: Get<u32>;
/// Maximum fee for any collator
type MaxFee: Get<Perbill>;
/// Commission due to collators, set at genesis
type DefaultCollatorCommission: Get<Perbill>;
/// Minimum stake required for any account to be in `SelectedCandidates` for the round
type MinCollatorStk: Get<BalanceOf<Self>>;
/// Minimum stake required for any account to be a collator candidate
Expand All @@ -408,7 +404,6 @@ pub mod pallet {
CandidateDNE,
NominatorExists,
CandidateExists,
FeeOverMax,
ValBondBelowMin,
NomBondBelowMin,
NominationBelowMin,
Expand Down Expand Up @@ -462,6 +457,8 @@ pub mod pallet {
StakeExpectationsSet(BalanceOf<T>, BalanceOf<T>, BalanceOf<T>),
/// Set total selected candidates to this value [old, new]
TotalSelectedSet(u32, u32),
/// Set collator commission to this value [old, new]
CollatorCommissionSet(Perbill, Perbill),
/// Set blocks per round [current_round, first_block, old, new]
BlocksPerRoundSet(RoundIndex, T::BlockNumber, u32, u32),
}
Expand Down Expand Up @@ -493,6 +490,11 @@ pub mod pallet {
}
}

#[pallet::storage]
#[pallet::getter(fn collator_commission)]
/// Commission percent taken off of rewards for all collators
type CollatorCommission<T: Config> = StorageValue<_, Perbill, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn total_selected)]
/// The total candidates selected every round
Expand Down Expand Up @@ -622,11 +624,12 @@ pub mod pallet {
} else {
<Pallet<T>>::join_candidates(
T::Origin::from(Some(actor.clone()).into()),
Perbill::zero(), // default fee for collators registered at genesis is 0%
balance,
)
};
}
// Set collator commission to default config
<CollatorCommission<T>>::put(T::DefaultCollatorCommission::get());
// Set total selected candidates to minimum config
<TotalSelected<T>>::put(T::MinSelectedCandidates::get());
// Choose top TotalSelected collator candidates
Expand Down Expand Up @@ -700,6 +703,18 @@ pub mod pallet {
Ok(().into())
}
#[pallet::weight(0)]
/// Set the commission for all collators
pub fn set_collator_commission(
origin: OriginFor<T>,
pct: Perbill,
) -> DispatchResultWithPostInfo {
frame_system::ensure_root(origin)?;
let old = <CollatorCommission<T>>::get();
<CollatorCommission<T>>::put(pct);
Self::deposit_event(Event::CollatorCommissionSet(old, pct));
Ok(().into())
}
#[pallet::weight(0)]
/// Set blocks per round
/// - if called with `new` less than length of current round, will transition immediately
/// in the next block
Expand All @@ -720,13 +735,11 @@ pub mod pallet {
#[pallet::weight(0)]
pub fn join_candidates(
origin: OriginFor<T>,
fee: Perbill,
bond: BalanceOf<T>,
) -> DispatchResultWithPostInfo {
let acc = ensure_signed(origin)?;
ensure!(!Self::is_candidate(&acc), Error::<T>::CandidateExists);
ensure!(!Self::is_nominator(&acc), Error::<T>::NominatorExists);
ensure!(fee <= T::MaxFee::get(), Error::<T>::FeeOverMax);
ensure!(
bond >= T::MinCollatorCandidateStk::get(),
Error::<T>::ValBondBelowMin
Expand All @@ -740,7 +753,7 @@ pub mod pallet {
Error::<T>::CandidateExists
);
T::Currency::reserve(&acc, bond)?;
let candidate = Collator::new(acc.clone(), fee, bond);
let candidate = Collator::new(acc.clone(), bond);
let new_total = <Total<T>>::get() + bond;
<Total<T>>::put(new_total);
<CollatorState<T>>::insert(&acc, candidate);
Expand Down Expand Up @@ -1147,6 +1160,7 @@ pub mod pallet {
}
};
let duration = T::BondDuration::get();
let collator_fee = <CollatorCommission<T>>::get();
if next > duration {
let round_to_payout = next - duration;
let total = <Points<T>>::get(round_to_payout);
Expand All @@ -1166,7 +1180,7 @@ pub mod pallet {
} else {
// pay collator first; commission + due_portion
let val_pct = Perbill::from_rational(state.bond, state.total);
let commission = state.fee * amt_due;
let commission = collator_fee * amt_due;
let val_due = if commission > T::Currency::minimum_balance() {
amt_due -= commission;
(val_pct * amt_due) + commission
Expand Down
4 changes: 2 additions & 2 deletions pallets/parachain-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ parameter_types! {
pub const MinSelectedCandidates: u32 = 5;
pub const MaxNominatorsPerCollator: u32 = 4;
pub const MaxCollatorsPerNominator: u32 = 4;
pub const MaxFee: Perbill = Perbill::from_percent(50);
pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20);
pub const MinCollatorStk: u128 = 10;
pub const MinNominatorStk: u128 = 5;
pub const MinNomination: u128 = 3;
Expand All @@ -114,7 +114,7 @@ impl Config for Test {
type MinSelectedCandidates = MinSelectedCandidates;
type MaxNominatorsPerCollator = MaxNominatorsPerCollator;
type MaxCollatorsPerNominator = MaxCollatorsPerNominator;
type MaxFee = MaxFee;
type DefaultCollatorCommission = DefaultCollatorCommission;
type MinCollatorStk = MinCollatorStk;
type MinCollatorCandidateStk = MinCollatorStk;
type MinNominatorStk = MinNominatorStk;
Expand Down
82 changes: 33 additions & 49 deletions pallets/parachain-staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::mock::{
};
use crate::{CollatorStatus, Error, Event};
use frame_support::{assert_noop, assert_ok};
use sp_runtime::{traits::Zero, DispatchError, Perbill};
use sp_runtime::{traits::Zero, DispatchError};

#[test]
fn geneses() {
Expand Down Expand Up @@ -131,35 +131,27 @@ fn online_offline_works() {
fn join_collator_candidates() {
two_collators_four_nominators().execute_with(|| {
assert_noop!(
Stake::join_candidates(Origin::signed(1), Perbill::from_percent(2), 11u128,),
Stake::join_candidates(Origin::signed(1), 11u128,),
Error::<Test>::CandidateExists
);
assert_noop!(
Stake::join_candidates(Origin::signed(3), Perbill::from_percent(2), 11u128,),
Stake::join_candidates(Origin::signed(3), 11u128,),
Error::<Test>::NominatorExists
);
assert_noop!(
Stake::join_candidates(Origin::signed(7), Perbill::from_percent(2), 9u128,),
Stake::join_candidates(Origin::signed(7), 9u128,),
Error::<Test>::ValBondBelowMin
);
assert_noop!(
Stake::join_candidates(Origin::signed(8), Perbill::from_percent(2), 10u128,),
Stake::join_candidates(Origin::signed(8), 10u128,),
DispatchError::Module {
index: 1,
error: 3,
message: Some("InsufficientBalance")
}
);
assert_noop!(
Stake::join_candidates(Origin::signed(7), Perbill::from_percent(51), 10u128,),
Error::<Test>::FeeOverMax
);
assert!(System::events().is_empty());
assert_ok!(Stake::join_candidates(
Origin::signed(7),
Perbill::from_percent(3),
10u128,
));
assert_ok!(Stake::join_candidates(Origin::signed(7), 10u128,));
assert_eq!(
last_event(),
MetaEvent::stake(Event::JoinedCollatorCandidates(7, 10u128, 1110u128))
Expand Down Expand Up @@ -225,11 +217,7 @@ fn collator_selection_chooses_top_candidates() {
MetaEvent::stake(Event::CollatorScheduledExit(2, 6, 4))
);
roll_to(21);
assert_ok!(Stake::join_candidates(
Origin::signed(6),
Perbill::from_percent(2),
69u128
));
assert_ok!(Stake::join_candidates(Origin::signed(6), 69u128));
assert_eq!(
last_event(),
MetaEvent::stake(Event::JoinedCollatorCandidates(6, 69u128, 469u128))
Expand Down Expand Up @@ -448,11 +436,7 @@ fn collator_commission() {
Event::NewRound(5, 2, 1, 40),
];
assert_eq!(events(), expected);
assert_ok!(Stake::join_candidates(
Origin::signed(4),
Perbill::from_percent(20),
20u128
));
assert_ok!(Stake::join_candidates(Origin::signed(4), 20u128));
assert_eq!(
last_event(),
MetaEvent::stake(Event::JoinedCollatorCandidates(4, 20u128, 60u128))
Expand Down Expand Up @@ -783,10 +767,10 @@ fn payouts_follow_nomination_changes() {
Event::CollatorChosen(3, 3, 20),
Event::CollatorChosen(3, 5, 10),
Event::NewRound(10, 3, 5, 140),
Event::Rewarded(1, 20),
Event::Rewarded(6, 10),
Event::Rewarded(7, 10),
Event::Rewarded(10, 10),
Event::Rewarded(1, 26),
Event::Rewarded(6, 8),
Event::Rewarded(7, 8),
Event::Rewarded(10, 8),
Event::CollatorChosen(4, 1, 50),
Event::CollatorChosen(4, 2, 40),
Event::CollatorChosen(4, 4, 20),
Expand All @@ -810,10 +794,10 @@ fn payouts_follow_nomination_changes() {
let mut new2 = vec![
Event::NominatorLeftCollator(6, 1, 10, 40),
Event::NominatorLeft(6, 10),
Event::Rewarded(1, 21),
Event::Rewarded(6, 10),
Event::Rewarded(7, 10),
Event::Rewarded(10, 10),
Event::Rewarded(1, 27),
Event::Rewarded(6, 8),
Event::Rewarded(7, 8),
Event::Rewarded(10, 8),
Event::CollatorChosen(5, 2, 40),
Event::CollatorChosen(5, 1, 40),
Event::CollatorChosen(5, 4, 20),
Expand All @@ -828,10 +812,10 @@ fn payouts_follow_nomination_changes() {
roll_to(26);
// keep paying 6
let mut new3 = vec![
Event::Rewarded(1, 22),
Event::Rewarded(6, 11),
Event::Rewarded(7, 11),
Event::Rewarded(10, 11),
Event::Rewarded(1, 29),
Event::Rewarded(6, 9),
Event::Rewarded(7, 9),
Event::Rewarded(10, 9),
Event::CollatorChosen(6, 2, 40),
Event::CollatorChosen(6, 1, 40),
Event::CollatorChosen(6, 4, 20),
Expand All @@ -845,9 +829,9 @@ fn payouts_follow_nomination_changes() {
roll_to(31);
// no more paying 6
let mut new4 = vec![
Event::Rewarded(1, 29),
Event::Rewarded(7, 14),
Event::Rewarded(10, 14),
Event::Rewarded(1, 35),
Event::Rewarded(7, 11),
Event::Rewarded(10, 11),
Event::CollatorChosen(7, 2, 40),
Event::CollatorChosen(7, 1, 40),
Event::CollatorChosen(7, 4, 20),
Expand All @@ -863,9 +847,9 @@ fn payouts_follow_nomination_changes() {
// new nomination is not rewarded yet
let mut new5 = vec![
Event::Nomination(8, 10, 1, 50),
Event::Rewarded(1, 30),
Event::Rewarded(7, 15),
Event::Rewarded(10, 15),
Event::Rewarded(1, 36),
Event::Rewarded(7, 12),
Event::Rewarded(10, 12),
Event::CollatorChosen(8, 1, 50),
Event::CollatorChosen(8, 2, 40),
Event::CollatorChosen(8, 4, 20),
Expand All @@ -879,9 +863,9 @@ fn payouts_follow_nomination_changes() {
roll_to(41);
// new nomination is still not rewarded yet
let mut new6 = vec![
Event::Rewarded(1, 32),
Event::Rewarded(7, 16),
Event::Rewarded(10, 16),
Event::Rewarded(1, 38),
Event::Rewarded(7, 13),
Event::Rewarded(10, 13),
Event::CollatorChosen(9, 1, 50),
Event::CollatorChosen(9, 2, 40),
Event::CollatorChosen(9, 4, 20),
Expand All @@ -894,10 +878,10 @@ fn payouts_follow_nomination_changes() {
roll_to(46);
// new nomination is rewarded for first time, 2 rounds after joining (`BondDuration` = 2)
let mut new7 = vec![
Event::Rewarded(1, 27),
Event::Rewarded(7, 13),
Event::Rewarded(8, 13),
Event::Rewarded(10, 13),
Event::Rewarded(1, 35),
Event::Rewarded(7, 11),
Event::Rewarded(8, 11),
Event::Rewarded(10, 11),
Event::CollatorChosen(10, 1, 50),
Event::CollatorChosen(10, 2, 40),
Event::CollatorChosen(10, 4, 20),
Expand Down
6 changes: 3 additions & 3 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,8 @@ parameter_types! {
pub const MaxNominatorsPerCollator: u32 = 10;
/// Maximum 25 collators per nominator
pub const MaxCollatorsPerNominator: u32 = 25;
/// The maximum percent a collator can take off the top of its rewards is 50%
pub const MaxFee: Perbill = Perbill::from_percent(50);
/// The fixed percent a collator takes off the top of due rewards is 20%
pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20);
/// Minimum stake required to be reserved to be a collator is 1_000
pub const MinCollatorStk: u128 = 1_000 * GLMR;
/// Minimum stake required to be reserved to be a nominator is 5
Expand All @@ -409,7 +409,7 @@ impl parachain_staking::Config for Runtime {
type MinSelectedCandidates = MinSelectedCandidates;
type MaxNominatorsPerCollator = MaxNominatorsPerCollator;
type MaxCollatorsPerNominator = MaxCollatorsPerNominator;
type MaxFee = MaxFee;
type DefaultCollatorCommission = DefaultCollatorCommission;
type MinCollatorStk = MinCollatorStk;
type MinCollatorCandidateStk = MinCollatorStk;
type MinNomination = MinNominatorStk;
Expand Down

0 comments on commit 82cc7ed

Please sign in to comment.