Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: edit farming spec to improve documentation quality (part of #172) #191

Merged
merged 3 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions x/farming/spec/01_concepts.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
<!-- order: 1 -->

# Concepts

## Farming Module

`x/farming` is a Cosmos SDK module that implements farming functionality that keeps track of the staking and provides farming rewards to farmers. A primary use case is to use this module to provide incentives for liquidity pool investors for their pool participation.
The `x/farming` Cosmos SDK module implements farming functionality that keeps track of staking and provides farming rewards to farmers. A primary use case of this module is to provide incentives for liquidity pool investors for their pool participation.

## Plans

There are two types of farming plans in the `farming` module as below.
There are two types of farming plans in the `farming` module:

### Public Farming Plan

A public farming plan can be created only through governance proposal.

### 1. Public Farming Plan
- The proposal must be first agreed and passed before a public farming plan can be created.
- A creation fee is not required.

A public farming plan can only be created through governance proposal meaning that the proposal must be first agreed and passed in order to create a public plan.
### 2. Private Farming Plan
### Private Farming Plan

A private farming plan can be created with any account. The plan creator's account is used as `TerminationAddress`. There is a fee `PlanCreationFee` paid upon plan creation to prevent from spamming attack.
A private farming plan can be created with any account.

- The account address of the plan creator account is used as the `TerminationAddress`.
- To prevent spamming attacks, the `PlanCreationFee` fee must be paid on plan creation.

## Distribution Methods

There are two types of distribution methods in the `farming` module as below.
### 1. Fixed Amount Plan
There are two types of reward distribution methods in the `farming` module:

### Fixed Amount Plan

A `FixedAmountPlan` distributes fixed amount of coins to farmers for every epoch day. If the plan creators `FarmingPoolAddress` is depleted with distributing coins, then there is no more coins to distribute unless it is filled up again.
A `FixedAmountPlan` distributes a fixed amount of coins to farmers for every epoch day.

### 2. Ratio Plan
When the plan creator's `FarmingPoolAddress` is depleted, then there are no more coins to distribute until more coins are added to the account.

A `RatioPlan` distributes to farmers by ratio distribution for every epoch day. If the plan creators `FarmingPoolAddress` is depleted with distributing coins, then there is no more coins to distribute unless it is filled up with more coins.
### Ratio Plan

A `RatioPlan` distributes coins to farmers by ratio distribution for every epoch day.

If the plan creator's `FarmingPoolAddress` is depleted, then there are no more coins to distribute until more coins are added to the account.

## Accumulated Reward Calculation

In farming module, farming rewards are calculated per epoch based on plans. The rewards for a single farmer can be calculated by taking the total rewards for the epoch before the staking started, minus the current total rewards. The farming module takes references from [F1 Fee Distribution](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/fee_distribution/f1_fee_distr.pdf) that is used in Cosmos SDK [x/distribution](https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/spec/01_concepts.md) module.
In the farming module, farming rewards are calculated per epoch based on the distribution plan.

To calculate the rewards for a single farmer, take the total rewards for the epoch before the staking started, minus the current total rewards.

The farming module takes references from [F1 Fee Distribution](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/fee_distribution/f1_fee_distr.pdf) that is used in the Cosmos SDK [x/distribution](https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/spec/01_concepts.md) module.

### Accumulated Unit Reward

Expand Down
21 changes: 12 additions & 9 deletions x/farming/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

# State

The farming module keeps track of the staking and rewards states.
The `farming` module keeps track of the staking and rewards states.

## Plan Interface

The plan interface exposes methods to read and write standard farming plan information. Note that all of these methods operate on a plan struct confirming to the interface and in order to write the plan to the store, the plan keeper will need to be used.
The plan interface exposes methods to read and write standard farming plan information.

Note that all of these methods operate on a plan struct that confirms to the interface. In order to write the plan to the store, the plan keeper is required.

```go
// PlanI is an interface used to store plan records within state.
Expand Down Expand Up @@ -56,7 +58,7 @@ type PlanI interface {

## Base Plan

A base plan is the simplest and most common plan type, which just stores all requisite fields directly in a struct.
A base plan is the simplest and most common plan type that just stores all requisite fields directly in a struct.

```go
// BasePlan defines a base plan type. It contains all the necessary fields
Expand Down Expand Up @@ -111,7 +113,7 @@ const (
)
```

The parameters of the Plan state are:
The parameters of the plan state are:

- ModuleName, RouterKey, StoreKey, QuerierRoute: `farming`
- Plan: `0x11 | Id -> ProtocolBuffer(Plan)`
Expand All @@ -135,7 +137,8 @@ type Staking struct {
}
```

The parameters of the Staking state are:
The parameters of the staking state are:

- Staking: `0x21 | StakingCoinDenomLen (1 byte) | StakingCoinDenom | FarmerAddr -> ProtocolBuffer(Staking)`
- StakingIndex: `0x22 | FarmerAddrLen (1 byte) | FarmerAddr | StakingCoinDenom -> nil`

Expand All @@ -158,7 +161,7 @@ type TotalStakings struct {

## Historical Rewards

`HistoricalRewards` struct holds the cumulative unit rewards for each epoch which are needed for the reward calculation.
The `HistoricalRewards` struct holds the cumulative unit rewards for each epoch that are required for the reward calculation.

```go
type HistoricalRewards struct {
Expand All @@ -171,7 +174,7 @@ type HistoricalRewards struct {

## Outstanding Rewards

`OutstandingRewards` struct holds outstanding(un-withdrawn) rewards for a staking denom.
The `OutstandingRewards` struct holds outstanding (un-withdrawn) rewards for a staking denom.

```go
type OutstandingRewards struct {
Expand All @@ -183,7 +186,7 @@ type OutstandingRewards struct {

## Examples

An example of `FixedAmountPlan`
An example of `FixedAmountPlan`:

```json
{
Expand Down Expand Up @@ -227,7 +230,7 @@ An example of `FixedAmountPlan`
}
```

An example of `RatioPlan`
An example of `RatioPlan`:

```json
{
Expand Down
44 changes: 24 additions & 20 deletions x/farming/spec/03_state_transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

# State Transitions

This document describes the state transaction operations pertaining to the farming module.
This document describes the state transaction operations for the farming module.

## Plan
## Plans

As stated in [Concepts](01_concepts.md), both public and private farming plans are available in the `farming` module:

- A public farming plan can be created only through governance proposal.
- A private farming plan can be created with any account.

As stated in [01_concepts.md](01_concepts.md), there are public and private farming plans available in the `farming` module. Private plan can be created by any account whereas public plan can only be created through governance proposal.

```go
// PlanType enumerates the valid types of a plan.
Expand All @@ -26,35 +30,35 @@ const (

When a farmer stakes an amount of coins, the following state transitions occur:

- it reserves the amount of coins to the staking reserve pool account `StakingReservePoolAcc`
- it creates `QueuedStaking` object and stores the staking coins in `QueueStaking`, which are waiting in a queue until the end of epoch to move to `Staking` object
- it imposes more gas if the farmer already has `Staking` with the same coin denom(see [07_params.md](07_params.md#DelayedStakingGasFee) for details)
- Reserves the amount of coins to the staking reserve pool account `StakingReservePoolAcc`
- Creates `QueuedStaking` object and stores the staking coins in `QueueStaking`, which then wait in a queue until the end of epoch to move to the `Staking` object
- Imposes more gas if the farmer already has `Staking` with the same coin denom. See [Parameters](07_params.md#DelayedStakingGasFee) for details.

## Unstake

When a farmer unstakes an amount of coins, the following state transitions occur:

- it adds `Staking` and `QueueStaking` amounts to see if the unstaking amount is sufficient
- it automatically withdraws rewards for the coin denom which are accumulated over the last epochs
- it subtracts the unstaking amount of coins from `QueueStaking` first and if it is not sufficient then it subtracts from `Staking`
- it releases the unstaking amount of coins to the farmer
- Adds `Staking` and `QueueStaking` amounts to see if the unstaking amount is sufficient
- Automatically withdraws rewards for the coin denom that are accumulated over the last epochs
- Subtracts the unstaking amount of coins from `QueueStaking` first, and if not sufficient then subtracts from `Staking`
- Releases the unstaking amount of coins to the farmer

## Harvest (Reward Withdrawal)

- it calculates `CumulativeUnitRewards` in `HistoricalRewards` object in order to get the rewards for the staking coin denom which are accumulated over the last epochs for the farmer
- it releases the accumulated rewards to the farmer if it is not zero and decreases the `OutstandingRewards`
- it sets `StartingEpoch` in `Staking` object
- Calculates `CumulativeUnitRewards` in `HistoricalRewards` object in order to get the rewards for the staking coin denom that are accumulated over the last epochs
- Releases the accumulated rewards to the farmer if it is not zero and decreases the `OutstandingRewards`
- Sets `StartingEpoch` in `Staking` object

## Reward Allocation

If the sum of total calculated `EpochAmount` (or `EpochRatio` multiplied by the farming pool's balance) exceeds the farming pool's balance, then the reward allocation is skipped for that epoch.
If the sum of total calculated `EpochAmount` (or `EpochRatio` multiplied by the farming pool balance) exceeds the farming pool balance, then skip the reward allocation for that epoch.

Each abci end block call, the operations to update rewards allocation are to execute:
For each [abci end block call](https://docs.cosmos.network/master/modules/staking/05_end_block.html), the operations to update the rewards allocation are:

++ https://github.com/tendermint/farming/blob/69db071ce30b99617b8ba9bb6efac76e74cd100b/x/farming/keeper/reward.go#L363-L426

- it calculates rewards allocation information for the end of the current epoch depending on plan type `FixedAmountPlan` or `RatioPlan`
- it distributes total allocated coins from each plan’s farming pool address `FarmingPoolAddress` to the rewards reserve pool account `RewardsReserveAcc`
- it calculates staking coin weight for each denom in each plan and gets the unit rewards by denom
- it updates `HistoricalRewards` and `CurrentEpoch` based on the allocation information
- it deletes `QueueStaking` object after moving `QueueCoins` to `StakedCoins` in `Staking` object
- Calculates rewards allocation information for the end of the current epoch depending on plan type `FixedAmountPlan` or `RatioPlan`
- Distributes total allocated coins from each plan’s farming pool address `FarmingPoolAddress` to the rewards reserve pool account `RewardsReserveAcc`
- Calculates staking coin weight for each denom in each plan and gets the unit rewards by denom
- Updates `HistoricalRewards` and `CurrentEpoch` based on the allocation information
- Deletes `QueueStaking` object after moving `QueueCoins` to `StakedCoins` in the `Staking` object
46 changes: 38 additions & 8 deletions x/farming/spec/04_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@

# Messages

Messages (Msg) are objects that trigger state transitions. Msgs are wrapped in transactions (Txs) that clients submit to the network. The Cosmos SDK wraps and unwraps farming module messages from transactions.
Messages (Msg) are objects that trigger state transitions. Msgs are wrapped in transactions (Txs) that clients submit to the network. The Cosmos SDK wraps and unwraps `farming` module messages from transactions.

## MsgCreateFixedAmountPlan

This is one of the private plan type messages that anyone can create. A fixed amount plan plans to distribute amount of coins by a fixed amount defined in `EpochAmount`. Internally, `PrivatePlanFarmingPoolAddress` is generated and assigned to the plan and the creator should query the plan and send amount of coins to the farming pool address so that the plan distributes as intended. Note that there is a fee `PlanCreationFee` paid upon plan creation to prevent from spamming attack.
Anyone can create this private plan type message.

- A fixed amount plan distributes the amount of coins by a fixed amount that is defined in `EpochAmount`.
- Internally, `PrivatePlanFarmingPoolAddress` is generated and assigned to the plan.

The creator must query the plan and send the amount of coins to the farming pool address so that the plan distributes as intended.

**Note:** The `PlanCreationFee` must be paid on plan creation to prevent spamming attacks.

```go
type MsgCreateFixedAmountPlan struct {
Expand All @@ -21,7 +28,17 @@ type MsgCreateFixedAmountPlan struct {

## MsgCreateRatioPlan

This is one of the private plan type messages that anyone can create. A ratio plan plans to distribute amount of coins by ratio defined in `EpochRatio`. Internally, `PrivatePlanFarmingPoolAddress` is generated and assigned to the plan and the creator should query the plan and send amount of coins to the farming pool address so that the plan distributes as intended. For a ratio plan, whichever coins that the farming pool address has in balances are used every epoch. Note that there is a fee `PlanCreationFee` paid upon plan creation to prevent from spamming attack.
Anyone can create this private plan type message.

- A ratio plan plans to distribute amount of coins by ratio defined in `EpochRatio`.
- Internally, `PrivatePlanFarmingPoolAddress` is generated and assigned to the plan.

The creator must query the plan and send the amount of coins to the farming pool address so that the plan distributes as intended.

For a ratio plan, whichever coins the farming pool address has in balances are used every epoch.

**Note:** The `PlanCreationFee` must be paid on plan creation to prevent spamming attacks.


```go
type MsgCreateRatioPlan struct {
Expand All @@ -36,7 +53,7 @@ type MsgCreateRatioPlan struct {

## MsgStake

A farmer must have sufficient amount of coins to stake. If a farmer stakes coin(s) that are defined in staking coin weights of plans, then the farmer becomes eligible to receive rewards.
A farmer must have sufficient amount of coins to stake. If a farmer stakes coin or coins that are defined in staking the coin weights of plans, then the farmer becomes eligible to receive rewards.

```go
type MsgStake struct {
Expand All @@ -47,7 +64,11 @@ type MsgStake struct {

## MsgUnstake

A farmer must have some staking coins to trigger this message. Unlike Cosmos SDK's [staking](https://github.com/cosmos/cosmos-sdk/blob/master/x/staking/spec/01_state.md) module, there is no concept of unbonding period that requires some time to unstake coins. All the accumulated farming rewards are automatically withdrawn to the farmer once unstaking event is triggered.
A farmer must have some staking coins to trigger this message.

In contrast to the Cosmos SDK [staking](https://github.com/cosmos/cosmos-sdk/blob/master/x/staking/spec/01_state.md) module, there is no concept of an unbonding period where some time is required to unstake coins.

All of the accumulated farming rewards are automatically withdrawn to the farmer after an unstaking event is triggered.

```go
type MsgUnstake struct {
Expand All @@ -58,7 +79,9 @@ type MsgUnstake struct {

## MsgHarvest

The farming rewards are automatically accumulated, but they are not automatically distributed. A farmer should harvest their farming rewards. This mechanism is similar with Cosmos SDK's [distribution](https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/spec/01_concepts.md) module.
The farming rewards are automatically accumulated, but they are not automatically distributed.

A farmer must harvest their farming rewards. This mechanism is similar to the Cosmos SDK [distribution](https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/spec/01_concepts.md) module.

```go
type MsgHarvest struct {
Expand All @@ -69,8 +92,15 @@ type MsgHarvest struct {

## MsgAdvanceEpoch

This is custom message to advance epoch by one for the testing purpose. Enabling this message is possibly only if you build `farmingd` binary with `make install-testing` command.
When you send `MsgAdvanceEpoch` to the network, it increases epoch by 1.
For testing purposes only, this custom message is used to advance epoch by 1.

To enable this message, you must build the `farmingd` binary:

```sh
make install-testing
```

When you send the `MsgAdvanceEpoch` message to the network, epoch increases by 1.

```go
type MsgAdvanceEpoch struct {
Expand Down
20 changes: 19 additions & 1 deletion x/farming/spec/05_end_block.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
<!-- order: 6 -->
# End-Block

At each end-block call, the `farming` module operations are specified to execute.

++ https://github.com/tendermint/farming/blob/69db071ce3/x/farming/abci.go#L13-L46

At the end of each block, it terminates plans that their end time has passed over the current block time. It sends all remaining coins in the plan's farming pool account `FarmingPoolAddress` to the termination address `TerminationAddress` and mark the plan as terminated by making `Terminated` true. A global parameter `NextEpochDays` is there but the farming module uses an internal state `CurrentEpochDays` to prevent from a case where it may affect the rewards allocation. Suppose `NextEpochDays` is 7 and it is proposed to change the value to 1 through governance proposal. Although the proposal is passed, rewards allocation should continue to proceed with 7, not 1. The [test code](https://github.com/tendermint/farming/blob/69db071ce3/x/farming/abci_test.go#L12-L64) is available for you if you want to understand it in more detail. Then it allocates farming rewards, processes `QueueStaking` to be staked, and sets `LastEpochTime` to keep in track in case of the chain upgrade.
At the end of each block:

- Terminates plans if their end time has passed over the current block time.

- Sends all remaining coins in the plan's farming pool account `FarmingPoolAddress` to the termination address `TerminationAddress`.
- Marks the plan as terminated by making `Terminated` true.
- Allocates farming rewards.
- Processes `QueueStaking` to be staked.
- Sets `LastEpochTime` to track in case of chain upgrade.

## Internal state CurrentEpochDays

Although a global parameter `NextEpochDays` exists, the farming module uses an internal state `CurrentEpochDays` to prevent impacting rewards allocation.

Suppose `NextEpochDays` is 7 and it is proposed to change the value to 1 through governance proposal. Although the proposal is passed, rewards allocation must continue to proceed with 7, not 1.

To explore internal state `CurrentEpochDays` in more detail, see the [test code](https://github.com/tendermint/farming/blob/69db071ce3/x/farming/abci_test.go#L12-L64).
4 changes: 2 additions & 2 deletions x/farming/spec/06_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Events

The farming module emits the following events:
The `farming` module emits the following events:

## EndBlocker

Expand Down Expand Up @@ -82,4 +82,4 @@ The farming module emits the following events:

### MsgAdvanceEpoch

This message is for testing purpose. It is only available when you build `farmingd` binary by `make install-testing` command.
The `MsgAdvanceEpoch` message is for testing purposes only and requires that you build the `farmingd` binary. See [MsgAdvanceEpoch](04_messages.md#MsgAdvanceEpoch).
Loading