diff --git a/x/budget/abci.go b/x/budget/abci.go index b4f118c..2b8a3de 100644 --- a/x/budget/abci.go +++ b/x/budget/abci.go @@ -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) diff --git a/x/budget/keeper/budget.go b/x/budget/keeper/budget.go index 3edbec7..324c785 100644 --- a/x/budget/keeper/budget.go +++ b/x/budget/keeper/budget.go @@ -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) { diff --git a/x/budget/spec/01_concepts.md b/x/budget/spec/01_concepts.md index 42d091a..4394426 100644 --- a/x/budget/spec/01_concepts.md +++ b/x/budget/spec/01_concepts.md @@ -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 diff --git a/x/budget/spec/02_state.md b/x/budget/spec/02_state.md index 7d20843..0a8d01f 100644 --- a/x/budget/spec/02_state.md +++ b/x/budget/spec/02_state.md @@ -1,33 +1,35 @@ - # 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` diff --git a/x/budget/spec/03_state_transitions.md b/x/budget/spec/03_state_transitions.md index 077c9eb..3065a5c 100644 --- a/x/budget/spec/03_state_transitions.md +++ b/x/budget/spec/03_state_transitions.md @@ -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). diff --git a/x/budget/spec/04_begin_block.md b/x/budget/spec/04_begin_block.md index 9a0c231..d6ed4b4 100644 --- a/x/budget/spec/04_begin_block.md +++ b/x/budget/spec/04_begin_block.md @@ -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. \ No newline at end of file + +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. + diff --git a/x/budget/spec/06_params.md b/x/budget/spec/06_params.md index 93a3d3b..6341f8a 100644 --- a/x/budget/spec/06_params.md +++ b/x/budget/spec/06_params.md @@ -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 \ No newline at end of file diff --git a/x/budget/types/events.go b/x/budget/types/events.go index 699269a..274b0da 100644 --- a/x/budget/types/events.go +++ b/x/budget/types/events.go @@ -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" )