From b9dcf89e58a7a6f16d58d5b55b4b3b1e15b0df43 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Fri, 7 Apr 2023 17:38:54 -0700 Subject: [PATCH 01/25] some words --- designdocs/capacity_staking_rewards.md | 84 ++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 designdocs/capacity_staking_rewards.md diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md new file mode 100644 index 0000000000..59a96b3116 --- /dev/null +++ b/designdocs/capacity_staking_rewards.md @@ -0,0 +1,84 @@ +# Capacity Staking Rewards + +## Context and Scope: +The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with FRQCY must: +1. Have an [MSA](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/accounts.md) +2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md) +3. Stake token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). + +The proposed feature is a design for staking FRQCY token in exchange for Capacity and/or FRQCY. +It consists of enhancements to the capacity pallet, needed traits and their implementations, and needed runtime configuration. + +[//]: # (A short description of the landscape in which the new system is being built, what is actually being built.) +[//]: # (It may also say what is not being built, and any assumptions.) +[//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) + +## Problem Statement: +To build a self-sustaining Frequency network, a variety of economic incentives are needed. One of these is the ability to stake token in return for something. + +[//]: # (The "why." A short summary of the issue(s) that this design solves. This doesn't have to be a technical problem, and it doesn't have to be a literal "problem." It could also be a necessary feature. "Developer unhappiness", "user experience needs improvement", are also problems.) + +## Goals +* Outline the architecture for the implementation of staking rewards for Capacity. +* Allow staking rewards to be adjusted without a chain upgrade. + +## Non-goals +* This does not determine the actual amount of rewards - either in Capacity or FRQCY - for staking. +* This does not account for other economic incentives on the Frequency network, such as collator rewards. +* This design does not (and cannot) account for token price in any other currency. +* It does not change how paying for transactions with Capacity works + +[//]: # (what this solution is trying to do, and is also not trying to do, in concrete terms. Measurable goals are best.) +[//]: # (## Glossary (optional):) +[//]: # (if you think inline links to concepts are too distracting, include a glossary section. This can be links, text or both.) + +## Proposal: +Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. +On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. +There are two types of staking, **Maximized Rewards** and **Simple Rewards**. +In both types, the staker designates a target Provider who receives capacity upon staking. +The difference is: + +* With **Maximized Rewards**, the target Provider receives more Capacity than it would with Simple Rewards. + The staker does not receive any token rewards. +* With **Simple Rewards**, the target Provider shares rewards with the staker. + The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. + + +[//]: # (A high level overview, followed by a detailed description.) +[//]: # (This is where specific technology, such as language, frameworks, encryption algorithms, type of authentication, and APIs can be described.) +[//]: # (It can include diagrams such as a system context diagram, or a sequence diagram.) + +## Benefits and Risks: +### Benefit: stabilizing message costs +Staking locks up token. Locked token may not be immediately withdrawn; this dampens some level of speculation-driven volatility as well as that driven by opportunistic Capacity purchases. + +### Benefit: engage and expand user base +A Provider may, for example, airdrop tokens to users who meet certain criteria, such as referrals or sharing links on other platforms. Users with token may choose Simple Reward staking to generate Capacity for their Provider and also get token rewards. + +### Benefit: improved economic sustainability +A staking reward system can improve /onboard/uptake/usage/... + +### Risk: Faulty reward calculations: +* Maximized Stake for capacity is not cheaper per txn than pay-as-you-go with token +* Maximized Stake for capacity pays better than staking to be a collator + +#### Mitigation: +Adjust reward amounts. This is why the reward amounts need to be adjustable. + +[//]: # (the reasons why this solution was chosen, and the risks this solution poses.) +[//]: # (For example, the solution may be very simple, but there could performance bottlenecks above a certain threshold.) +[//]: # (Another: the solution is well known and widely used, but it's not a perfect fit and requires complicated changes in one area.) + +## Alternatives and Rationale: +### 1. Providers simply purchase capacity without staking (locking token balance) +### 2. Accounts stake only for token and/or to be collators +### 3. Only Simple Rewards staking type +### 4. ?? + +[//]: # (discuss alternatives that were considered, and why they were rejected.) +[//]: # (Note when there are absolute requirements that the solution does not and can't meet. One example might be, it's a proprietary solution but we need something open source.) + +## Sources: + +[//]: # (sources of information that led to this design.) From 8ee145ff3f6f74ff2715abb9506ea91c88a94f7a Mon Sep 17 00:00:00 2001 From: shannonwells Date: Mon, 10 Apr 2023 17:13:05 -0700 Subject: [PATCH 02/25] outline some code requirements, reason about when to calculate and assign staking rewards --- designdocs/capacity_staking_rewards.md | 63 +++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 59a96b3116..817389440e 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -20,18 +20,20 @@ To build a self-sustaining Frequency network, a variety of economic incentives a ## Goals * Outline the architecture for the implementation of staking rewards for Capacity. -* Allow staking rewards to be adjusted without a chain upgrade. +* Allow staking rewards parameters to be adjusted without a chain upgrade. +* Design prevents rewards storage updates and calculations from excessive weighing down of blocks. ## Non-goals -* This does not determine the actual amount of rewards - either in Capacity or FRQCY - for staking. -* This does not account for other economic incentives on the Frequency network, such as collator rewards. -* This design does not (and cannot) account for token price in any other currency. -* It does not change how paying for transactions with Capacity works +* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking. +* Do not account for other economic incentives on the Frequency network, such as collator rewards. +* Cannot account for token price in any other currency. +* Do not change how paying for transactions with Capacity works [//]: # (what this solution is trying to do, and is also not trying to do, in concrete terms. Measurable goals are best.) [//]: # (## Glossary (optional):) [//]: # (if you think inline links to concepts are too distracting, include a glossary section. This can be links, text or both.) +--- ## Proposal: Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. @@ -44,16 +46,56 @@ The difference is: * With **Simple Rewards**, the target Provider shares rewards with the staker. The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. +## Staking Token Rewards +If Frequency were to wait until a withdrawal to calculate rewards, it would make accounting extremely complicated; since account holders may adjust their stake up or down, the chain would have to keep a ledger of amounts for every staking reward period, and if the reward rates change, that makes it even more complicated. Rewards may not be applied off-chain, since token balances and staking rewards are part of consensus, and must be validatable. + +### Some options considered: +1. Rewards are accounted for periodically all together, at once; this puts an extreme burden on one or more blocks due to storage updates. +2. At least some portion of rewards are accounted for every block, however, all rewards must be updated for all stakers within the Era. +3. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. + +### Why can't Frequency use Substrate `staking` pallet? [or can it?] +The staking pallet is for rewarding node validators, and rewards must be claimed within `HISTORY_DEPTH` blocks before the record of them is purged. Reward payouts for a given validator can be called by any account and the rewards go o the validator and are shared with its nominators. The staking pallet keeps track of what rewards have been claimed within that `HISTORY_DEPTH` number of blocks. + +Since Capacity Rewards staking is for FRQCY token account holders, we should not require those holders to have to call an extrinsic regularly to receive rewards. + +Secondly, we must plan for the number of Providers to dwarf the number of validators on the Polkadot Relay chain. The Polkadot relay chain currently has validators in the hundreds. Calculating the payouts for hundreds of items in RocksDB storage is a very different prospect than calculating rewards for thousands of Providers and potentially tens of millions (or more) of Rewards stakers. It may be that this type of optimization is deferred, however, this design must not make it difficult to optimize. + +### Properties and Pallet Storage +* `staking_type` (Maximized or Simple): An enum. A property on `StakingAccountDetails` +* `pub type RewardRate: StorageValue<_, uint16, ValueQuery>`: Stores the reward rate as hundredths of a percent; a reward rate of 1.25% would be stored as `125`. +* `pub type RewardFrequency StorageValue<_, , ValueQuery>`: Stores Reward frequency in number of epochs or blocks, **TBD** +* `pub type CapacityPriceMaximized StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Maximized Staking. +* `pub type CapacityPriceSimple StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Simple/Rewards Staking. + +### Capacity Pallet extrinsics +* `change_reward_rate(origin, rate)`: governance-only +* `change _reward_frequency(origin, period)`: governance-only +* `change_staking_type(origin, target, new_type)` +* `change_target(origin, old_target, new_target)`: + +### Capacity Pallet helper functions +* `participation_rate`: function, calculates participation using some combination of Total amount staked, reward Pool Token Size, the number of providers, the provider capacity amount (total?), individual amount staked (for individual reward amount only) +* `current_staking_reward(account_id, target)`: function, calculates the current rewards that would be paid out if the StakingAccount holder unstaked at the current block. +* `pay_reward`: function, + +### RPC +* `current_staking_reward()`: caller can force the calculation of a staking reward. + +### Other functions +* change_staking_type: a function on StakingAccountDetails +* [//]: # (A high level overview, followed by a detailed description.) [//]: # (This is where specific technology, such as language, frameworks, encryption algorithms, type of authentication, and APIs can be described.) [//]: # (It can include diagrams such as a system context diagram, or a sequence diagram.) +--- ## Benefits and Risks: -### Benefit: stabilizing message costs +### Benefit: stabler message costs Staking locks up token. Locked token may not be immediately withdrawn; this dampens some level of speculation-driven volatility as well as that driven by opportunistic Capacity purchases. -### Benefit: engage and expand user base +### Benefit: improved engagement and expanded user base A Provider may, for example, airdrop tokens to users who meet certain criteria, such as referrals or sharing links on other platforms. Users with token may choose Simple Reward staking to generate Capacity for their Provider and also get token rewards. ### Benefit: improved economic sustainability @@ -63,6 +105,13 @@ A staking reward system can improve /onboard/uptake/usage/... * Maximized Stake for capacity is not cheaper per txn than pay-as-you-go with token * Maximized Stake for capacity pays better than staking to be a collator +### Arguments in favor of storage values for reward rate and capacity price +* transparency: it's more transparent than a Config, which could be changed only by an upgrade. This is because changes to Config values can be easily overlooked if they are buried in a large upgrade. Making them be subject to governance approval puts the change on chain, making it more subject to review. +* stabler: reward rates and capacity prices would have an automatic upper limit to how frequently they could change. + +### Arguments against +* risk to network sustainability: it's possible that proposed changes which would actually be necessary to Frequency's economic stability and sustainability may be rejected by token voters. This is mitigated particularly at the start of Frequency's operation given the token distribution, and also with the voting power and permissions of Frequency and Technical Councils. + #### Mitigation: Adjust reward amounts. This is why the reward amounts need to be adjustable. From 559e55be66e298ac440a6f9df2c65aa4e6ac051f Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 12 Apr 2023 17:27:59 -0700 Subject: [PATCH 03/25] outline some more ideas, example code, example rewards formulas --- designdocs/capacity_staking_rewards.md | 147 ++++++++++++++++++++----- 1 file changed, 119 insertions(+), 28 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 817389440e..e925cd40e5 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -1,38 +1,71 @@ # Capacity Staking Rewards ## Context and Scope: -The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with FRQCY must: +The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with Capacity must: 1. Have an [MSA](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/accounts.md) -2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md) -3. Stake token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). +2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md)) +3. Stake a minimum amount of FRQCY token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). + +There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - known as _staking_ - while also targeting a Provider to receive some Capacity. The proposed feature is a design for staking FRQCY token in exchange for Capacity and/or FRQCY. +It is specific to the Frequency Substrate parachain. It consists of enhancements to the capacity pallet, needed traits and their implementations, and needed runtime configuration. +## Glossary +1. **FRQCY**: the native token of the Frequency blockchain +1. **Capacity**: the non-transferrable utility token which can be used only to pay for certain Frequency transactions. +1. **Account**: a Frequency System Account controlled by a private key and addressed by a public key, having at least a minimum balance (currently 1 FRQCY). +1. **Stake** (verb): to lock some amount of a token against transfer for a period of time in exchange for some reward. +1. **Era**: the time period (TBD in blocks or Capacity Epochs) that Staking Rewards are based upon. +1. **Staking Reward**: a per-Era share of a staking reward pool of FRQCY tokens for a given staking account. +1. **Reward Pool**: a fixed amount of FRQCY that can be minted for rewards each Era and distributed to stakers. + [//]: # (A short description of the landscape in which the new system is being built, what is actually being built.) [//]: # (It may also say what is not being built, and any assumptions.) [//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) ## Problem Statement: -To build a self-sustaining Frequency network, a variety of economic incentives are needed. One of these is the ability to stake token in return for something. +To build a self-sustaining Frequency network, a variety of economic incentives are needed. One of these is the ability to stake FRQCY token in return for something. [//]: # (The "why." A short summary of the issue(s) that this design solves. This doesn't have to be a technical problem, and it doesn't have to be a literal "problem." It could also be a necessary feature. "Developer unhappiness", "user experience needs improvement", are also problems.) +## Assumptions +* The exact formula for calculating rewards is provided in advance and used in the implementation of this design. +* The reward pool size is fixed until it is either set directly by governance or calculated from a value set by governance (which of these is TBD) +* Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. + +### Example possible calculations +There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated. +* Reward pool is like simple interest. Network rewards are fixed at M / total staked token, where M is some number set by governance. + +* Reward pool is linear, and is proportional to staked token and rewards decentralization of Providers. Example: + 1. Reward pool = (StakedToken + Providers\*1000) / 1000 + +* Reward pool is linear and rewards decentralization of stakers, decentralization of Providers. Example: + 1. Reward pool = N\*StakedToken + (M\*Stakers + P\*Providers) / 1000, where N, M, and P are constants set by governance. + +* Reward pool is a polynomial function: + 1. Reward pool = (N\*StakedToken + M\*Stakers^2 + P\*Providers^2) / sqrt(2), where N, M, and P are constants set by governance. + +* There is no fixed reward pool, but rewards per FRQCY staked are calculated based on a logarithmic function: + 1. RewardPerFRQCY = N * e^-2\*(M\*Stakers + P\*Providers), where N, M, and P are constants set by governance. + ## Goals * Outline the architecture for the implementation of staking rewards for Capacity. * Allow staking rewards parameters to be adjusted without a chain upgrade. -* Design prevents rewards storage updates and calculations from excessive weighing down of blocks. +* Prevent rewards storage operations and calculations from excessively weighing down blocks. +* Disallow receiving staking rewards for token that is not staked for a full Era. +* Prevent unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. +* Create a living design document that changes as compelling new findings and needs arise ## Non-goals -* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking. +* Do not finalize names, functions, storage types and shape of storage and structs +* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking * Do not account for other economic incentives on the Frequency network, such as collator rewards. * Cannot account for token price in any other currency. * Do not change how paying for transactions with Capacity works -[//]: # (what this solution is trying to do, and is also not trying to do, in concrete terms. Measurable goals are best.) -[//]: # (## Glossary (optional):) -[//]: # (if you think inline links to concepts are too distracting, include a glossary section. This can be links, text or both.) - --- ## Proposal: Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. @@ -41,27 +74,70 @@ There are two types of staking, **Maximized Rewards** and **Simple Rewards**. In both types, the staker designates a target Provider who receives capacity upon staking. The difference is: -* With **Maximized Rewards**, the target Provider receives more Capacity than it would with Simple Rewards. +* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Simple Rewards. The staker does not receive any token rewards. -* With **Simple Rewards**, the target Provider shares rewards with the staker. +* With **Rewards + Capacity Staking**, the target Provider shares rewards with the staker. The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. -## Staking Token Rewards -If Frequency were to wait until a withdrawal to calculate rewards, it would make accounting extremely complicated; since account holders may adjust their stake up or down, the chain would have to keep a ledger of amounts for every staking reward period, and if the reward rates change, that makes it even more complicated. Rewards may not be applied off-chain, since token balances and staking rewards are part of consensus, and must be validatable. - -### Some options considered: -1. Rewards are accounted for periodically all together, at once; this puts an extreme burden on one or more blocks due to storage updates. -2. At least some portion of rewards are accounted for every block, however, all rewards must be updated for all stakers within the Era. -3. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. +Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. -### Why can't Frequency use Substrate `staking` pallet? [or can it?] -The staking pallet is for rewarding node validators, and rewards must be claimed within `HISTORY_DEPTH` blocks before the record of them is purged. Reward payouts for a given validator can be called by any account and the rewards go o the validator and are shared with its nominators. The staking pallet keeps track of what rewards have been claimed within that `HISTORY_DEPTH` number of blocks. +Whenever a Rewards Pool calculation is changed, it goes into effect at the start of the next Era. The new Rewards parameters are pushed to storage, and, assuming the history queue is full, the oldest one is removed. -Since Capacity Rewards staking is for FRQCY token account holders, we should not require those holders to have to call an extrinsic regularly to receive rewards. +A special condition of this is a blend of the above: some staking accounts are large enough that if their balance changes significantly, it can affect the Reward Pool significantly for all staking accounts. We choose to -Secondly, we must plan for the number of Providers to dwarf the number of validators on the Polkadot Relay chain. The Polkadot relay chain currently has validators in the hundreds. Calculating the payouts for hundreds of items in RocksDB storage is a very different prospect than calculating rewards for thousands of Providers and potentially tens of millions (or more) of Rewards stakers. It may be that this type of optimization is deferred, however, this design must not make it difficult to optimize. +## Staking Token Rewards -### Properties and Pallet Storage +### StakingAccountDetails updates +We add a new field, `last_rewarded_at`, to keep track of the last time rewards were claimed for this Staking Account. +```rust +pub struct StakingAccountDetails { + pub active: BalanceOf, + pub total: BalanceOf, + pub unlocking: BoundedVec, T::EpochNumber>, T::MaxUnlockingChunks>, + /// The number of the last StakingEra that this account's rewards were claimed. + pub last_rewarded_at: T::StakingEra, // NEW +} +``` + +### New storage items and related types + +#### RewardsPoolHistory and RewardsPoolParameters +We store changes to the Rewards Pool calculations when any change occurs that affects the Rewards Pool greater than or equal to a hundredth of a percent (0.01%), rounded up, or when Rewards Pool Parameters are changed. + +**Toy Example:** +Let's assume a simple reward pool calculation relates to total token staked and the number of stakers, multiplied by some constant: +```rust +RewardPoolTokenAmount = (TotalToken + 1000*NumStakers) + _____________________________ + 100,000 +``` +Say total staked token is 100k FRQCY, there are 25 stakers, and Moby staker has staked 20k FRQCY. The reward pool starts at 125k/100k = 1.25 FRQCY to spread among 25 stakers based on their stake. + +Moby account unstakes 10k FRQCY, which drops staked token by 10%. The new reward pool is (90,000 + 25,000) / 100,000 = 1.15 FRQCY to spread among the stakers. This causes the Reward Pool to go down by 12%, which is much larger than 0.01%), so a new entry is pushed into the RewardPool history. + +```rust +/// A queue of the last `RewardsPoolHistoryMaxDepth` RewardsPoolParameters. +type RewardsPoolHistory: BoundedVec, T::RewardsPoolHistoryMaxDepth>; +``` + +```rust +/// The parameters for a rewards pool that applied from `applied_at` StakingEra to the next time +/// the parameters changed. +pub struct RewardsPoolParameters { + /// the total of all FRQCY staked when these parameters were applied + pub staking_total: BalanceOf, + /// the size of the rewards pool when these parameters were applied + pub rewards_pool_total: BalanceOf + /// the first era these parameters were applied + pub applied_at: T::StakingEra, + /// the number of providers + pub providers: uint32, + /// the number of stakers + pub stakers: uint32, +} +``` + +### Properties and Pallet Storage (DRAFT! some of these are just a guess!) * `staking_type` (Maximized or Simple): An enum. A property on `StakingAccountDetails` * `pub type RewardRate: StorageValue<_, uint16, ValueQuery>`: Stores the reward rate as hundredths of a percent; a reward rate of 1.25% would be stored as `125`. * `pub type RewardFrequency StorageValue<_, , ValueQuery>`: Stores Reward frequency in number of epochs or blocks, **TBD** @@ -80,11 +156,10 @@ Secondly, we must plan for the number of Providers to dwarf the number of valida * `pay_reward`: function, ### RPC -* `current_staking_reward()`: caller can force the calculation of a staking reward. +* `unclaimed_staking_reward()`: caller can query unclaimed staking reward. ### Other functions -* change_staking_type: a function on StakingAccountDetails -* +* `change_staking_type`: a function on StakingAccountDetails (? maybe you have to unstake and restake to do this) [//]: # (A high level overview, followed by a detailed description.) [//]: # (This is where specific technology, such as language, frameworks, encryption algorithms, type of authentication, and APIs can be described.) @@ -120,10 +195,26 @@ Adjust reward amounts. This is why the reward amounts need to be adjustable. [//]: # (Another: the solution is well known and widely used, but it's not a perfect fit and requires complicated changes in one area.) ## Alternatives and Rationale: +If Frequency were to wait until a withdrawal to calculate rewards, it would make accounting extremely complicated; since account holders may adjust their stake up or down, the chain would have to keep a ledger of amounts for every staking reward period, and if the reward rates change, that makes it even more complicated. Rewards may not be applied off-chain, since token balances and staking rewards are part of consensus, and must be validatable. + + ### 1. Providers simply purchase capacity without staking (locking token balance) ### 2. Accounts stake only for token and/or to be collators ### 3. Only Simple Rewards staking type -### 4. ?? +### 4. Rewards are accounted for periodically all together, at once. +this puts an extreme burden on one or more blocks due to storage updates. +### 5. At least some portion of rewards are accounted for every block; all rewards are updated for all stakers within the Era. +This effectively creates a constant overhead, but this approach causes much heavier blocks than the chosen solution. +### 6. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. +### 7. Pay rewards out every time there is a change for a given token staking account, or a change in Rewards parameters. +Since the only thing that changes staking rewards is the `StakingAccountDetails.total`, unless the Rewards calculation changes, we don't need to do a sweep unless the staker changes their total, either through staking more or unstaking. This minimizes the average block burden significantly, however, occasionally, when the Rewards calculation changes, block time will be slower for the next Era due to rewards payouts. + +### Why can't Frequency use Substrate `staking` pallet? +The staking pallet is for rewarding node validators, and rewards must be claimed within `HISTORY_DEPTH` blocks before the record of them is purged. Reward payouts for a given validator can be called by any account and the rewards go o the validator and are shared with its nominators. The staking pallet keeps track of what rewards have been claimed within that `HISTORY_DEPTH` number of blocks. + +Since Capacity Rewards staking is for FRQCY token account holders, we should not require those holders to have to call an extrinsic regularly to receive rewards. + +Secondly, we must plan for the number of Providers to dwarf the number of validators on the Polkadot Relay chain. The Polkadot relay chain currently has validators in the hundreds. Calculating the payouts for hundreds of items in RocksDB storage is a very different prospect than calculating rewards for thousands of Providers and potentially tens of millions (or more) of Rewards stakers. It may be that this type of optimization is deferred, however, this design must not make it difficult to optimize. [//]: # (discuss alternatives that were considered, and why they were rejected.) [//]: # (Note when there are absolute requirements that the solution does not and can't meet. One example might be, it's a proprietary solution but we need something open source.) From 2561d977eb34b6f90955b8340aaa87005bdd4e8c Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 12 Apr 2023 17:30:56 -0700 Subject: [PATCH 04/25] unstaking and staking spam --- designdocs/capacity_staking_rewards.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index e925cd40e5..ab5b2a948c 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -56,7 +56,7 @@ There are many possible calculations but here are some ideas about what factors * Allow staking rewards parameters to be adjusted without a chain upgrade. * Prevent rewards storage operations and calculations from excessively weighing down blocks. * Disallow receiving staking rewards for token that is not staked for a full Era. -* Prevent unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. +* Prevent staking and unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. * Create a living design document that changes as compelling new findings and needs arise ## Non-goals From 82dbad0345eacde724d84ce4f3592c332d6f9a8d Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 12 Apr 2023 17:46:18 -0700 Subject: [PATCH 05/25] allow rewards to be claimed via extrinsic --- designdocs/capacity_staking_rewards.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index ab5b2a948c..de7df76a41 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -79,11 +79,13 @@ The difference is: * With **Rewards + Capacity Staking**, the target Provider shares rewards with the staker. The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. -Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. + +Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. Rewards may also be claimed directly for a specific AccountId by calling an extrinsic. In either case, `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. + Whenever a Rewards Pool calculation is changed, it goes into effect at the start of the next Era. The new Rewards parameters are pushed to storage, and, assuming the history queue is full, the oldest one is removed. -A special condition of this is a blend of the above: some staking accounts are large enough that if their balance changes significantly, it can affect the Reward Pool significantly for all staking accounts. We choose to +A special condition of this is a blend of the above: some staking accounts could be large enough that if their staking balance changes significantly, it also affects the Reward Pool significantly for all staking accounts. Such accounts are called "whales" in blockchain jargon. We deem "significant" change as greater than or equal to one hundredth of a percent (0.01%), rounded. If so, a new set of Rewards parameters is pushed. We _may_ need to extend the thaw period for a staking account when their unstaking will cause a RewardsPool history push, in order to strongly reduce incentives for staking/unstaking spam. ## Staking Token Rewards @@ -102,7 +104,7 @@ pub struct StakingAccountDetails { ### New storage items and related types #### RewardsPoolHistory and RewardsPoolParameters -We store changes to the Rewards Pool calculations when any change occurs that affects the Rewards Pool greater than or equal to a hundredth of a percent (0.01%), rounded up, or when Rewards Pool Parameters are changed. +We store changes to the Rewards Pool calculations when any change occurs that affects the Rewards Pool greater than or equal to a hundredth of a percent (0.01%), rounded, or when Rewards Pool Parameters are changed. **Toy Example:** Let's assume a simple reward pool calculation relates to total token staked and the number of stakers, multiplied by some constant: @@ -113,7 +115,7 @@ RewardPoolTokenAmount = (TotalToken + 1000*NumStakers) ``` Say total staked token is 100k FRQCY, there are 25 stakers, and Moby staker has staked 20k FRQCY. The reward pool starts at 125k/100k = 1.25 FRQCY to spread among 25 stakers based on their stake. -Moby account unstakes 10k FRQCY, which drops staked token by 10%. The new reward pool is (90,000 + 25,000) / 100,000 = 1.15 FRQCY to spread among the stakers. This causes the Reward Pool to go down by 12%, which is much larger than 0.01%), so a new entry is pushed into the RewardPool history. +Moby account unstakes 10k FRQCY, which drops staked token by 10%. The new reward pool is (90,000 + 25,000) / 100,000 = 1.15 FRQCY to spread among the stakers. This causes the Reward Pool to go down by 12%, i.e. >0.01%, so a new entry is pushed into the RewardPool history. ```rust /// A queue of the last `RewardsPoolHistoryMaxDepth` RewardsPoolParameters. @@ -148,7 +150,8 @@ pub struct RewardsPoolParameters { * `change_reward_rate(origin, rate)`: governance-only * `change _reward_frequency(origin, period)`: governance-only * `change_staking_type(origin, target, new_type)` -* `change_target(origin, old_target, new_target)`: +* `change_target(origin, old_target, new_target)` +* `claim_staking_reward(origin)` ### Capacity Pallet helper functions * `participation_rate`: function, calculates participation using some combination of Total amount staked, reward Pool Token Size, the number of providers, the provider capacity amount (total?), individual amount staked (for individual reward amount only) @@ -156,7 +159,7 @@ pub struct RewardsPoolParameters { * `pay_reward`: function, ### RPC -* `unclaimed_staking_reward()`: caller can query unclaimed staking reward. +* `unclaimed_staking_reward(account_id: AccountId) -> BalanceOf`: caller can query the unclaimed staking reward for a given AccountId. ### Other functions * `change_staking_type`: a function on StakingAccountDetails (? maybe you have to unstake and restake to do this) From 7b34382636a73319cebf184e7b5351f2fc0c8b25 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 12 Apr 2023 17:48:09 -0700 Subject: [PATCH 06/25] remove bad argument --- designdocs/capacity_staking_rewards.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index de7df76a41..d2b05d43ba 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -198,8 +198,6 @@ Adjust reward amounts. This is why the reward amounts need to be adjustable. [//]: # (Another: the solution is well known and widely used, but it's not a perfect fit and requires complicated changes in one area.) ## Alternatives and Rationale: -If Frequency were to wait until a withdrawal to calculate rewards, it would make accounting extremely complicated; since account holders may adjust their stake up or down, the chain would have to keep a ledger of amounts for every staking reward period, and if the reward rates change, that makes it even more complicated. Rewards may not be applied off-chain, since token balances and staking rewards are part of consensus, and must be validatable. - ### 1. Providers simply purchase capacity without staking (locking token balance) ### 2. Accounts stake only for token and/or to be collators From 885ec73c3ef7b9aa46648314c00e268962baa7e7 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 12 Apr 2023 17:49:44 -0700 Subject: [PATCH 07/25] remove irrelevant non-choices --- designdocs/capacity_staking_rewards.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index d2b05d43ba..bae62dd10c 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -199,15 +199,13 @@ Adjust reward amounts. This is why the reward amounts need to be adjustable. ## Alternatives and Rationale: -### 1. Providers simply purchase capacity without staking (locking token balance) -### 2. Accounts stake only for token and/or to be collators -### 3. Only Simple Rewards staking type -### 4. Rewards are accounted for periodically all together, at once. +### 1. Rewards are accounted for periodically all together, at once. this puts an extreme burden on one or more blocks due to storage updates. -### 5. At least some portion of rewards are accounted for every block; all rewards are updated for all stakers within the Era. +### 2. At least some portion of rewards are accounted for every block; all rewards are updated for all stakers within the Era. This effectively creates a constant overhead, but this approach causes much heavier blocks than the chosen solution. -### 6. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. -### 7. Pay rewards out every time there is a change for a given token staking account, or a change in Rewards parameters. +### 3. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. +This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. +### 4. Pay rewards out every time there is a change for a given token staking account, or a change in Rewards parameters. Since the only thing that changes staking rewards is the `StakingAccountDetails.total`, unless the Rewards calculation changes, we don't need to do a sweep unless the staker changes their total, either through staking more or unstaking. This minimizes the average block burden significantly, however, occasionally, when the Rewards calculation changes, block time will be slower for the next Era due to rewards payouts. ### Why can't Frequency use Substrate `staking` pallet? From 4461807e1f6d65e2bb7ac77c4152269a0acfdb2b Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 18 Apr 2023 17:32:12 -0700 Subject: [PATCH 08/25] thoughts --- designdocs/capacity_staking_rewards.md | 65 ++++++++++++++++++++------ 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index bae62dd10c..39e3193e9a 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -15,7 +15,7 @@ It consists of enhancements to the capacity pallet, needed traits and their impl ## Glossary 1. **FRQCY**: the native token of the Frequency blockchain 1. **Capacity**: the non-transferrable utility token which can be used only to pay for certain Frequency transactions. -1. **Account**: a Frequency System Account controlled by a private key and addressed by a public key, having at least a minimum balance (currently 1 FRQCY). +1. **Account**: a Frequency System Account controlled by a private key and addressed by a public key, having at least a minimum balance (currently 0.01 FRQCY). 1. **Stake** (verb): to lock some amount of a token against transfer for a period of time in exchange for some reward. 1. **Era**: the time period (TBD in blocks or Capacity Epochs) that Staking Rewards are based upon. 1. **Staking Reward**: a per-Era share of a staking reward pool of FRQCY tokens for a given staking account. @@ -26,30 +26,67 @@ It consists of enhancements to the capacity pallet, needed traits and their impl [//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) ## Problem Statement: -To build a self-sustaining Frequency network, a variety of economic incentives are needed. One of these is the ability to stake FRQCY token in return for something. - -[//]: # (The "why." A short summary of the issue(s) that this design solves. This doesn't have to be a technical problem, and it doesn't have to be a literal "problem." It could also be a necessary feature. "Developer unhappiness", "user experience needs improvement", are also problems.) +A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. +To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. ## Assumptions * The exact formula for calculating rewards is provided in advance and used in the implementation of this design. * The reward pool size is fixed until it is either set directly by governance or calculated from a value set by governance (which of these is TBD) * Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. +* Like other blockchains, we round away "dust", values that are 10-6 FRQCY or less. (??) + +## Economic Model +By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. + +Inputs in the economic model to consider could include: +* Proportion of accounts are staking to total accounts +* Mean number MSAs per Provider, or the mean compared to median. +* Proportion of token staked to free balance held by non-Treasury accounts +* The Capacity-per-Epoch use rate, perhaps averaged over N epochs +* The length of an Epoch in blocks +* The length of an Era n blocks + +These could be used to adjust the cost of capacity and the reward return percentage. + +Example 1: We want a specific percentage of token accounts to stake in order to meet a certain decentralization goal, and we are below that amount. We increase the reward rate to encourage token holders to stake, without adjusting the cost of capacity. + +Example 2: Capacity is consistently under-utilized: We could decrease the cost of Capacity without changing the reward rate to encourage all Providers to post more often. We could also decrease the reward rate, which would cause some unstaking and reduce the available Capacity in the network. + +Example 3: The median is significantly higher than the mean, which means a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. ### Example possible calculations -There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated. -* Reward pool is like simple interest. Network rewards are fixed at M / total staked token, where M is some number set by governance. +There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). For a reward pool P, Staked Token t, Stakers s, Providers p: + +* Reward is like simple interest. Network rewards are fixed at M / total staked token, where M is some number set by governance. + +$$ P = {M \over t} $$ + +* Reward pool is linear and rewards decentralization of stakers and Providers. Example: + +$$ P = {Nt + Ms + Pp \over 100} $$, + +where N, M, and P are constants set by governance. + +* Reward pool is some polynomial: + +$$ P = Nt + Ms^2 + Pp^2 $$ + +* Rewards/Capacity are based on a more complex equation, which depends on the size of the targeted Provider. +We could implement diminishing returns on rewards and/or capacity, such as with a natural log function. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. + +Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It should be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. + +Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. Furthermore, large Providers will make a much bigger hit on database access than smaller ones. + +A log or ln function would have increasing diminishing returns, which would make growth increasingly more expensive. -* Reward pool is linear, and is proportional to staked token and rewards decentralization of Providers. Example: - 1. Reward pool = (StakedToken + Providers\*1000) / 1000 +$$ R = N\log{ (Ms + Pp) } $$ -* Reward pool is linear and rewards decentralization of stakers, decentralization of Providers. Example: - 1. Reward pool = N\*StakedToken + (M\*Stakers + P\*Providers) / 1000, where N, M, and P are constants set by governance. +A simple power law could suffice for the Capacity/Reward per token -* Reward pool is a polynomial function: - 1. Reward pool = (N\*StakedToken + M\*Stakers^2 + P\*Providers^2) / sqrt(2), where N, M, and P are constants set by governance. +$$ R = { N(x-Ti)^j } $$ -* There is no fixed reward pool, but rewards per FRQCY staked are calculated based on a logarithmic function: - 1. RewardPerFRQCY = N * e^-2\*(M\*Stakers + P\*Providers), where N, M, and P are constants set by governance. +Where N is a governance constant, Ti is the initial price for one unit of Capacity, and j is a positive integer < 1. ## Goals * Outline the architecture for the implementation of staking rewards for Capacity. From 5efb0530b3942b9a25f7be073c42ef10f40c7a8f Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 18 Apr 2023 17:51:45 -0700 Subject: [PATCH 09/25] changed my mind --- designdocs/capacity_staking_rewards.md | 29 ++++++++++---------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 39e3193e9a..2824b30bb5 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -69,25 +69,15 @@ where N, M, and P are constants set by governance. * Reward pool is some polynomial: -$$ P = Nt + Ms^2 + Pp^2 $$ +$$ P = { Nt + Ms^n + Pp^2 } $$ * Rewards/Capacity are based on a more complex equation, which depends on the size of the targeted Provider. -We could implement diminishing returns on rewards and/or capacity, such as with a natural log function. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. +We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It should be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. Furthermore, large Providers will make a much bigger hit on database access than smaller ones. -A log or ln function would have increasing diminishing returns, which would make growth increasingly more expensive. - -$$ R = N\log{ (Ms + Pp) } $$ - -A simple power law could suffice for the Capacity/Reward per token - -$$ R = { N(x-Ti)^j } $$ - -Where N is a governance constant, Ti is the initial price for one unit of Capacity, and j is a positive integer < 1. - ## Goals * Outline the architecture for the implementation of staking rewards for Capacity. * Allow staking rewards parameters to be adjusted without a chain upgrade. @@ -138,18 +128,21 @@ pub struct StakingAccountDetails { } ``` +**Unstaking thaw period** (Maybe) +We change the thaw period to begin at the first block of next Epoch instead of immediately. + ### New storage items and related types #### RewardsPoolHistory and RewardsPoolParameters We store changes to the Rewards Pool calculations when any change occurs that affects the Rewards Pool greater than or equal to a hundredth of a percent (0.01%), rounded, or when Rewards Pool Parameters are changed. -**Toy Example:** +**Toy Example using a very simple rewards equation:** Let's assume a simple reward pool calculation relates to total token staked and the number of stakers, multiplied by some constant: -```rust -RewardPoolTokenAmount = (TotalToken + 1000*NumStakers) - _____________________________ - 100,000 -``` + +$$ P = { t + Cs \over 100,000 } $$$ + +Where P is the Reward Pool Total, t is total staked token and s is the number of stakers as before. + Say total staked token is 100k FRQCY, there are 25 stakers, and Moby staker has staked 20k FRQCY. The reward pool starts at 125k/100k = 1.25 FRQCY to spread among 25 stakers based on their stake. Moby account unstakes 10k FRQCY, which drops staked token by 10%. The new reward pool is (90,000 + 25,000) / 100,000 = 1.15 FRQCY to spread among the stakers. This causes the Reward Pool to go down by 12%, i.e. >0.01%, so a new entry is pushed into the RewardPool history. From bff052a641f30ca4543695bb8176583cf4493f7b Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Tue, 18 Apr 2023 18:04:42 -0700 Subject: [PATCH 10/25] Update capacity_staking_rewards.md Some corrections --- designdocs/capacity_staking_rewards.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 2824b30bb5..d37dcc3e68 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -30,11 +30,15 @@ A system consisting only of providers and coinless users who delegate to provide To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. ## Assumptions -* The exact formula for calculating rewards is provided in advance and used in the implementation of this design. -* The reward pool size is fixed until it is either set directly by governance or calculated from a value set by governance (which of these is TBD) +* The exact formula for calculating rewards is determined in advance and used in the implementation of this design. * Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. * Like other blockchains, we round away "dust", values that are 10-6 FRQCY or less. (??) +## To be decided: +* Is Reward Pool fixed? +* What are the inputs to the economic model? +* How does the capacity generated from Maximized Capacity Staking different from that from Rewards Capacity Staking? + ## Economic Model By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. @@ -54,7 +58,7 @@ Example 2: Capacity is consistently under-utilized: We could decrease the cost Example 3: The median is significantly higher than the mean, which means a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. -### Example possible calculations +### Example possible calculations for rewards: There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). For a reward pool P, Staked Token t, Stakers s, Providers p: * Reward is like simple interest. Network rewards are fixed at M / total staked token, where M is some number set by governance. @@ -63,13 +67,13 @@ $$ P = {M \over t} $$ * Reward pool is linear and rewards decentralization of stakers and Providers. Example: -$$ P = {Nt + Ms + Pp \over 100} $$, +$$ P = {Nt + Ms + Pp \over 100} $$ where N, M, and P are constants set by governance. * Reward pool is some polynomial: -$$ P = { Nt + Ms^n + Pp^2 } $$ +$$ P = { Nt + Ms^i + Pp^j } $$ * Rewards/Capacity are based on a more complex equation, which depends on the size of the targeted Provider. We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. @@ -97,13 +101,13 @@ Since there is no difference to the chain for what Provider is posting what mess ## Proposal: Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. -There are two types of staking, **Maximized Rewards** and **Simple Rewards**. +There are two types of staking, **Maximized Capacity Staking** and **Rewards Capacity Staking**. In both types, the staker designates a target Provider who receives capacity upon staking. The difference is: -* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Simple Rewards. +* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Rewards Capacity Staking. The staker does not receive any token rewards. -* With **Rewards + Capacity Staking**, the target Provider shares rewards with the staker. +* With **Rewards Capacity Staking**, the target Provider shares rewards with the staker. The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. @@ -170,11 +174,11 @@ pub struct RewardsPoolParameters { ``` ### Properties and Pallet Storage (DRAFT! some of these are just a guess!) -* `staking_type` (Maximized or Simple): An enum. A property on `StakingAccountDetails` +* `staking_type` (Maximized or Rewards): An enum. A property on `StakingAccountDetails` * `pub type RewardRate: StorageValue<_, uint16, ValueQuery>`: Stores the reward rate as hundredths of a percent; a reward rate of 1.25% would be stored as `125`. * `pub type RewardFrequency StorageValue<_, , ValueQuery>`: Stores Reward frequency in number of epochs or blocks, **TBD** * `pub type CapacityPriceMaximized StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Maximized Staking. -* `pub type CapacityPriceSimple StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Simple/Rewards Staking. +* `pub type CapacityPriceRewards StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Rewards Staking. ### Capacity Pallet extrinsics * `change_reward_rate(origin, rate)`: governance-only @@ -204,7 +208,7 @@ pub struct RewardsPoolParameters { Staking locks up token. Locked token may not be immediately withdrawn; this dampens some level of speculation-driven volatility as well as that driven by opportunistic Capacity purchases. ### Benefit: improved engagement and expanded user base -A Provider may, for example, airdrop tokens to users who meet certain criteria, such as referrals or sharing links on other platforms. Users with token may choose Simple Reward staking to generate Capacity for their Provider and also get token rewards. +A Provider may, for example, airdrop tokens to users who meet certain criteria, such as referrals or sharing links on other platforms. Users with token may choose Reward staking to generate Capacity for their Provider and also get token rewards. ### Benefit: improved economic sustainability A staking reward system can improve /onboard/uptake/usage/... From 8fe7169bc7833142e4fbda0275bee796ce791c24 Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Wed, 19 Apr 2023 17:19:28 -0700 Subject: [PATCH 11/25] Formatting, eqns --- designdocs/capacity_staking_rewards.md | 55 ++++++++++++++++---------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index d37dcc3e68..65e4d82d55 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -29,15 +29,19 @@ It consists of enhancements to the capacity pallet, needed traits and their impl A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. +How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users stake, then they lose capacity if those end users unstake. If a Provider's Capacity from Reward staking is significant, this gives Reward Stakers some power over Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should be if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. + +We imagine that FRQCY could be airdropped by various entities to encourage onboarding, including Providers themselves. Providers may offer airdrops in exchange for such things as bringing in new users, or sharing links on other platforms, then encourage their users to stake their FRQCY for rewards. Rewards could be exchanged for in-dApp benefits such as premium features, special emoji, avatar customization, and the like. Rewards Staking could also unlock features. + ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. * Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. -* Like other blockchains, we round away "dust", values that are 10-6 FRQCY or less. (??) +* Like other blockchains, we round away "dust", values that are _10-tbd_ FRQCY or less. ## To be decided: -* Is Reward Pool fixed? -* What are the inputs to the economic model? -* How does the capacity generated from Maximized Capacity Staking different from that from Rewards Capacity Staking? +* Is Reward Pool token total itself fixed (with input values determined by governance), or is it the Reward _rate_ that is fixed? +* What are the inputs to the economic model(s) for Capacity generation and Rewards? +* How does the capacity generated by Maximized Capacity Staking differ from that generated by Rewards Capacity Staking? Maximized is more than Rewards, but by how much? ## Economic Model By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. @@ -59,28 +63,30 @@ Example 2: Capacity is consistently under-utilized: We could decrease the cost Example 3: The median is significantly higher than the mean, which means a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. ### Example possible calculations for rewards: -There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). For a reward pool P, Staked Token t, Stakers s, Providers p: - -* Reward is like simple interest. Network rewards are fixed at M / total staked token, where M is some number set by governance. - -$$ P = {M \over t} $$ - -* Reward pool is linear and rewards decentralization of stakers and Providers. Example: - -$$ P = {Nt + Ms + Pp \over 100} $$ - -where N, M, and P are constants set by governance. - -* Reward pool is some polynomial: - -$$ P = { Nt + Ms^i + Pp^j } $$ +There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_: + +| Description| Governance constants | Equation| +|------------|----------------------|---------| +| Like simple interest, _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | +| _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | +| Reward pool is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | +| Reward pool is a simple ratio | D, rm, rc | $P = D{1 - r_{c} \over m_{c}}$ | +* : + 1. Governance sets the Maximized Capacity Staking price (currently 50:1 FRQC:Capacity). + 2. Governance sets the Rewards Capacity Staking price -- the Capacity portion + 3. Governance may further choose a distribution period constant, D. + +where rc = Rewards Capacity generated, and mc = how much Capacity would have been generated if it were all Maximized Staking. +The constant C would be <1 so that difference is split over some number of Eras to encourage longer term staking. For instance C could be 1/30 and Eras = 1 Epoch (a day), so it takes 30 days to get rewarded the FRQCY equivalent of your "share" of Capacity. * Rewards/Capacity are based on a more complex equation, which depends on the size of the targeted Provider. We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. -Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It should be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. +Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It would need to be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. -Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. Furthermore, large Providers will make a much bigger hit on database access than smaller ones. +Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. + +### One way to set the difference between Maximized and Reward Staking ## Goals * Outline the architecture for the implementation of staking rewards for Capacity. @@ -213,6 +219,13 @@ A Provider may, for example, airdrop tokens to users who meet certain criteria, ### Benefit: improved economic sustainability A staking reward system can improve /onboard/uptake/usage/... +### Risk: staking system incentivizes gaming +If the staking system is too complicated, it can breed exploits and encourage gaming the systme. +If the staking system does not make it worthwhile to stake for rewards, the goal of decentralization is not achieved, and/or it can encourage gaming the system + +# Risk: staking system penalizes whale Providers +If the system is unreliable, unstable or not economical enough for large Providers -- _particularly_ compared to alternatives -- the goal of decentralization may be achieved in some sense, but at the expense of widespread adoption. + ### Risk: Faulty reward calculations: * Maximized Stake for capacity is not cheaper per txn than pay-as-you-go with token * Maximized Stake for capacity pays better than staking to be a collator From 5ef621685842eb3b36f62b9520ae0f105941f43e Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Wed, 19 Apr 2023 17:45:30 -0700 Subject: [PATCH 12/25] Corrected eqns --- designdocs/capacity_staking_rewards.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 65e4d82d55..c67c905195 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -42,6 +42,7 @@ We imagine that FRQCY could be airdropped by various entities to encourage onboa * Is Reward Pool token total itself fixed (with input values determined by governance), or is it the Reward _rate_ that is fixed? * What are the inputs to the economic model(s) for Capacity generation and Rewards? * How does the capacity generated by Maximized Capacity Staking differ from that generated by Rewards Capacity Staking? Maximized is more than Rewards, but by how much? +* Are rewards compounded? ## Economic Model By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. @@ -63,23 +64,22 @@ Example 2: Capacity is consistently under-utilized: We could decrease the cost Example 3: The median is significantly higher than the mean, which means a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. ### Example possible calculations for rewards: -There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_: +There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). -| Description| Governance constants | Equation| -|------------|----------------------|---------| -| Like simple interest, _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | +For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_, total Capacity generated by Maximized staking cm, total Capacity generated by Rewards staking cr + +| Description| Governance constants | Example Equation| +|------------|----------------------|-----------------| +| _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | | _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | -| Reward pool is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | -| Reward pool is a simple ratio | D, rm, rc | $P = D{1 - r_{c} \over m_{c}}$ | -* : - 1. Governance sets the Maximized Capacity Staking price (currently 50:1 FRQC:Capacity). - 2. Governance sets the Rewards Capacity Staking price -- the Capacity portion - 3. Governance may further choose a distribution period constant, D. +| _RP_ is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | +| _R_ is a simple ratio | D, cm, cr | $R = D(1 - {c_{r} \over c_{m}})$ | +| _RP_ is a simple ratio | D, cm, cr | $RP = D(1 - {c_{r} \over c_{m}})$ | + +In the last two examples, the constant D would be < 1, so that difference is split over some number of Eras to encourage longer term staking. For instance D could be 1/30 and Eras = 1 Epoch (a day), so with all other things being equal, it would take 30 days to get rewarded the FRQCY equivalent of your "share" of Capacity. This formula could be applied to either individual stakers or to the entire pool, in which case stakers affect each others' rewards, so more maximized staking would mean less reward for reward stakers. If applied to individual rewards, then only the Capacity generated by that token would be considered. -where rc = Rewards Capacity generated, and mc = how much Capacity would have been generated if it were all Maximized Staking. -The constant C would be <1 so that difference is split over some number of Eras to encourage longer term staking. For instance C could be 1/30 and Eras = 1 Epoch (a day), so it takes 30 days to get rewarded the FRQCY equivalent of your "share" of Capacity. +Lastly, Rewards/Capacity could be based on a more complex equation, perhaps which depends on the size of the targeted Provider. -* Rewards/Capacity are based on a more complex equation, which depends on the size of the targeted Provider. We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It would need to be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. From f5ec192ba5168745431f35b51b3338ae68382422 Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Wed, 19 Apr 2023 22:56:15 -0700 Subject: [PATCH 13/25] Update capacity_staking_rewards.md --- designdocs/capacity_staking_rewards.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index c67c905195..18742d5777 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -61,7 +61,7 @@ Example 1: We want a specific percentage of token accounts to stake in order to Example 2: Capacity is consistently under-utilized: We could decrease the cost of Capacity without changing the reward rate to encourage all Providers to post more often. We could also decrease the reward rate, which would cause some unstaking and reduce the available Capacity in the network. -Example 3: The median is significantly higher than the mean, which means a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. +Example 3: The median number of MSAs per provider is significantly lower than the mean, which could indicate a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. ### Example possible calculations for rewards: There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). From 66dbd5f9a2b3fdb62a12a67ad2c137445f812a62 Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Thu, 20 Apr 2023 13:51:57 -0700 Subject: [PATCH 14/25] Update capacity_staking_rewards.md simple ratio just don't work --- designdocs/capacity_staking_rewards.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md index 18742d5777..ac127e9236 100644 --- a/designdocs/capacity_staking_rewards.md +++ b/designdocs/capacity_staking_rewards.md @@ -73,10 +73,6 @@ For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number | _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | | _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | | _RP_ is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | -| _R_ is a simple ratio | D, cm, cr | $R = D(1 - {c_{r} \over c_{m}})$ | -| _RP_ is a simple ratio | D, cm, cr | $RP = D(1 - {c_{r} \over c_{m}})$ | - -In the last two examples, the constant D would be < 1, so that difference is split over some number of Eras to encourage longer term staking. For instance D could be 1/30 and Eras = 1 Epoch (a day), so with all other things being equal, it would take 30 days to get rewarded the FRQCY equivalent of your "share" of Capacity. This formula could be applied to either individual stakers or to the entire pool, in which case stakers affect each others' rewards, so more maximized staking would mean less reward for reward stakers. If applied to individual rewards, then only the Capacity generated by that token would be considered. Lastly, Rewards/Capacity could be based on a more complex equation, perhaps which depends on the size of the targeted Provider. From 3ec3939546dc8aaf737348942abd4cb0fad08442 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Mon, 8 May 2023 14:09:59 -0700 Subject: [PATCH 15/25] WIP --- designdocs/capacity_staking_rewards.md | 266 ------------------ ...capacity_staking_rewards_economic_model.md | 110 ++++++++ 2 files changed, 110 insertions(+), 266 deletions(-) delete mode 100644 designdocs/capacity_staking_rewards.md create mode 100644 designdocs/capacity_staking_rewards_economic_model.md diff --git a/designdocs/capacity_staking_rewards.md b/designdocs/capacity_staking_rewards.md deleted file mode 100644 index ac127e9236..0000000000 --- a/designdocs/capacity_staking_rewards.md +++ /dev/null @@ -1,266 +0,0 @@ -# Capacity Staking Rewards - -## Context and Scope: -The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with Capacity must: -1. Have an [MSA](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/accounts.md) -2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md)) -3. Stake a minimum amount of FRQCY token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). - -There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - known as _staking_ - while also targeting a Provider to receive some Capacity. - -The proposed feature is a design for staking FRQCY token in exchange for Capacity and/or FRQCY. -It is specific to the Frequency Substrate parachain. -It consists of enhancements to the capacity pallet, needed traits and their implementations, and needed runtime configuration. - -## Glossary -1. **FRQCY**: the native token of the Frequency blockchain -1. **Capacity**: the non-transferrable utility token which can be used only to pay for certain Frequency transactions. -1. **Account**: a Frequency System Account controlled by a private key and addressed by a public key, having at least a minimum balance (currently 0.01 FRQCY). -1. **Stake** (verb): to lock some amount of a token against transfer for a period of time in exchange for some reward. -1. **Era**: the time period (TBD in blocks or Capacity Epochs) that Staking Rewards are based upon. -1. **Staking Reward**: a per-Era share of a staking reward pool of FRQCY tokens for a given staking account. -1. **Reward Pool**: a fixed amount of FRQCY that can be minted for rewards each Era and distributed to stakers. - -[//]: # (A short description of the landscape in which the new system is being built, what is actually being built.) -[//]: # (It may also say what is not being built, and any assumptions.) -[//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) - -## Problem Statement: -A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. -To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. - -How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users stake, then they lose capacity if those end users unstake. If a Provider's Capacity from Reward staking is significant, this gives Reward Stakers some power over Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should be if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. - -We imagine that FRQCY could be airdropped by various entities to encourage onboarding, including Providers themselves. Providers may offer airdrops in exchange for such things as bringing in new users, or sharing links on other platforms, then encourage their users to stake their FRQCY for rewards. Rewards could be exchanged for in-dApp benefits such as premium features, special emoji, avatar customization, and the like. Rewards Staking could also unlock features. - -## Assumptions -* The exact formula for calculating rewards is determined in advance and used in the implementation of this design. -* Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. -* Like other blockchains, we round away "dust", values that are _10-tbd_ FRQCY or less. - -## To be decided: -* Is Reward Pool token total itself fixed (with input values determined by governance), or is it the Reward _rate_ that is fixed? -* What are the inputs to the economic model(s) for Capacity generation and Rewards? -* How does the capacity generated by Maximized Capacity Staking differ from that generated by Rewards Capacity Staking? Maximized is more than Rewards, but by how much? -* Are rewards compounded? - -## Economic Model -By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. - -Inputs in the economic model to consider could include: -* Proportion of accounts are staking to total accounts -* Mean number MSAs per Provider, or the mean compared to median. -* Proportion of token staked to free balance held by non-Treasury accounts -* The Capacity-per-Epoch use rate, perhaps averaged over N epochs -* The length of an Epoch in blocks -* The length of an Era n blocks - -These could be used to adjust the cost of capacity and the reward return percentage. - -Example 1: We want a specific percentage of token accounts to stake in order to meet a certain decentralization goal, and we are below that amount. We increase the reward rate to encourage token holders to stake, without adjusting the cost of capacity. - -Example 2: Capacity is consistently under-utilized: We could decrease the cost of Capacity without changing the reward rate to encourage all Providers to post more often. We could also decrease the reward rate, which would cause some unstaking and reduce the available Capacity in the network. - -Example 3: The median number of MSAs per provider is significantly lower than the mean, which could indicate a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. - -### Example possible calculations for rewards: -There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). - -For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_, total Capacity generated by Maximized staking cm, total Capacity generated by Rewards staking cr - -| Description| Governance constants | Example Equation| -|------------|----------------------|-----------------| -| _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | -| _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | -| _RP_ is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | - -Lastly, Rewards/Capacity could be based on a more complex equation, perhaps which depends on the size of the targeted Provider. - -We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. - -Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It would need to be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. - -Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. - -### One way to set the difference between Maximized and Reward Staking - -## Goals -* Outline the architecture for the implementation of staking rewards for Capacity. -* Allow staking rewards parameters to be adjusted without a chain upgrade. -* Prevent rewards storage operations and calculations from excessively weighing down blocks. -* Disallow receiving staking rewards for token that is not staked for a full Era. -* Prevent staking and unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. -* Create a living design document that changes as compelling new findings and needs arise - -## Non-goals -* Do not finalize names, functions, storage types and shape of storage and structs -* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking -* Do not account for other economic incentives on the Frequency network, such as collator rewards. -* Cannot account for token price in any other currency. -* Do not change how paying for transactions with Capacity works - ---- -## Proposal: -Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. -On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. -There are two types of staking, **Maximized Capacity Staking** and **Rewards Capacity Staking**. -In both types, the staker designates a target Provider who receives capacity upon staking. -The difference is: - -* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Rewards Capacity Staking. - The staker does not receive any token rewards. -* With **Rewards Capacity Staking**, the target Provider shares rewards with the staker. - The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. - - -Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. Rewards may also be claimed directly for a specific AccountId by calling an extrinsic. In either case, `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. - - -Whenever a Rewards Pool calculation is changed, it goes into effect at the start of the next Era. The new Rewards parameters are pushed to storage, and, assuming the history queue is full, the oldest one is removed. - -A special condition of this is a blend of the above: some staking accounts could be large enough that if their staking balance changes significantly, it also affects the Reward Pool significantly for all staking accounts. Such accounts are called "whales" in blockchain jargon. We deem "significant" change as greater than or equal to one hundredth of a percent (0.01%), rounded. If so, a new set of Rewards parameters is pushed. We _may_ need to extend the thaw period for a staking account when their unstaking will cause a RewardsPool history push, in order to strongly reduce incentives for staking/unstaking spam. - -## Staking Token Rewards - -### StakingAccountDetails updates -We add a new field, `last_rewarded_at`, to keep track of the last time rewards were claimed for this Staking Account. -```rust -pub struct StakingAccountDetails { - pub active: BalanceOf, - pub total: BalanceOf, - pub unlocking: BoundedVec, T::EpochNumber>, T::MaxUnlockingChunks>, - /// The number of the last StakingEra that this account's rewards were claimed. - pub last_rewarded_at: T::StakingEra, // NEW -} -``` - -**Unstaking thaw period** (Maybe) -We change the thaw period to begin at the first block of next Epoch instead of immediately. - -### New storage items and related types - -#### RewardsPoolHistory and RewardsPoolParameters -We store changes to the Rewards Pool calculations when any change occurs that affects the Rewards Pool greater than or equal to a hundredth of a percent (0.01%), rounded, or when Rewards Pool Parameters are changed. - -**Toy Example using a very simple rewards equation:** -Let's assume a simple reward pool calculation relates to total token staked and the number of stakers, multiplied by some constant: - -$$ P = { t + Cs \over 100,000 } $$$ - -Where P is the Reward Pool Total, t is total staked token and s is the number of stakers as before. - -Say total staked token is 100k FRQCY, there are 25 stakers, and Moby staker has staked 20k FRQCY. The reward pool starts at 125k/100k = 1.25 FRQCY to spread among 25 stakers based on their stake. - -Moby account unstakes 10k FRQCY, which drops staked token by 10%. The new reward pool is (90,000 + 25,000) / 100,000 = 1.15 FRQCY to spread among the stakers. This causes the Reward Pool to go down by 12%, i.e. >0.01%, so a new entry is pushed into the RewardPool history. - -```rust -/// A queue of the last `RewardsPoolHistoryMaxDepth` RewardsPoolParameters. -type RewardsPoolHistory: BoundedVec, T::RewardsPoolHistoryMaxDepth>; -``` - -```rust -/// The parameters for a rewards pool that applied from `applied_at` StakingEra to the next time -/// the parameters changed. -pub struct RewardsPoolParameters { - /// the total of all FRQCY staked when these parameters were applied - pub staking_total: BalanceOf, - /// the size of the rewards pool when these parameters were applied - pub rewards_pool_total: BalanceOf - /// the first era these parameters were applied - pub applied_at: T::StakingEra, - /// the number of providers - pub providers: uint32, - /// the number of stakers - pub stakers: uint32, -} -``` - -### Properties and Pallet Storage (DRAFT! some of these are just a guess!) -* `staking_type` (Maximized or Rewards): An enum. A property on `StakingAccountDetails` -* `pub type RewardRate: StorageValue<_, uint16, ValueQuery>`: Stores the reward rate as hundredths of a percent; a reward rate of 1.25% would be stored as `125`. -* `pub type RewardFrequency StorageValue<_, , ValueQuery>`: Stores Reward frequency in number of epochs or blocks, **TBD** -* `pub type CapacityPriceMaximized StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Maximized Staking. -* `pub type CapacityPriceRewards StorageValue<_, BalanceOf, ValueQuery>`: Stores the price of 1 capacity in FRQCY, in the case of Rewards Staking. - -### Capacity Pallet extrinsics -* `change_reward_rate(origin, rate)`: governance-only -* `change _reward_frequency(origin, period)`: governance-only -* `change_staking_type(origin, target, new_type)` -* `change_target(origin, old_target, new_target)` -* `claim_staking_reward(origin)` - -### Capacity Pallet helper functions -* `participation_rate`: function, calculates participation using some combination of Total amount staked, reward Pool Token Size, the number of providers, the provider capacity amount (total?), individual amount staked (for individual reward amount only) -* `current_staking_reward(account_id, target)`: function, calculates the current rewards that would be paid out if the StakingAccount holder unstaked at the current block. -* `pay_reward`: function, - -### RPC -* `unclaimed_staking_reward(account_id: AccountId) -> BalanceOf`: caller can query the unclaimed staking reward for a given AccountId. - -### Other functions -* `change_staking_type`: a function on StakingAccountDetails (? maybe you have to unstake and restake to do this) - -[//]: # (A high level overview, followed by a detailed description.) -[//]: # (This is where specific technology, such as language, frameworks, encryption algorithms, type of authentication, and APIs can be described.) -[//]: # (It can include diagrams such as a system context diagram, or a sequence diagram.) - ---- -## Benefits and Risks: -### Benefit: stabler message costs -Staking locks up token. Locked token may not be immediately withdrawn; this dampens some level of speculation-driven volatility as well as that driven by opportunistic Capacity purchases. - -### Benefit: improved engagement and expanded user base -A Provider may, for example, airdrop tokens to users who meet certain criteria, such as referrals or sharing links on other platforms. Users with token may choose Reward staking to generate Capacity for their Provider and also get token rewards. - -### Benefit: improved economic sustainability -A staking reward system can improve /onboard/uptake/usage/... - -### Risk: staking system incentivizes gaming -If the staking system is too complicated, it can breed exploits and encourage gaming the systme. -If the staking system does not make it worthwhile to stake for rewards, the goal of decentralization is not achieved, and/or it can encourage gaming the system - -# Risk: staking system penalizes whale Providers -If the system is unreliable, unstable or not economical enough for large Providers -- _particularly_ compared to alternatives -- the goal of decentralization may be achieved in some sense, but at the expense of widespread adoption. - -### Risk: Faulty reward calculations: -* Maximized Stake for capacity is not cheaper per txn than pay-as-you-go with token -* Maximized Stake for capacity pays better than staking to be a collator - -### Arguments in favor of storage values for reward rate and capacity price -* transparency: it's more transparent than a Config, which could be changed only by an upgrade. This is because changes to Config values can be easily overlooked if they are buried in a large upgrade. Making them be subject to governance approval puts the change on chain, making it more subject to review. -* stabler: reward rates and capacity prices would have an automatic upper limit to how frequently they could change. - -### Arguments against -* risk to network sustainability: it's possible that proposed changes which would actually be necessary to Frequency's economic stability and sustainability may be rejected by token voters. This is mitigated particularly at the start of Frequency's operation given the token distribution, and also with the voting power and permissions of Frequency and Technical Councils. - -#### Mitigation: -Adjust reward amounts. This is why the reward amounts need to be adjustable. - -[//]: # (the reasons why this solution was chosen, and the risks this solution poses.) -[//]: # (For example, the solution may be very simple, but there could performance bottlenecks above a certain threshold.) -[//]: # (Another: the solution is well known and widely used, but it's not a perfect fit and requires complicated changes in one area.) - -## Alternatives and Rationale: - -### 1. Rewards are accounted for periodically all together, at once. -this puts an extreme burden on one or more blocks due to storage updates. -### 2. At least some portion of rewards are accounted for every block; all rewards are updated for all stakers within the Era. -This effectively creates a constant overhead, but this approach causes much heavier blocks than the chosen solution. -### 3. Stakers for a given Provider could be "lazily" rewarded at the same time a Provider posts a new message at the beginning of an Epoch. -This presents a problem if a Provider does not post every Epoch, especially if the Rewards Era is less than or equal to an Epoch. This will also put a lot of extra weight on blocks at the beginning of every Epoch. -### 4. Pay rewards out every time there is a change for a given token staking account, or a change in Rewards parameters. -Since the only thing that changes staking rewards is the `StakingAccountDetails.total`, unless the Rewards calculation changes, we don't need to do a sweep unless the staker changes their total, either through staking more or unstaking. This minimizes the average block burden significantly, however, occasionally, when the Rewards calculation changes, block time will be slower for the next Era due to rewards payouts. - -### Why can't Frequency use Substrate `staking` pallet? -The staking pallet is for rewarding node validators, and rewards must be claimed within `HISTORY_DEPTH` blocks before the record of them is purged. Reward payouts for a given validator can be called by any account and the rewards go o the validator and are shared with its nominators. The staking pallet keeps track of what rewards have been claimed within that `HISTORY_DEPTH` number of blocks. - -Since Capacity Rewards staking is for FRQCY token account holders, we should not require those holders to have to call an extrinsic regularly to receive rewards. - -Secondly, we must plan for the number of Providers to dwarf the number of validators on the Polkadot Relay chain. The Polkadot relay chain currently has validators in the hundreds. Calculating the payouts for hundreds of items in RocksDB storage is a very different prospect than calculating rewards for thousands of Providers and potentially tens of millions (or more) of Rewards stakers. It may be that this type of optimization is deferred, however, this design must not make it difficult to optimize. - -[//]: # (discuss alternatives that were considered, and why they were rejected.) -[//]: # (Note when there are absolute requirements that the solution does not and can't meet. One example might be, it's a proprietary solution but we need something open source.) - -## Sources: - -[//]: # (sources of information that led to this design.) diff --git a/designdocs/capacity_staking_rewards_economic_model.md b/designdocs/capacity_staking_rewards_economic_model.md new file mode 100644 index 0000000000..da4c3b2e03 --- /dev/null +++ b/designdocs/capacity_staking_rewards_economic_model.md @@ -0,0 +1,110 @@ +# Capacity Staking Rewards Economic Model + + +## Context and Scope: +The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with Capacity must: +1. Have an [MSA](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/accounts.md) +2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md)) +3. Stake a minimum amount of FRQCY token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). + +There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - known as _staking_ - while also targeting a Provider to receive some Capacity. + +[//]: # (A short description of the landscape in which the new system is being built, what is actually being built.) +[//]: # (It may also say what is not being built, and any assumptions.) +[//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) + +## Problem Statement: +A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. +To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. + +How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users stake, then they lose capacity if those end users unstake. If a Provider's Capacity from Reward staking is significant, this gives Reward Stakers some power over Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should be if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. + +We imagine that FRQCY could be airdropped by various entities to encourage onboarding, including Providers themselves. Providers may offer airdrops in exchange for such things as bringing in new users, or sharing links on other platforms, then encourage their users to stake their FRQCY for rewards. Rewards could be exchanged for in-dApp benefits such as premium features, special emoji, avatar customization, and the like. Rewards Staking could also unlock features. + +## Assumptions +* The exact formula for calculating rewards is determined in advance and used in the implementation of this design. +* Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. +* Like other blockchains, we round away "dust", values that are _10-tbd_ FRQCY or less. + +## To be decided: +* Is Reward Pool token total itself fixed (with input values determined by governance), or is it the Reward _rate_ that is fixed? +* What are the inputs to the economic model(s) for Capacity generation and Rewards? +* How does the capacity generated by Maximized Capacity Staking differ from that generated by Rewards Capacity Staking? Maximized is more than Rewards, but by how much? +* Are rewards compounded? + +## Economic Model +By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. + +Inputs in the economic model to consider could include: +* Proportion of accounts are staking to total accounts +* Mean number MSAs per Provider, or the mean compared to median. +* Proportion of token staked to free balance held by non-Treasury accounts +* The Capacity-per-Epoch use rate, perhaps averaged over N epochs +* The length of an Epoch in blocks +* The length of an Era n blocks + +These could be used to adjust the cost of capacity and the reward return percentage. + +Example 1: We want a specific percentage of token accounts to stake in order to meet a certain decentralization goal, and we are below that amount. We increase the reward rate to encourage token holders to stake, without adjusting the cost of capacity. + +Example 2: Capacity is consistently under-utilized: We could decrease the cost of Capacity without changing the reward rate to encourage all Providers to post more often. We could also decrease the reward rate, which would cause some unstaking and reduce the available Capacity in the network. + +Example 3: The median number of MSAs per provider is significantly lower than the mean, which could indicate a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. + +### Example possible calculations for rewards: +There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). + +For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_, total Capacity generated by Maximized staking cm, total Capacity generated by Rewards staking cr + +| Description| Governance constants | Example Equation| +|------------|----------------------|-----------------| +| _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | +| _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | +| _RP_ is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | + +Lastly, Rewards/Capacity could be based on a more complex equation, perhaps which depends on the size of the targeted Provider. + +We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. + +Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It would need to be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. + +Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. + +### One way to set the difference between Maximized and Reward Staking + +## Goals +* Outline the architecture for the implementation of staking rewards for Capacity. +* Allow staking rewards parameters to be adjusted without a chain upgrade. +* Prevent rewards storage operations and calculations from excessively weighing down blocks. +* Disallow receiving staking rewards for token that is not staked for a full Era. +* Prevent staking and unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. +* Create a living design document that changes as compelling new findings and needs arise + +## Non-goals +* Do not finalize names, functions, storage types and shape of storage and structs +* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking +* Do not account for other economic incentives on the Frequency network, such as collator rewards. +* Cannot account for token price in any other currency. +* Do not change how paying for transactions with Capacity works + +--- +## Proposal: +Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. +On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. +There are two types of staking, **Maximized Capacity Staking** and **Rewards Capacity Staking**. +In both types, the staker designates a target Provider who receives capacity upon staking. +The difference is: + +* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Rewards Capacity Staking. + The staker does not receive any token rewards. +* With **Rewards Capacity Staking**, the target Provider shares rewards with the staker. + The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. + + +Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. Rewards may also be claimed directly for a specific AccountId by calling an extrinsic. In either case, `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. + + +Whenever a Rewards Pool calculation is changed, it goes into effect at the start of the next Era. The new Rewards parameters are pushed to storage, and, assuming the history queue is full, the oldest one is removed. + +A special condition of this is a blend of the above: some staking accounts could be large enough that if their staking balance changes significantly, it also affects the Reward Pool significantly for all staking accounts. Such accounts are called "whales" in blockchain jargon. We deem "significant" change as greater than or equal to one hundredth of a percent (0.01%), rounded. If so, a new set of Rewards parameters is pushed. We _may_ need to extend the thaw period for a staking account when their unstaking will cause a RewardsPool history push, in order to strongly reduce incentives for staking/unstaking spam. + From e768cd494d09922d77c34e514d88b146fdb1bca6 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 23 May 2023 16:27:28 -0700 Subject: [PATCH 16/25] updates to design docs to use a capacity rewards interface --- ...capacity_staking_rewards_economic_model.md | 50 ++++--------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/designdocs/capacity_staking_rewards_economic_model.md b/designdocs/capacity_staking_rewards_economic_model.md index da4c3b2e03..ddceed30a3 100644 --- a/designdocs/capacity_staking_rewards_economic_model.md +++ b/designdocs/capacity_staking_rewards_economic_model.md @@ -1,5 +1,11 @@ # Capacity Staking Rewards Economic Model +This document outlines the economic model to be used for: +1. determining the token value of the Reward Pool for a given Era +2. how to calculate rewards for an individual staker +3. when rewards are calculated +4. when rewards are paid out +5. where these calculations are performed ## Context and Scope: The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with Capacity must: @@ -9,9 +15,6 @@ The Frequency Transaction Payment system uses Capacity to pay for certain transa There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - known as _staking_ - while also targeting a Provider to receive some Capacity. -[//]: # (A short description of the landscape in which the new system is being built, what is actually being built.) -[//]: # (It may also say what is not being built, and any assumptions.) -[//]: # (Example: The proposed feature is a testing library. The context is: the library is for our chosen blockchain. The scope is: this is for a specific repository, so it's not meant to be reused. That means it won't be a separate package, and the code will be tailored for this repo. One might also say that the scope is also limited to developer testing, so it's not meant to be used in CI or a test environment such as a test blockchain network.) ## Problem Statement: A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. @@ -70,41 +73,10 @@ Such a system could diminish the "nothing succeeds like success" effect, however Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. -### One way to set the difference between Maximized and Reward Staking - ## Goals -* Outline the architecture for the implementation of staking rewards for Capacity. -* Allow staking rewards parameters to be adjusted without a chain upgrade. -* Prevent rewards storage operations and calculations from excessively weighing down blocks. -* Disallow receiving staking rewards for token that is not staked for a full Era. -* Prevent staking and unstaking "spam" which would destabilize the chain token economy and slow down block formation due to excessive database read/writes. -* Create a living design document that changes as compelling new findings and needs arise - -## Non-goals -* Do not finalize names, functions, storage types and shape of storage and structs -* Do not determine the actual amount of rewards - either in Capacity or FRQCY - for staking -* Do not account for other economic incentives on the Frequency network, such as collator rewards. -* Cannot account for token price in any other currency. -* Do not change how paying for transactions with Capacity works - ---- -## Proposal: -Any Frequency account with a set minimum amount of FRQCY to may stake token to the network. -On staking, the staker designates a type of staking, plus a target Provider to receive Capacity. -There are two types of staking, **Maximized Capacity Staking** and **Rewards Capacity Staking**. -In both types, the staker designates a target Provider who receives capacity upon staking. -The difference is: - -* With **Maximized Capacity Staking**, the target Provider receives more Capacity than it would with Rewards Capacity Staking. - The staker does not receive any token rewards. -* With **Rewards Capacity Staking**, the target Provider shares rewards with the staker. - The target Provider receives some Capacity, and the staker receives periodic rewards in FRQCY. - - -Whenever `StakingAccountDetails.total` changes, either by staking more or unstaking, rewards are calculated, minted and transferred immediately. Rewards may also be claimed directly for a specific AccountId by calling an extrinsic. In either case, `StakingAccountDetails.total` is updated to be the current era. Rewards are paid out from `last_rewarded_at` to `current_era() - 1` by applying the RewardsPoolParameters to each Era. - - -Whenever a Rewards Pool calculation is changed, it goes into effect at the start of the next Era. The new Rewards parameters are pushed to storage, and, assuming the history queue is full, the oldest one is removed. - -A special condition of this is a blend of the above: some staking accounts could be large enough that if their staking balance changes significantly, it also affects the Reward Pool significantly for all staking accounts. Such accounts are called "whales" in blockchain jargon. We deem "significant" change as greater than or equal to one hundredth of a percent (0.01%), rounded. If so, a new set of Rewards parameters is pushed. We _may_ need to extend the thaw period for a staking account when their unstaking will cause a RewardsPool history push, in order to strongly reduce incentives for staking/unstaking spam. +1. Specify verbally or in pseudo-code how to do the 5 things listed at the top of this document +## Non-Goals +1. Do not specify implementation details +2. Do not specify final naming +## Proposal: From 0e88e75bf9a47ef70046f9a70b97d7a81e388579 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 16 Apr 2024 15:03:19 -0700 Subject: [PATCH 17/25] updates reflecting economic model (WIP) --- ...capacity_staking_rewards_economic_model.md | 76 ++++++------------- 1 file changed, 23 insertions(+), 53 deletions(-) diff --git a/designdocs/capacity_staking_rewards_economic_model.md b/designdocs/capacity_staking_rewards_economic_model.md index ddceed30a3..a2516379ea 100644 --- a/designdocs/capacity_staking_rewards_economic_model.md +++ b/designdocs/capacity_staking_rewards_economic_model.md @@ -1,82 +1,52 @@ -# Capacity Staking Rewards Economic Model +# Provider Boosting Economic Model This document outlines the economic model to be used for: 1. determining the token value of the Reward Pool for a given Era -2. how to calculate rewards for an individual staker +2. how to calculate rewards for an individual participant in the Provider Boost program 3. when rewards are calculated 4. when rewards are paid out 5. where these calculations are performed ## Context and Scope: -The Frequency Transaction Payment system uses Capacity to pay for certain transactions on chain. Accounts that wish to pay with Capacity must: +The Frequency Transaction Payment system uses Capacity to pay for a limited number of specific transactions on chain. Accounts that wish to pay for transactions with Capacity must: 1. Have an [MSA](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/accounts.md) 2. Be a [Provider](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_registration.md) (see also [Provider Permissions and Grants](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/provider_permissions.md)) -3. Stake a minimum amount of FRQCY token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). +3. Lock up a minimum amount of FRQCY token to receive [Capacity](https://github.com/LibertyDSNP/frequency/blob/main/designdocs/capacity.md). -There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - known as _staking_ - while also targeting a Provider to receive some Capacity. +There is also a business case for allowing any token holder to lock up its tokens in exchange for a reward - while also targeting a Provider to receive some Capacity. ## Problem Statement: A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. -To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to stake FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. +To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to lock up FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. -How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users stake, then they lose capacity if those end users unstake. If a Provider's Capacity from Reward staking is significant, this gives Reward Stakers some power over Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should be if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. +How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users lock up some token, then they lose Capacity if those end users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. -We imagine that FRQCY could be airdropped by various entities to encourage onboarding, including Providers themselves. Providers may offer airdrops in exchange for such things as bringing in new users, or sharing links on other platforms, then encourage their users to stake their FRQCY for rewards. Rewards could be exchanged for in-dApp benefits such as premium features, special emoji, avatar customization, and the like. Rewards Staking could also unlock features. +FRQCY could potentially be airdropped by various entities to encourage onboarding. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. -* Rewards are not prorated; they are calculated based on the staking account balance at the start of an Era. -* Like other blockchains, we round away "dust", values that are _10-tbd_ FRQCY or less. - -## To be decided: -* Is Reward Pool token total itself fixed (with input values determined by governance), or is it the Reward _rate_ that is fixed? -* What are the inputs to the economic model(s) for Capacity generation and Rewards? -* How does the capacity generated by Maximized Capacity Staking differ from that generated by Rewards Capacity Staking? Maximized is more than Rewards, but by how much? -* Are rewards compounded? +* Rewards are not prorated; they are calculated based on the Provider Boosted account balance at the start of each Era. ## Economic Model -By "economic model" we mean the formulae used to manage staking rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. - -Inputs in the economic model to consider could include: -* Proportion of accounts are staking to total accounts -* Mean number MSAs per Provider, or the mean compared to median. -* Proportion of token staked to free balance held by non-Treasury accounts -* The Capacity-per-Epoch use rate, perhaps averaged over N epochs -* The length of an Epoch in blocks -* The length of an Era n blocks - -These could be used to adjust the cost of capacity and the reward return percentage. - -Example 1: We want a specific percentage of token accounts to stake in order to meet a certain decentralization goal, and we are below that amount. We increase the reward rate to encourage token holders to stake, without adjusting the cost of capacity. - -Example 2: Capacity is consistently under-utilized: We could decrease the cost of Capacity without changing the reward rate to encourage all Providers to post more often. We could also decrease the reward rate, which would cause some unstaking and reduce the available Capacity in the network. - -Example 3: The median number of MSAs per provider is significantly lower than the mean, which could indicate a handful of Providers (or just one) are dominating Capacity use, which could mean a trend toward centralization. We could decrease the cost of Capacity to encourage all Providers to post more often, and to encourage more new Providers. We could also increase the reward rate to encourage more staking, which could also provide capacity to new Providers. - -### Example possible calculations for rewards: -There are many possible calculations but here are some ideas about what factors could influence the rewards and how they could be incorporated, starting with very simple (and also very unlikely) to complicated (probably also not likely). - -For a reward pool _RP_ or individual rewards _R_, Total Staked Token _t_, number of Stakers _s_, number of Providers _p_, total Capacity generated by Maximized staking cm, total Capacity generated by Rewards staking cr - -| Description| Governance constants | Example Equation| -|------------|----------------------|-----------------| -| _R_ is fixed at some percent _M_ of _t_| M | $R = {Mt}$ | -| _RP_ is linear and rewards decentralization of Stakers and Providers | N,M,P | $RP = {Nt + Ms + Pp \over 100}$ | -| _RP_ is some polynomial of order _i,j_ | N,M,P | $RP = { Nt + Ms^i + Pp^j }$ | - -Lastly, Rewards/Capacity could be based on a more complex equation, perhaps which depends on the size of the targeted Provider. - -We could implement diminishing returns on rewards and/or capacity. This would reward smaller Providers and stakers who target them much more than "whales". The coefficient could be adjusted based on total number of accounts, number of Providers, total token staked, etc, depending on where we want the "hump" to be for most Providers and stakers; we would probably want it significantly above their average Capacity level so that purchasing more Capacity is still approximately a linear return, whereas much larger participants ("whales") would have to spend more money to get the same increase in Capacity. - -Such a system could diminish the "nothing succeeds like success" effect, however, if the effect is too strong, whales could be driven off the platform since growth is too expensive. It would need to be carefully tailored so new Providers could grow their presence relatively easily. This is much different from the norm of resource acquisition, where "bulk discounts" dominate. - -Since there is no difference to the chain for what Provider is posting what message, a "bulk discount" for posting Capacity messages doesn't apply. +By "economic model" we mean the formulas used to manage Provider Boost rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. ## Goals -1. Specify verbally or in pseudo-code how to do the 5 things listed at the top of this document +To specify the following: +1. In words or pseudo-code how the reward pool and individual rewards are calculated +2. When reward amounts are minted +3. How much Capacity is generated for the targeted Provider for a Provider Boost. +4. What to do with any left over funds set aside for Provider Boost Rewards. ## Non-Goals 1. Do not specify implementation details 2. Do not specify final naming + ## Proposal: +### Inputs to Provider Boost Reward Calculation +- Number of complete Eras of Provider Boosting +- System-wide Totals Provider-Boosted each era +- Individual totals Provider-Boosted each era +- Rewards Cap amount +- Era reward percentage + From a1ef541cce745ed861bac1bad255a7e3e25e283d Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 16 Apr 2024 15:04:04 -0700 Subject: [PATCH 18/25] rename --- ...ards_economic_model.md => provider_boosting_economic_model.md} | 0 ...ards_implementation.md => provider_boosting_implementation.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename designdocs/{capacity_staking_rewards_economic_model.md => provider_boosting_economic_model.md} (100%) rename designdocs/{capacity_staking_rewards_implementation.md => provider_boosting_implementation.md} (100%) diff --git a/designdocs/capacity_staking_rewards_economic_model.md b/designdocs/provider_boosting_economic_model.md similarity index 100% rename from designdocs/capacity_staking_rewards_economic_model.md rename to designdocs/provider_boosting_economic_model.md diff --git a/designdocs/capacity_staking_rewards_implementation.md b/designdocs/provider_boosting_implementation.md similarity index 100% rename from designdocs/capacity_staking_rewards_implementation.md rename to designdocs/provider_boosting_implementation.md From e731a7c046d8774c534a4f2d1cd6f59d72b7f2ea Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 16 Apr 2024 17:29:16 -0700 Subject: [PATCH 19/25] econ model updates pt 2 --- .../provider_boosting_economic_model.md | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index a2516379ea..593e1c6281 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -18,35 +18,59 @@ There is also a business case for allowing any token holder to lock up its token ## Problem Statement: A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. -To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to lock up FRQCY token in return for something; this creates an incentive for participation and involvement with the chain fundamentals and governance. +To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to lock up FRQCY token in return for something; this creates an incentive for participation and involvement with the Frequency chain fundamentals and governance. -How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. If Providers receive some capacity when end users lock up some token, then they lose Capacity if those end users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. +How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. In the proposed system, when Providers receive Capacity when end users lock up some FRQCY, they would lose Capacity if those end users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. This gives those end-users relying upon - and Boosting - their Providers the ability to exercise direct market power they did not previously have. -FRQCY could potentially be airdropped by various entities to encourage onboarding. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). +End users with Message Source Accounts (MSAs) may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. -* Rewards are not prorated; they are calculated based on the Provider Boosted account balance at the start of each Era. ## Economic Model -By "economic model" we mean the formulas used to manage Provider Boost rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. +By "economic model" we mean the formulas and inputs used to manage Provider Boost rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. ## Goals To specify the following: -1. In words or pseudo-code how the reward pool and individual rewards are calculated -2. When reward amounts are minted -3. How much Capacity is generated for the targeted Provider for a Provider Boost. -4. What to do with any left over funds set aside for Provider Boost Rewards. +* In words or pseudo-code how the reward pool and individual rewards are calculated +* When reward amounts are minted +* How much Capacity is generated for the targeted Provider for a Provider Boost. +* What to do with any left over funds set aside for Provider Boost Rewards. ## Non-Goals -1. Do not specify implementation details -2. Do not specify final naming +This document does not: +* specify implementation details or naming in code. +* specify reward amounts for all time; values and methods used for calculating rewards should be expected to change to meet economic goals of the Frequency Blockchain and any legal requirements. ## Proposal: ### Inputs to Provider Boost Reward Calculation -- Number of complete Eras of Provider Boosting -- System-wide Totals Provider-Boosted each era -- Individual totals Provider-Boosted each era -- Rewards Cap amount -- Era reward percentage +* Rera is a predetermined number of tokens available each Boost Era for Rewards +* Su is the amount an MSA holder has locked for Provider Boost Era e +* ST is the total that all MSA holders have locked for Provider Boost Era e +* Rmax is the maximum percentage of a Provider-Boosted amount that can be paid out in Era e +### Formula +The Provider Boost reward in FRQCY tokens for a given Era e is + +R = min(Rera*Su/ST, Su*Rmax) + +Put into words, if the pool of Rewards per Era is Rera 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 Rmax times the amount locked, whichever is less. + +Put another way, there is a fixed number of tokens to be rewarded each Era, split up according to each Provider Boost account holder's percentage of the staked total. However, the reward percentage each Era for every individual account is capped at 10%. + +### Examples: +Given the following values: +* Rera = 2 Million FRQCY +* Rmax is 10% + +1. Ang has locked up 100 FRQCY for Provider Boosting. The total locked by everyone, ST for era e, is 10 Million FRQCY. The left side of the minimum is `2e6 * 100 / 10.0e6 = 100/5 = 20` (that is, 20% of what Ang has locked). The right side is `100 * 10% = 10`. Since 10 is less than 20, the reward amount is 10 FRQCY. +2. Bey has locked up 1000 FRQCY for Provider Boosting. The total locked by everyone, ST for era e, is 50 Million FRQCY. The left side of the minimum s `2e6 * 1000 / 50.0e6 = 1000/25 = 40` (that is, 4% of what Bey has locked). The right side is `1000 * 10% = 100`. Since 40 is less than 100, Bey's Provider Boost reward is 40 FRQCY. + +## Rewards are not issued for a partial Era +Rewards are not prorated; they are calculated only for balances held for an entire Era. For example, if an amount is staked at the end of Era 100, and unstaked in Era 101, _no_ Reward will be issued. If an amount is staked in Era 100, and unstaked in Era 102, a Provider Boost Reward is available _only_ for Era 101. + +## Claiming Rewards +* Provider Boost Rewards are not minted until they are explicitly claimed 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 MSA of the Provider Boost Account. +* **Is there a cap on how much can be claimed at once?** From 78b917ca2c714fe3dd3822d3936b1373b23ff73e Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Tue, 16 Apr 2024 17:39:07 -0700 Subject: [PATCH 20/25] Update provider_boosting_economic_model.md --- designdocs/provider_boosting_economic_model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index 593e1c6281..84bd5d0156 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -28,7 +28,7 @@ End users with Message Source Accounts (MSAs) may receive FRQCY from different s * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. ## Economic Model -By "economic model" we mean the formulas and inputs used to manage Provider Boost rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. +"Economic model" means the formulas and inputs used to manage Provider Boost rewards to achieve the goals of decentralization, economic stabiilty, and sustainability. ## Goals To specify the following: From f173d360b82d14543770ae50facf1377f3a303f6 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Tue, 16 Apr 2024 17:48:41 -0700 Subject: [PATCH 21/25] some clarifications in the equations --- .../provider_boosting_economic_model.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index 84bd5d0156..f9a68041e5 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -33,9 +33,9 @@ End users with Message Source Accounts (MSAs) may receive FRQCY from different s ## Goals To specify the following: * In words or pseudo-code how the reward pool and individual rewards are calculated -* When reward amounts are minted -* How much Capacity is generated for the targeted Provider for a Provider Boost. -* What to do with any left over funds set aside for Provider Boost Rewards. +* How and when rewards are minted and transferred +* What to do with leftover and/or unclaimed funds set aside for Provider Boost Rewards. +* Limitations on receiving rewards and reward amounts ## Non-Goals This document does not: @@ -44,30 +44,30 @@ This document does not: ## Proposal: ### Inputs to Provider Boost Reward Calculation -* Rera is a predetermined number of tokens available each Boost Era for Rewards -* Su is the amount an MSA holder has locked for Provider Boost Era e -* ST is the total that all MSA holders have locked for Provider Boost Era e -* Rmax is the maximum percentage of a Provider-Boosted amount that can be paid out in Era e +* Rera is a predetermined amount of FRQCY available each Boost Era for Rewards +* Lu is the amount an MSA holder has locked for Provider Boost Era e +* LT is the total that all MSA holders have locked for Provider Boost Era e +* Pmax is the maximum percentage of a Provider-Boosted amount that can be paid out in Era e ### Formula The Provider Boost reward in FRQCY tokens for a given Era e is -R = min(Rera*Su/ST, Su*Rmax) +R = min(Rera*Lu/LT, Lu*Pmax) -Put into words, if the pool of Rewards per Era is Rera 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 Rmax times the amount locked, whichever is less. +Put into words, if the pool of Rewards per Era is Rera 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 Pmax times the amount locked, whichever is less. -Put another way, there is a fixed number of tokens to be rewarded each Era, split up according to each Provider Boost account holder's percentage of the staked total. However, the reward percentage each Era for every individual account is capped at 10%. +Put another way, there is a fixed number of tokens to be rewarded each Era (Rera), 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 (Pmax) is capped at some rate, for example, 10%. ### Examples: Given the following values: * Rera = 2 Million FRQCY * Rmax is 10% -1. Ang has locked up 100 FRQCY for Provider Boosting. The total locked by everyone, ST for era e, is 10 Million FRQCY. The left side of the minimum is `2e6 * 100 / 10.0e6 = 100/5 = 20` (that is, 20% of what Ang has locked). The right side is `100 * 10% = 10`. Since 10 is less than 20, the reward amount is 10 FRQCY. -2. Bey has locked up 1000 FRQCY for Provider Boosting. The total locked by everyone, ST for era e, is 50 Million FRQCY. The left side of the minimum s `2e6 * 1000 / 50.0e6 = 1000/25 = 40` (that is, 4% of what Bey has locked). The right side is `1000 * 10% = 100`. Since 40 is less than 100, Bey's Provider Boost reward is 40 FRQCY. +1. Ang has locked 100 FRQCY (Lu) for Provider Boosting. The total locked by everyone, LT for era e, is 10 Million FRQCY. The left side of the minimum is `2e6 * 100 / 10.0e6 = 100/5 = 20` (that is, 20% of what Ang has locked). The right side is `100 * 10% = 10`. Since 10 is less than 20, the reward amount is 10 FRQCY. +2. Bey has locked 1000 FRQCY (Lu) for Provider Boosting. The total locked by everyone, LT for era e, is 50 Million FRQCY. The left side of the minimum s `2e6 * 1000 / 50.0e6 = 1000/25 = 40` (that is, 4% of what Bey has locked). The right side is `1000 * 10% = 100`. Since 40 is less than 100, Bey's Provider Boost reward is 40 FRQCY. ## Rewards are not issued for a partial Era -Rewards are not prorated; they are calculated only for balances held for an entire Era. For example, if an amount is staked at the end of Era 100, and unstaked in Era 101, _no_ Reward will be issued. If an amount is staked in Era 100, and unstaked in Era 102, a Provider Boost Reward is available _only_ for Era 101. +Rewards are not prorated; they are calculated only for balances held for an entire Era. For example, if an amount is locked at the end of Era 100, and unlocked in Era 101, _no_ Reward will be issued. If an amount is locked in Era 100, and unlocked in Era 102, a Provider Boost Reward is available _only_ for Era 101. ## Claiming Rewards * Provider Boost Rewards are not minted until they are explicitly claimed by the Provider Boost account holder, by calling a non-free extrinsic. From 73c4377bab97c7d1d500e6cd5cd6a1a38e5e2599 Mon Sep 17 00:00:00 2001 From: Shannon Wells Date: Wed, 17 Apr 2024 09:38:48 -0700 Subject: [PATCH 22/25] Update designdocs/provider_boosting_economic_model.md Co-authored-by: Wil Wade --- designdocs/provider_boosting_economic_model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index f9a68041e5..10f2ffaa5e 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -72,5 +72,5 @@ Rewards are not prorated; they are calculated only for balances held for an enti ## Claiming Rewards * Provider Boost Rewards are not minted until they are explicitly claimed 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 MSA of the Provider Boost Account. +* 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?** From 0788e7f3ce236b60ed0e86e8c71542985394221a Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 17 Apr 2024 14:42:55 -0700 Subject: [PATCH 23/25] End user -> user, plus correct some grammar --- designdocs/provider_boosting_economic_model.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index 10f2ffaa5e..baa46cfa79 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -20,9 +20,9 @@ There is also a business case for allowing any token holder to lock up its token A system consisting only of providers and coinless users who delegate to providers will tend toward centralization. To build a self-sustaining Frequency network where control is decentralized, a variety of economic solutions are needed. One of these is the ability to lock up FRQCY token in return for something; this creates an incentive for participation and involvement with the Frequency chain fundamentals and governance. -How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. In the proposed system, when Providers receive Capacity when end users lock up some FRQCY, they would lose Capacity if those end users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. This gives those end-users relying upon - and Boosting - their Providers the ability to exercise direct market power they did not previously have. +How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. In the proposed system, Providers receive Capacity when users lock up some FRQCY. These Providers would then lose Capacity if those users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. This gives those end-users relying upon - and Boosting - their Providers the ability to exercise direct market power they did not previously have. -End users with Message Source Accounts (MSAs) may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). +Users with Message Source Accounts (MSAs) may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. From 235335ec5951d19d3c6febd736209656b8bba419 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 17 Apr 2024 17:49:56 -0700 Subject: [PATCH 24/25] MSAs not needed for Provider Boost program --- designdocs/provider_boosting_economic_model.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index baa46cfa79..9072e82701 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -22,7 +22,7 @@ To build a self-sustaining Frequency network where control is decentralized, a v How is that so? Capacity is how Frequency intends Providers to pay for the vast majority of their on-chain messages. In the proposed system, Providers receive Capacity when users lock up some FRQCY. These Providers would then lose Capacity if those users unlock. If a Provider's Capacity from Provider Boosting is significant, this gives Provider Boosters some power over their targeted Providers. If a Provider is utilizing all or nearly all their Capacity almost every Epoch -- which they should do if trying to be economical -- then even a small percentage of lost Capacity will literally cost them to replace it. This gives those end-users relying upon - and Boosting - their Providers the ability to exercise direct market power they did not previously have. -Users with Message Source Accounts (MSAs) may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). +Account holders on Frequency may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design. @@ -45,8 +45,8 @@ This document does not: ## Proposal: ### Inputs to Provider Boost Reward Calculation * Rera is a predetermined amount of FRQCY available each Boost Era for Rewards -* Lu is the amount an MSA holder has locked for Provider Boost Era e -* LT is the total that all MSA holders have locked for Provider Boost Era e +* Lu is the amount a given Provider Boost account has locked for Provider Boost Era e +* LT is the total that all Provider Boost accounts have locked for Provider Boost Era e * Pmax is the maximum percentage of a Provider-Boosted amount that can be paid out in Era e ### Formula From 5a1b57b706319c6d1dfedb0b9725ad3942011eb8 Mon Sep 17 00:00:00 2001 From: shannonwells Date: Wed, 17 Apr 2024 17:53:14 -0700 Subject: [PATCH 25/25] explicitly state MSAs are not required --- designdocs/provider_boosting_economic_model.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/designdocs/provider_boosting_economic_model.md b/designdocs/provider_boosting_economic_model.md index 9072e82701..8363b96265 100644 --- a/designdocs/provider_boosting_economic_model.md +++ b/designdocs/provider_boosting_economic_model.md @@ -24,6 +24,9 @@ How is that so? Capacity is how Frequency intends Providers to pay for the vast Account holders on Frequency may receive FRQCY from different sources. Providers may offer airdrops in return for such bringing in new users or sharing links on other platforms, then encourage their users to participate in Provider Boosting. Rewards could potentially be exchanged for non-transferable, in-app-only benefits such as premium features, special emoji, avatar customization, and the like, similarly to platforms such as [Steam](https://store.steampowered.com). +### Provider Boost Accounts are not required to have MSA +Any Frequency account with an existential balance + the minimum staking amount in FRQCY may participate in in the Provider Boost program. An MSA is optional. + ## Assumptions * The exact formula for calculating rewards is determined in advance and used in the implementation of this design.