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

feat: add emit events and update spec docs #46

Merged
merged 14 commits into from
Sep 30, 2021
2 changes: 1 addition & 1 deletion x/budget/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/tendermint/budget/x/budget/types"
)

// BeginBlocker distribute budget rewards for the previous block
// BeginBlocker collect budgets for the current block
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
err := k.BudgetCollection(ctx)
Expand Down
11 changes: 11 additions & 0 deletions x/budget/keeper/budget.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ func (k Keeper) BudgetCollection(ctx sdk.Context) error {
// TODO: sendcoins after validation
sendCoins(budgetSourceAcc, collectionAcc, collectionCoins)
k.AddTotalCollectedCoins(ctx, budget.Name, collectionCoins)

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeBudgetCollected,
sdk.NewAttribute(types.AttributeValueName, budget.Name),
sdk.NewAttribute(types.AttributeValueCollectionAddress, budget.CollectionAddress),
sdk.NewAttribute(types.AttributeValueBudgetSourceAddress, budget.BudgetSourceAddress),
sdk.NewAttribute(types.AttributeValueRate, budget.Rate.String()),
sdk.NewAttribute(types.AttributeValueAmount, collectionCoins.String()),
),
})
}
// temporary validation logic
if totalCollectionCoins.IsAnyGT(validatedExpectedCollectionCoins) {
Expand Down
128 changes: 58 additions & 70 deletions x/budget/spec/01_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,61 @@

## Budget Module

`x/budget` is a Cosmos SDK module that implements budget functionality.

### 1. Atom Inflation Distribution case

- Current : distribution module reward flow

1. Gas fees collected in ante handler, sent to `feeCollectorName` module account

2. Atom inflation minted in mint module, sent to `feeCollectorName` module account

3. In distribution module

a) Send all rewards in `feeCollectorName` to distribution module account

b) From `distributionModuleAccount`, substitute `communityTax`

c) Rest are distributed to proposer and validator reward pools

d) Substituted amount for community budget is saved in kv store

- **Implementation with Budget Module**

