Skip to content

Commit

Permalink
Provider Boosting implementation (#1694)
Browse files Browse the repository at this point in the history
# Goal
Implement a Provider Boost feature, whereby token holders may support
the network and a specific Provider by means of a custom staking model.
Token holders lock up a certain amount of token, and receive a return in
Frequency token for this support. The token holder chooses a Provider to
receive some Capacity, which the Provider may use to pay for chain
transactions.

Token holders may still stake for `MaximizedCapacity` and receive no
token return. As before, the entire benefit for staking would go to the
targeted Provider for this type.

#### For more details, please see the [Capacity Staking Rewards
Implementation](designdocs/capacity_staking_rewards_implementation.md)
design doc, which links to the economic model for this feature.
---------

Co-authored-by: Wil Wade <[email protected]>
Co-authored-by: Puneet Saraswat <[email protected]>
Co-authored-by: Aramik <[email protected]>
Co-authored-by: Matthew Orris <[email protected]>
Co-authored-by: Wil Wade <[email protected]>
  • Loading branch information
6 people authored Oct 31, 2024
1 parent 9dffba0 commit f862821
Show file tree
Hide file tree
Showing 47 changed files with 4,267 additions and 590 deletions.
13 changes: 13 additions & 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 @@ -118,6 +118,7 @@ serde_json = { version = "1.0.86", default-features = false }
tokio = { version = "1.25.0", default-features = false }
unicode-normalization = { version = "0.1.22", default-features = false }
clap = { version = "4.2.5", features = ["derive"] }
static_assertions = { version = "1.1.0", default-features = false }

sp-externalities = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", default-features = false}
sp-runtime-interface = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.13.0", default-features = false}
Expand Down
3 changes: 0 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,6 @@ benchmarks-multi:
benchmarks-multi-local:
./scripts/run_benchmarks.sh -t bench-dev $(PALLETS)

benchmarks-capacity:
./scripts/run_benchmark.sh -p capacity

.PHONY: docs
docs:
RUSTC_BOOTSTRAP=1 RUSTDOCFLAGS="--enable-index-page -Zunstable-options" cargo doc --no-deps --workspace --features frequency
Expand Down
41 changes: 35 additions & 6 deletions common/primitives/src/capacity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use crate::msa::MessageSourceId;
use frame_support::traits::tokens::Balance;
use scale_info::TypeInfo;
use sp_core::{Decode, Encode, MaxEncodedLen, RuntimeDebug};
use sp_runtime::DispatchError;

/// The type of a Reward Era
pub type RewardEra = u32;

/// A trait for checking that a target MSA can be staked to.
pub trait TargetValidator {
/// Checks if an MSA is a valid target.
Expand All @@ -15,19 +20,24 @@ impl TargetValidator for () {
}
}

/// A trait for Non-transferable asset.
/// A trait for Non-transferable asset
pub trait Nontransferable {
/// Scalar type for representing balance of an account.
type Balance: Balance;

/// The balance Capacity for an MSA account.
/// The available Capacity for an MSA.
fn balance(msa_id: MessageSourceId) -> Self::Balance;

/// Reduce Capacity of an MSA account by amount.
fn deduct(msa_id: MessageSourceId, amount: Self::Balance) -> Result<(), DispatchError>;
/// Reduce Capacity of an MSA by amount.
fn deduct(msa_id: MessageSourceId, capacity_amount: Self::Balance)
-> Result<(), DispatchError>;

/// Increase Capacity of an MSA account by an amount.
fn deposit(msa_id: MessageSourceId, amount: Self::Balance) -> Result<(), DispatchError>;
/// Increase Staked Token + Capacity amounts of an MSA. (unused)
fn deposit(
msa_id: MessageSourceId,
token_amount: Self::Balance,
capacity_amount: Self::Balance,
) -> Result<(), DispatchError>;
}

/// A trait for replenishing Capacity.
Expand All @@ -47,3 +57,22 @@ pub trait Replenishable {
/// Checks if an account can be replenished.
fn can_replenish(msa_id: MessageSourceId) -> bool;
}

/// Result of checking a Boost History item to see if it's eligible for a reward.
#[derive(
Copy, Clone, Default, Encode, Eq, Decode, RuntimeDebug, MaxEncodedLen, PartialEq, TypeInfo,
)]

pub struct UnclaimedRewardInfo<Balance, BlockNumber> {
/// The Reward Era for which this reward was earned
pub reward_era: RewardEra,
/// When this reward expires, i.e. can no longer be claimed
pub expires_at_block: BlockNumber,
/// The total staked in this era as of the current block
pub staked_amount: Balance,
/// The amount staked in this era that is eligible for rewards. Does not count additional amounts
/// staked in this era.
pub eligible_amount: Balance,
/// The amount in token of the reward (only if it can be calculated using only on chain data)
pub earned_amount: Balance,
}
444 changes: 249 additions & 195 deletions designdocs/capacity.md

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions designdocs/provider_boosting_economic_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ This document does not:

### Formula

The Provider Boost reward in FRQCY tokens for a given Era <i>e</i> is
The Provider Boost reward in FRQCY tokens for a given Era <i>e</i> is a simple interest model, with the following formula:

R = <i>min</i>(R<sub>era</sub>*L<sub>u</sub>/L<sub>T</sub>, L<sub>u</sub>*P<sub>max</sub>)

Put into words, if the pool of Rewards per Era is R<sub>era</sub> FRQCY, then the Reward amount in FRQCY earned by a given Provider Booster will be proportional to how much they've locked for Provider Boosting out of the total, OR P<sub>max</sub> times the amount locked, whichever is less.
Put into words, if the pool of Rewards per Era is

R<sub>era</sub> FRQCY, then the Reward amount in FRQCY earned by a given Provider Booster will be proportional to how much they've locked for Provider Boosting out of the total OR P<sub>max</sub> times the amount locked, whichever is less.

Put another way, there is a fixed number of tokens to be rewarded each Era (R<sub>era</sub>), split up according to each Provider Boost account holder's percentage of the locked total. However, the reward return each Era for every individual account (P<sub>max</sub>) is capped at some rate, for example, 10%.

Expand All @@ -93,4 +95,4 @@ Rewards are not prorated; they are calculated only for balances held for an enti
- Provider Boost Rewards are not minted until they are explicitly <i>claimed</i> by the Provider Boost account holder, by calling a non-free extrinsic.
- Rewards must be claimed within a certain number of Provider Boost Eras.
- When claimed, all available, unexpired Rewards for each previous Era are minted and transferred to the same account that locked them.
- **Is there a cap on how much can be claimed at once?**
- Currently there is no cap on how much can be claimed at once.
Loading

0 comments on commit f862821

Please sign in to comment.