- Implementation Independency
- Budget Module is **100% independent** from other existing modules
- We don’t need to change **any module** at all to adopt Budget Module!
- Budget Module even works **without** Distribution Module or Mint Module!
- Begin Block Processing Order : Mint → **(Budget)** → Distribution
- Functionalities
- Distribute Atom inflation and gas fees to different budget purposes
- Atom inflation and gas fees are accumulated in `feeCollectorName` module account
- Distribute budget amounts from `feeCollectorName` module account to **each budget pool** module account
- Rest amounts **stay** in `feeCollectorName` so that “Distribution Module” can use it for community fund and staking rewards distribution
- Create, modify or remove budget plans via governance
- Budget plans can be created, modified or removed by **usual parameter governance**
- Coin Flow with Budget module
- In Mint Module
- Atom inflation to `feeCollectorName` module account
- [https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/mint/abci.go#L27-L40](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/mint/abci.go#L27-L40)
- [https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/mint/keeper/keeper.go#L108-L110](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/mint/keeper/keeper.go#L108-L110)
- In Ante Handler
- Gas fees to `feeCollectorName` module account
- [https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/auth/ante/fee.go#L112-L135](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/auth/ante/fee.go#L112-L135)
- In Budget Module
- Part of Atom inflation and gas fees go to different budget pools
- Rest stays within `feeCollectorName` module account
- In Distribution Module
- All amounts in `feeCollectorName` module account go to community fund and staking rewards
- [https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/distribution/keeper/allocation.go#L82-L101](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc0/x/distribution/keeper/allocation.go#L82-L101)

- budget module parameter example

```json
{
"budget": {
"params": {
"epoch_blocks": 1,
"budgets": [
{
"name": "liquidity-farming-20213Q-20221Q",
"rate": "0.300000000000000000",
"budget_source_address": "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", // Address corresponding to fee_collector module account in cosmoshub case
"collection_address": "cosmos10pg34xts7pztyu9n63vsydujjayge7gergyzavl4dhpq36hgmkts880rwl", // 32-bytes address case, sdk.AccAddress(address.Module("farming", []byte("FarmingBudget"))).String()
"start_time": "2021-10-01T00:00:00Z",
"end_time": "2022-04-01T00:00:00Z"
}
]
}
}
}
```
`x/budget` is a simple Cosmos SDK module that implements budget functionality. It is an independent module from other SDK modules and core functionality is to enable anyone to create a budget plan through parameter change governance proposal. Once it is agreed within the community, voted, and passed, it uses `BudgetSourceAddress` to distribute amount of coins relative to the rate defined in the plan to the `CollectionAddress`. At each `BeginBlock`, collecting all budgets and distribution take place every `EpochBlocks`. `EpochBlocks` is a global parameter that can be modified by a governance proposal.

A primary use case is for Gravity DEX farming plan. A budget module can be used to create a budget plan that has `BudgetSourceAddress` for Cosmos Hub's [FeeCollector](https://github.com/cosmos/cosmos-sdk/blob/v0.44.0/x/auth/types/keys.go#L15) module account which collects transaction gas fees and part of ATOM inflation. Then, `BudgetSourceAddress` plans to distribute some amount of coins to `CollectionAddress` for farming plan.

### Budget Plan for ATOM Inflation Use Case

Cosmos SDK's current reward workflow

- In AnteHandler

- Gas fees are collected in ante handler and they are sent to `FeeCollectorName` module account

- Reference the following lines of code

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.44.0/x/auth/ante/fee.go#L112-L140

- In `x/mint` module

- ATOM inflation is minted in `x/mint` module and they are sent to `FeeCollectorName` module account

- Reference the following lines of code

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.44.0/x/mint/abci.go#L27-L40

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.44.0/x/mint/keeper/keeper.go#L108-L110

- In `x/distribution` module

- Send all rewards in `FeeCollectorName` to distribution module account

- From `distributionModuleAccount`, substitute `communityTax`

- Rest are distributed to proposer and validator reward pools

- Substituted amount for community budget is saved in kv store

- Reference the following lines of code

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.44.0/x/distribution/keeper/allocation.go#L13-L102

Implementation with Budget Module

- A budget module is 100% independent from other Cosmos SDK's existing modules

- BeginBlock processing order is the following order

- mint module → budget module → distribution module

- Distribute ATOM inflation and transaction gas fees to different budget purposes

- ATOM inflation and gas fees are accumulated in `FeeCollectorName` module account

- Distribute budget amounts from `FeeCollectorName` module account to each budget pool module account

- Rest amounts stay in `FeeCollectorName` so that distribution module can use it for community fund and staking rewards distribution as what it is doing now

- Create, modify or remove budget plans via governance process
- A budget plan can be created, modified or removed by parameter change governance proposal
34 changes: 18 additions & 16 deletions x/budget/spec/02_state.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
<!-- order: 2 -->

# State

## Budget

The Budget structure is not stored in kv, but in parameters in the budget module as budgets.
Budget object is not stored in KVStore.

```go
// Budget contains budget information
type Budget struct {
Name string // name defines the name of the budget
Rate sdk.Dec // rate specifies the distributing amount by ratio of total budget source
BudgetSourceAddress string // budget_source_address defines the bech32-encoded address that source of the budget
CollectionAddress string // collection_address defines the bech32-encoded address of the budget pool to distribute
StartTime time.Time // start_time specifies the start time of the budget
EndTime time.Time // end_time specifies the end time of the budget
Name string // name of the budget
Rate sdk.Dec // distributing amount by ratio of total budget source
BudgetSourceAddress string // bech32-encoded address that source of the budget
CollectionAddress string // bech32-encoded address that collects budget from the budget source address
StartTime time.Time // start time of the budget plan
EndTime time.Time // end time of the budget plan
}
```

### Total collected coins
+++ https://github.com/tendermint/budget/blob/master/proto/tendermint/budget/v1beta1/budget.proto#L25-L53

The total collected coins is cumulative coins collected in the budget since the bucket was created.
The total collected coins for each budget are stored as follows:
```
0x11 | BudgetName -> TotalCollectedCoins
```
## TotalCollectedCoins

Where `TotalCollectedCoins` is just a wrapper around `sdk.Coins`:
```go
// TotalCollectedCoins are cumulative coins collected in the budget since the bucket was created.
type TotalCollectedCoins struct {
TotalCollectedCoins sdk.Coins
}
```

+++ https://github.com/tendermint/budget/blob/master/proto/tendermint/budget/v1beta1/budget.proto#L55-L64


For the purpose of tracking total collected coins for a budget, budget name is used as key to find it in store.

- TotalCollectedCoins: `0x11 | BudgetName -> TotalCollectedCoins`
12 changes: 12 additions & 0 deletions x/budget/spec/03_state_transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,15 @@
# State Transitions

This document describes the state transaction operations pertaining to the budget module.

- BudgetCollection
- TotalCollectedCoins
## BudgetCollection

Get all budgets registered in `params.Budgets` and select the valid budgets to collect budgets for the block by its respective plan.
This state transition occurs at each `BeginBlock`. You can read more about it in [04_begin_block.md](04_begin_block.md).

## TotalCollectedCoins

`TotalCollectedCoins` are accumulated coins in a budget since the creation of the budget.
This state transition occurs at each `BeginBlock` with `BudgetCollection`. You can read more about it in [04_begin_block.md](04_begin_block.md).
17 changes: 13 additions & 4 deletions x/budget/spec/04_begin_block.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

# Begin-Block

1. if current height % `params.EpochBlocks` != 0 or `params.EpochBlocks` == 0, exit.
1. Get all the Budgets registered in params.Budgets and select only the valid budgets. If there is no valid budget, exit.
At each `BeginBlock`, get all budgets registered in `params.Budgets` and select the valid budgets to collect budgets for the block by its respective plan (defined rate, budget source address, collection address, start time and end time). Then, it distributes the collected amount of coins from `BudgetSourceAddrss` to `CollectionAddress`.

+++ https://github.com/tendermint/budget/blob/master/x/budget/abci.go#L15-L22

## Workflow

1. Get all the budgets registered in `params.Budgets` and proceed with the valid and not expired budgets. Otherwise, it exits and waits for the next block.

2. Create a map by `BudgetSourceAddress` to handle the budgets for the same `BudgetSourceAddress` together based on the same balance when calculating rates for the same `BudgetSourceAddress`.
3. Collect budgets from `BudgetSourceAddress` and send them to `CollectionAddress` according to the `Rate` of each `Budget`.
4. Write to metric about successful budget collection and emit events.

3. Collect budgets from `BudgetSourceAddress` and send amount of coins to `CollectionAddress` relative to the rate of each budget`.

4. Cumulate `TotalCollectedCoins` and emit events about the successful budget collection for each budget.

72 changes: 28 additions & 44 deletions x/budget/spec/06_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,43 @@

The budget module contains the following parameters:

| Key | Type | Example |
| ----------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| EpochBlocks | uint32 | {"epoch_blocks":1} |
| Budgets | []Budget | {"budgets":[{"name":"liquidity-farming-20213Q-20221Q","rate":"0.300000000000000000","budget_source_address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta","collection_address":"cosmos10pg34xts7pztyu9n63vsydujjayge7gergyzavl4dhpq36hgmkts880rwl","start_time":"2021-10-01T00:00:00Z","end_time":"2022-04-01T00:00:00Z"}]} |

| Key | Type | Example |
| ----------- | -------- | ------------------------------------------------------------------------------------ |
| EpochBlocks | uint32 | {"epoch_blocks":1} |
| Budgets | []Budget | {"budgets":[{"name":"liquidity-farming-20213Q-20221Q","rate":"0.300000000000000000","budget_source_address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta","collection_address":"cosmos10pg34xts7pztyu9n63vsydujjayge7gergyzavl4dhpq36hgmkts880rwl","start_time":"2021-10-01T00:00:00Z","end_time":"2022-04-01T00:00:00Z"}]} |

## EpochBlocks

The universal epoch length in number of blocks.
Every process for budget collecting is executed with this epoch_blocks frequency.
Every process for budget collecting is executed with this `epoch_blocks` frequency.

The default value is 1 and all budget collections are disabled if the value is 0. Budget collection logic is executed with the following condition.

the default value is 1 and when the value is 0, all budget collections are disabled.
when current height % `params.EpochBlocks` == 0 the budget collection logic is executed.
```
params.EpochBlocks > 0 && Current Block Height % params.EpochBlocks == 0
```

You can reference [the line of the code](https://github.com/tendermint/budget/blob/master/x/budget/keeper/budget.go#L78).

## Budgets

The structure of the Budget can be found at [State](02_state.md).

Budgets parameter can be added, deleted, and modified through [gov.ParameterChangeProposal](https://docs.cosmos.network/master/modules/gov/01_concepts.html#proposal-submission), and for each purpose, the changes in the existing budget list should be applied and set.

Below is an example of adding budget.

`budgetd tx gov submit-proposal param-change proposal.json`

proposal.json

```json
{
"title": "Add a example budget",
"description": "This proposition is an example of adding Budgets using ParameterChangeProposal.",
"changes": [
{
"subspace": "budget",
"key": "Budgets",
"value": [
{
"name": "liquidity-farming-20213Q-20221Q",
"rate": "0.300000000000000000",
"budget_source_address": "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta",
"collection_address": "cosmos10pg34xts7pztyu9n63vsydujjayge7gergyzavl4dhpq36hgmkts880rwl",
"start_time": "2021-10-01T00:00:00Z",
"end_time": "2022-04-01T00:00:00Z"
}
]
}
],
"deposit": "10000000uatom"
}
```
The Budget structure can be found in [02_state.md](02_state.md).

Parameter of a budget can be added, modified, and deleted through [parameter change governance proposal](https://docs.cosmos.network/master/modules/gov/01_concepts.html#proposal-submission).

An example of how to add a budget plan can be found in this [docs/How-To/cli](../../../docs/How-To/cli) guide.

### Validity Checks

- Name only allowed letters(`A-Z, a-z`), digits(`0-9`), and `-` without spaces and the maximum length is 50 and not duplicated.
- The total rate of Budgets with the same `BudgetSourceAddress` value should not exceed 1.
- Budget name only allows letters(`A-Z, a-z`), digits(`0-9`), and `-` without spaces. Also, it has the maximum length of 50 and it should not be duplicate with the existing budget names.

- Validate `CollectionAddress` address.

- Validate `BudgetSourceAddress` address.

- EndTime should not be earlier than StartTime.
- Check that the `CollectionAddress` is a valid address.
- Check that the `BudgetSourceAddress` is a valid address.

- The total rate of budgets with the same `BudgetSourceAddress` value should not exceed 1 (100%).

+++ https://github.com/tendermint/budget/blob/master/x/budget/types/budget.go#L33-L63
10 changes: 7 additions & 3 deletions x/budget/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package types

// Event types for the budget module.
const (
EventTypeAddBudget = "add_budget"
EventTypeDeleteBudget = "delete_budget"
EventTypeUpdateBudget = "update_budget"
EventTypeBudgetCollected = "budget_collected"

AttributeValueName = "name"
AttributeValueCollectionAddress = "collection_address"
AttributeValueBudgetSourceAddress = "budget_source_address"
AttributeValueRate = "rate"
AttributeValueAmount = "amount"
)