Add hard and incentive spec updates (#817)

* wip: update hard spec

* feat: updated hard spec

* feat: updated incentive spec
This commit is contained in:
Kevin Davis 2021-02-19 09:14:48 -07:00 committed by GitHub
parent bdbc9b9c58
commit c5fc1c6b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 430 additions and 194 deletions

View File

@ -4,19 +4,11 @@ order: 1
# Concepts
The hard module introduces the hard token to the kava blockchain. This module distributes hard tokens to two types of ecosystem participants:
## Automated, Cross-Chain Money Markets
1. Kava stakers - any address that stakes (delegates) kava tokens will be eligible to claim hard tokens. For each delegator, hard tokens are accumulated ratably based on the total number of kava tokens staked. For example, if a user stakes 1 million KAVA tokens and there are 100 million staked KAVA, that user will accumulate 1% of hard tokens earmarked for stakers during the distribution period. Distribution periods are defined by a start date, an end date, and a number of hard tokens that are distributed per second.
2. Depositors - any address that deposits eligible tokens to the hard module will be eligible to claim hard tokens. For each depositor, hard tokens are accumulated ratably based on the total number of tokens staked of that denomination. For example, if a user deposits 1 million "xyz" tokens and there are 100 million xyz deposited, that user will accumulate 1% of hard tokens earmarked for depositors of that denomination during the distribution period. Distribution periods are defined by a start date, an end date, and a number of hard tokens that are distributed per second.
The hard module provides for functionality and governance of a two-sided money market protocol with autonomous interest rates and partially autonomous liquidations. The main state transitions in the hard module are composed of deposit, withdraw, borrow and repay actions. Additionally, borrow positions can be liquidated by the autonomous liquidation engine or by an external party called a "keeper". Keepers receive a fee in exchange for liquidating risk positions, and the fee rate is determined by governance. Internally, all funds are stored in a module account (the cosmos-sdk equivalent of the `address` portion of a smart contract), and can be accessed via the above actions. Each money market has governance parameters which are controlled by token-holder governance. Of particular note are the interest rate model, which determines (using a static formula) what the prevailing rate of interest will be for each block, and the loan-to-value (LTV), which determines how much borrowing power each unit of deposited collateral will count for. Initial parameterization of the hard module will stipulate that all markets are over-collateralized and that overall borrow limits for each collateral will start small and rise gradually.
Users are not air-dropped tokens, rather they accumulate `Claim` objects that they may submit a transaction in order to claim. In order to better align long term incentives, when users claim hard tokens, they have three options, called 'multipliers', for how tokens are distributed.
## HARD Token distribution
- Liquid - users can immediately receive hard tokens, but they will receive a smaller fraction of tokens than if they choose medium-term or long-term locked tokens.
- Medium-term locked - users can receive tokens that are medium-term transfer restricted. They will receive more tokens than users who choose liquid tokens, but fewer than those who choose long term locked tokens.
- Long-term locked - users can receive tokens that are long-term transfer restricted. Users choosing this option will receive more tokens than users who choose liquid or medium-term locked tokens.
[See Incentive Module](../../incentive/spec/01_concepts.md)
The exact multipliers will be voted by governance and can be changed via a governance vote. An example multiplier schedule would be:
- Liquid - 10% multiplier and no lock up. Users receive 10% as many tokens as users who choose long-term locked tokens.
- Medium-term locked - 33% multiplier and 6 month transfer restriction. Users receive 33% as many tokens as users who choose long-term locked tokens.
- Long-term locked - 100% multiplier and 2 year transfer restriction. Users receive 10x as many tokens as users who choose liquid tokens and 3x as many tokens as users who choose medium-term locked tokens.

View File

@ -6,47 +6,57 @@ order: 2
## Parameters and Genesis State
`Parameters` define the distribution schedule of hard tokens that will be distributed to delegators and depositors, respectively.
`Parameters` define the governance parameters and default behavior of each money market.
```go
// Params governance parameters for hard module
type Params struct {
Active bool `json:"active" yaml:"active"`
LiquidityProviderSchedules DistributionSchedules `json:"liquidity_provider_schedules" yaml:"liquidity_provider_schedules"`
DelegatorDistributionSchedules DelegatorDistributionSchedules `json:"delegator_distribution_schedules" yaml:"delegator_distribution_schedules"`
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"` // defines the parameters for each money market
CheckLtvIndexCount int `json:"check_ltv_index_count" yaml:"check_ltv_index_count"` // defines the number of positions that are checked for liquidation at the beginning of each block
}
// DistributionSchedule distribution schedule for liquidity providers
type DistributionSchedule struct {
Active bool `json:"active" yaml:"active"`
DepositDenom string `json:"deposit_denom" yaml:"deposit_denom"`
Start time.Time `json:"start" yaml:"start"`
End time.Time `json:"end" yaml:"end"`
RewardsPerSecond sdk.Coin `json:"rewards_per_second" yaml:"rewards_per_second"`
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"`
// MoneyMarket is a money market for an individual asset
type MoneyMarket struct {
Denom string `json:"denom" yaml:"denom"` // the denomination of the token for this money market
BorrowLimit BorrowLimit `json:"borrow_limit" yaml:"borrow_limit"` // the borrow limits, if any, applied to this money market
SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // the pricefeed market where price data is fetched
ConversionFactor sdk.Int `json:"conversion_factor" yaml:"conversion_factor"` //the internal conversion factor for going from the smallest unit of a token to a whole unit (ie. 8 for BTC, 6 for KAVA, 18 for ETH)
InterestRateModel InterestRateModel `json:"interest_rate_model" yaml:"interest_rate_model"` // the model that determines the prevailing interest rate at each block
ReserveFactor sdk.Dec `json:"reserve_factor" yaml:"reserve_factor"` // the percentage of interest that is accumulated by the protocol as reserves
AuctionSize sdk.Int `json:"auction_size" yaml:"auction_size"` // the maximum size of auction for this money market. Liquidations larger than this will be broken down into multiple auctions
KeeperRewardPercentage sdk.Dec `json:"keeper_reward_percentage" yaml:"keeper_reward_percentages"` // the percentage of a liquidation that is given to the keeper that liquidated the position
}
// DistributionSchedules slice of DistributionSchedule
type DistributionSchedules []DistributionSchedule
// MoneyMarkets slice of MoneyMarket
type MoneyMarkets []MoneyMarket
// DelegatorDistributionSchedule distribution schedule for delegators
type DelegatorDistributionSchedule struct {
DistributionSchedule DistributionSchedule `json:"distribution_schedule" yaml:"distribution_schedule"`
DistributionFrequency time.Duration `json:"distribution_frequency" yaml:"distribution_frequency"`
// InterestRateModel contains information about an asset's interest rate
type InterestRateModel struct {
BaseRateAPY sdk.Dec `json:"base_rate_apy" yaml:"base_rate_apy"` // the base rate of APY when borrows are zero. Ex. A value of "0.02" would signify an interest rate of 2% APY as the Y-intercept of the interest rate model for the money market. Note that internally, interest rates are stored as per-second interest.
BaseMultiplier sdk.Dec `json:"base_multiplier" yaml:"base_multiplier"` // the percentage rate at which the interest rate APY increases for each percentage increase in borrow utilization. Ex. A value of "0.01" signifies that the APY interest rate increases by 1% for each additional percentage increase in borrow utilization.
Kink sdk.Dec `json:"kink" yaml:"kink"` // the inflection point at which the BaseMultiplier no longer applies and the JumpMultiplier does apply. For example, a value of "0.8" signifies that at 80% utilization, the JumpMultiplier applies
JumpMultiplier sdk.Dec `json:"jump_multiplier" yaml:"jump_multiplier"` // same as BaseMultiplier, but only applied when utilization is above the Kink
}
// DelegatorDistributionSchedules slice of DelegatorDistributionSchedule
type DelegatorDistributionSchedules []DelegatorDistributionSchedule
// BorrowLimit enforces restrictions on a money market
type BorrowLimit struct {
HasMaxLimit bool `json:"has_max_limit" yaml:"has_max_limit"` // boolean for if the money market has a max amount that can be borrowed, irrespective of utilization.
MaximumLimit sdk.Dec `json:"maximum_limit" yaml:"maximum_limit"` // the maximum amount that can be borrowed for this money market, irrespective of utilization. Ignored if HasMaxLimit is false
LoanToValue sdk.Dec `json:"loan_to_value" yaml:"loan_to_value"` // the percentage amount of borrow power each unit of deposit accounts for. Ex. A value of "0.5" signifies that for $1 of supply of a particular asset, borrow limits will be increased by $0.5
}
```
`GenesisState` defines the state that must be persisted when the blockchain stops/restarts in order for normal function of the hard module to resume.
`GenesisState` defines the state that must be persisted when the blockchain stops/restarts in order for normal function of the hard module to resume and all outstanding funds + interest to be accounted for.
```go
// GenesisState is the state that must be provided at genesis.
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
Params Params `json:"params" yaml:"params"` // governance parameters
PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"` // stores the last time interest was calculated for a particular money market
Deposits Deposits `json:"deposits" yaml:"deposits"` // stores existing deposits when the chain starts, if any
Borrows Borrows `json:"borrows" yaml:"borrows"` // stores existing borrows when the chain starts, if any
TotalSupplied sdk.Coins `json:"total_supplied" yaml:"total_supplied"` // stores the running total of supplied (deposits + interest) coins when the chain starts, if any
TotalBorrowed sdk.Coins `json:"total_borrowed" yaml:"total_borrowed"` // stores the running total of borrowed coins when the chain starts, if any
TotalReserves sdk.Coins `json:"total_reserves" yaml:"total_reserves"` // stores the running total of reserves when the chain starts, if any
}
```

View File

@ -7,24 +7,51 @@ order: 3
There are three messages in the hard module. Deposit allows users to deposit assets to the hard module. In version 2, depositors will be able to use their deposits as collateral to borrow from hard. Withdraw removes assets from the hard module, returning them to the user. Claim allows users to claim earned HARD tokens.
```go
// MsgDeposit deposit asset to the hard module.
// MsgDeposit deposit collateral to the hard module.
type MsgDeposit struct {
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
Amount sdk.Coin `json:"amount" yaml:"amount"`
}
// MsgWithdraw withdraw from the hard module.
type MsgWithdraw struct {
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
Amount sdk.Coin `json:"amount" yaml:"amount"`
}
// MsgClaimReward message type used to claim HARD tokens
type MsgClaimReward struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"`
DepositDenom string `json:"deposit_denom" yaml:"deposit_denom"`
RewardMultiplier string `json:"reward_multiplier" yaml:"reward_multiplier"`
DepositType string `json:"deposit_type" yaml:"deposit_type"`
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
}
```
This message creates a `Deposit` object if one does not exist, or updates an existing one, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. The `Amount` of coins is transferred from `Depositor` to the hard module account. The global variable for `TotalSupplied` is updated.
```go
// MsgWithdraw withdraw from the hard module.
type MsgWithdraw struct {
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
}
```
This message decrements a `Deposit` object, or deletes one if the `Amount` specified is greater than or equal to the total deposited amount, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. For example, a message which requests to withdraw 100xyz tokens, if `Depositor` has only deposited 50xyz tokens, will withdraw the full 50xyz tokens. The `Amount` of coins, or the current deposited amount, whichever is lower, is transferred from the hard module account to `Depositor`. The global variable for `TotalSupplied` is updated.
```go
// MsgBorrow borrows funds from the hard module.
type MsgBorrow struct {
Borrower sdk.AccAddress `json:"borrower" yaml:"borrower"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
}
```
This message creates a `Borrow` object is one does not exist, or updates an existing one, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. The `Amount` of coins is transferred from the hard module account to `Depositor`. The global variable for `TotalBorrowed` is updated.
```go
// MsgRepay repays funds to the hard module.
type MsgRepay struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
}
```
This message decrements a `Borrow` object, or deletes one if the `Amount` specified is greater than or equal to the total borrowed amount, as well as creating/updating the necessary indexes and synchronizing any outstanding interest. For example, a message which requests to repay 100xyz tokens, if `Sender` has only deposited 50xyz tokens, will repay the full 50xyz tokens. The `Amount` of coins, or the current borrow amount, is transferred from `Sender`. The global variable for `TotalBorrowed` is updated.
```go
// MsgLiquidate attempts to liquidate a borrower's borrow
type MsgLiquidate struct {
Keeper sdk.AccAddress `json:"keeper" yaml:"keeper"`
Borrower sdk.AccAddress `json:"borrower" yaml:"borrower"`
}
```
This message deletes `Borrower's` `Deposit` and `Borrow` objects if they are below the required LTV ratio. The keeper (the sender of the message) is rewarded a portion of the borrow position, according to the `KeeperReward` governance parameter. The coins from the `Deposit` are then sold at auction (see [auction module](../../auction/spec/README.md)), which any remaining tokens returned to `Borrower`. After being liquidated, `Borrower` no longer must repay the borrow amount. The global variables for `TotalSupplied` and `TotalBorrowed` are updated.

View File

@ -16,7 +16,6 @@ The hard module emits the following events:
| message | sender | `{sender address}` |
| hard_deposit | amount | `{amount}` |
| hard_deposit | depositor | `{depositor address}` |
| hard_deposit | deposit_denom | `{deposit denom}` |
### MsgWithdraw
@ -24,24 +23,26 @@ The hard module emits the following events:
| ------------------- | ------------- | --------------------- |
| message | module | hard |
| message | sender | `{sender address}` |
| hard_deposit | amount | `{amount}` |
| hard_deposit | depositor | `{depositor address}` |
| hard_deposit | deposit_denom | `{deposit denom}` |
| hard_deposit | deposit_type | `{deposit type}` |
| delete_hard_deposit | depositor | `{depositor address}` |
| delete_hard_deposit | deposit_denom | `{deposit denom}` |
| hard_withdrawal | amount | `{amount}` |
| hard_withdrawal | depositor | `{depositor address}` |
### MsgClaimReward
### MsgBorrow
| Type | Attribute Key | Attribute Value |
| ----------------- | ---------------- | ------------------------ |
| message | module | hard |
| message | sender | `{sender address}` |
| claim_hard_reward | amount | `{amount}` |
| claim_hard_reward | claim_holder | `{claim holder address}` |
| claim_hard_reward | deposit_denom | `{deposit denom}` |
| claim_hard_reward | claim_type | `{claim type}` |
| claim_hard_reward | claim_multiplier | `{claim multiplier}` |
| Type | Attribute Key | Attribute Value |
| -------------- | ------------- | --------------------- |
| message | module | hard |
| message | sender | `{sender address}` |
| hard_borrow | borrow_coins | `{amount}` |
| hard_withdrawal| borrower | `{borrower address}` |
### MsgRepay
| Type | Attribute Key | Attribute Value |
| -------------- | ------------- | --------------------- |
| message | module | hard |
| message | sender | `{sender address}` |
| hard_repay | repay_coins | `{amount}` |
| hard_repay | sender | `{borrower address}` |
## BeginBlock

View File

@ -6,41 +6,37 @@ order: 5
The hard module has the following parameters:
| Key | Type | Example | Description |
| ------------------------------ | ------------------------------------- | ------------- | -------------------------------------------- |
| Active | bool | "true" | boolean for if token distribution is active |
| LiquidityProviderSchedules | array (LiquidityProviderSchedule) | [{see below}] | array of params for each supported asset |
| DelegatorDistributionSchedules | array (DelegatorDistributionSchedule) | [{see below}] | array of params for staking incentive assets |
| Key | Type | Example | Description |
| ------------------------------ | ------------------------------------- | ------------- | ----------------------------------------------------------------------------|
| MoneyMarkets | array (MoneyMarket) | [{see below}] | array of params for each supported market |
| CheckLtvIndexCount | int | 6 | Number of borrow positions to check for liquidation in each begin blocker |
Each `LiquidityProviderSchedules` has the following parameters
Each `MoneyMarket` has the following parameters
| Key | Type | Example | Description |
| ---------------- | ------------------ | ---------------------- | ------------------------------------------------------------- |
| Active | bool | "true" | boolean for if token distribution is active for this schedule |
| DepositDenom | string | "bnb" | coin denom of the asset which can be deposited |
| Start | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
| End | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
| RewardsPerSecond | Coin | "500hard" | HARD tokens per second that can be claimed by depositors |
| ClaimEnd | time.Time | "2022-06-01T15:20:00Z" | the time at which users can no longer claim HARD tokens |
| ClaimMultipliers | array (Multiplier) | [{see below}] | reward multipliers for users claiming HARD tokens |
| Key | Type | Example | Description |
| ------------------------- | ------------------ | ---------------------- | --------------------------------------------------------------------- |
| Denom | string | "bnb" | coin denom of the asset which can be deposited and borrowed |
| BorrowLimit | BorrowLimit | [{see below}] | borrow limits applied to this money market |
| SpotMarketID | string | "bnb:usd" | the market id which determines the price of the asset |
| ConversionFactor | Int | "6" | conversion factor for one unit (ie BNB) to the smallest internal unit |
| InterestRateModel | InterestRateModel | [{see below}] | Model which determines the prevailing interest rate per block |
| ReserveFactor | Dec | "0.01" | Percentage of interest that is kept as protocol reserves |
| AuctionSize | Int | "1000000000" | The maximum size of an individual auction |
| KeeperRewardPercentage | Dec | "0.02" | Percentage of deposit rewarded to keeper who liquidates a position |
Each `DelegatorDistributionSchedule` has the following parameters
Each `BorrowLimit` has the following parameters
| Key | Type | Example | Description |
| --------------------- | ------------------ | ---------------------- | ------------------------------------------------------------- |
| Active | bool | "true" | boolean for if token distribution is active for this schedule |
| DepositDenom | string | "bnb" | coin denom of the asset which can be deposited |
| Start | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
| End | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
| RewardsPerSecond | Coin | "500hard" | HARD tokens per second that can be claimed by depositors |
| ClaimEnd | time.Time | "2022-06-01T15:20:00Z" | the time at which users can no longer claim HARD tokens |
| ClaimMultipliers | array (Multiplier) | [{see below}] | reward multipliers for users claiming HARD tokens |
| DistributionFrequency | time.Duration | "24hr" | frequency at which delegation rewards are accumulated |
| Key | Type | Example | Description |
| --------------------- | ------------------ | ---------------------- | ------------------------------------------------------------------------ |
| HasMaxLimit | bool | "true" | boolean for if a maximum limit is in effect |
| MaximumLimit | Dec | "10000000.0" | global maximum amount of coins that can be borrowed |
| LoanToValue | Dec | "0.5" | the percentage amount of borrow power each unit of deposit accounts for |
Each `ClaimMultiplier` has the following parameters
Each `InterestRateModel` has the following parameters
| Key | Type | Example | Description |
| ------------ | ------ | ------- | --------------------------------------------------------------- |
| Name | string | "large" | the unique name of the reward multiplier |
| MonthsLockup | int | "6" | number of months HARD tokens with this multiplier are locked |
| Factor | Dec | "0.5" | the scaling factor for HARD tokens claimed with this multiplier |
| Key | Type | Example | Description |
| ---------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------- |
| BaseRateAPY | Dec | "0.0" | the base rate of APY interest when borrows are zero. |
| BaseMultiplier | Dec | "0.01" | the percentage rate at which the interest rate APY increases for each percentage increase in borrow utilization. |
| Kink | Dec | "0.5" | the inflection point of utilization at which the BaseMultiplier no longer applies and the JumpMultiplier does. |
| JumpMultiplier | Dec | "0.5" | same as BaseMultiplier, but only applied when utilization is above the Kink |

View File

@ -4,16 +4,12 @@ order: 6
# Begin Block
At the start of each block, hard tokens are distributed (as claims) to liquidity providers and delegators, respectively.
At the start of each block, interest is accumulated, and automated liquidations are attempted
```go
// BeginBlocker applies rewards to liquidity providers and delegators according to params
// BeginBlocker updates interest rates and attempts liquidations
func BeginBlocker(ctx sdk.Context, k Keeper) {
k.ApplyDepositRewards(ctx)
if k.ShouldDistributeValidatorRewards(ctx, k.BondDenom(ctx)) {
k.ApplyDelegationRewards(ctx, k.BondDenom(ctx))
k.SetPreviousDelegationDistribution(ctx, ctx.BlockTime(), k.BondDenom(ctx))
}
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
k.ApplyInterestRateUpdates(ctx)
k.AttemptIndexLiquidations(ctx)
}
```

View File

@ -18,4 +18,4 @@ parent:
## Abstract
`x/hard` is an implementation of a Cosmos SDK Module that will serve as the basis for a cross-chain money market platform. The current version of the module defines how HARD tokens are distributed, while future versions of this module will define lending, borrowing, distribution, incentives, and governance for the money market module.
`x/hard` is an implementation of a Cosmos SDK Module that provides for functionality and governance of a two-sided, cross-chain, money market protocol.

View File

@ -4,6 +4,23 @@ order: 1
# Concepts
This module presents an implementation of user incentives that are controlled by governance. When users take a certain action, in this case opening a CDP, they become eligible for rewards. Rewards are __opt in__ meaning that users must submit a message before the claim deadline to claim their rewards. The goals and background of this module were subject of a previous Kava governance proposal, which can be found [here](https://ipfs.io/ipfs/QmSYedssC3nyQacDJmNcREtgmTPyaMx2JX7RNkMdAVkdkr/user-growth-fund-proposal.pdf).
This module presents an implementation of user incentives that are controlled by governance. When users take a certain action, for example opening a CDP, they become eligible for rewards. Rewards are __opt in__ meaning that users must submit a message before the claim deadline to claim their rewards. The goals and background of this module were subject of a previous Kava governance proposal, which can be found [here](https://ipfs.io/ipfs/QmSYedssC3nyQacDJmNcREtgmTPyaMx2JX7RNkMdAVkdkr/user-growth-fund-proposal.pdf)
When governance adds a collateral type to be eligible for rewards, they set the rate (coins/time) at which rewards are given to users, the length of each reward period, the length of each claim period, and the amount of time reward coins must vest before users who claim them can transfer them. For the duration of a reward period, any user that has minted USDX using an eligible collateral type will ratably accumulate rewards in a `Claim` object. For example, if a user has minted 10% of all USDX for the duration of the reward period, they will earn 10% of all rewards for that period. When the reward period ends, the claim period begins immediately, at which point users can submit a message to claim their rewards. Rewards are time-locked, meaning that when a user claims rewards they will receive them as a vesting balance on their account. Vesting balances can be used to stake coins, but cannot be transferred until the vesting period ends. In addition to vesting, rewards can have multipliers that vary the number of tokens received. For example, a reward with a vesting period of 1 month may have a multiplier of 0.25, meaning that the user will receive 25% of the reward balance if they choose that vesting schedule.
## HARD Token distribution
The incentive module also distributes the HARD token on the Kava blockchain. HARD tokens are distributed to two types of ecosystem participants:
1. Kava stakers - any address that stakes (delegates) KAVA tokens will be eligible to claim HARD tokens. For each delegator, HARD tokens are accumulated ratably based on the total number of kava tokens staked. For example, if a user stakes 1 million KAVA tokens and there are 100 million staked KAVA, that user will accumulate 1% of HARD tokens earmarked for stakers during the distribution period. Distribution periods are defined by a start date, an end date, and a number of HARD tokens that are distributed per second.
2. Depositors/Borrows - any address that deposits and/or borrows eligible tokens to the hard module will be eligible to claim HARD tokens. For each depositor, HARD tokens are accumulated ratably based on the total number of tokens staked of that denomination. For example, if a user deposits 1 million "xyz" tokens and there are 100 million xyz deposited, that user will accumulate 1% of HARD tokens earmarked for depositors of that denomination during the distribution period. Distribution periods are defined by a start date, an end date, and a number of HARD tokens that are distributed per second.
Users are not air-dropped tokens, rather they accumulate `Claim` objects that they may submit a transaction in order to claim. In order to better align long term incentives, when users claim HARD tokens, they have three options, called 'multipliers', for how tokens are distributed.
The exact multipliers will be voted by governance and can be changed via a governance vote. An example multiplier schedule would be:
- Liquid - 10% multiplier and no lock up. Users receive 10% as many tokens as users who choose long-term locked tokens.
- Medium-term locked - 33% multiplier and 6 month transfer restriction. Users receive 33% as many tokens as users who choose long-term locked tokens.
- Long-term locked - 100% multiplier and 2 year transfer restriction. Users receive 10x as many tokens as users who choose liquid tokens and 3x as many tokens as users who choose medium-term locked tokens.
## USDX Minting Rewards
The incentive module is responsible for distribution of KAVA tokens to users who mint USDX. When governance adds a collateral type to be eligible for rewards, they set the rate (coins/second) at which rewards are given to users, the length of each reward period, the length of each claim period, and the amount of time reward coins must vest before users who claim them can transfer them. For the duration of a reward period, any user that has minted USDX using an eligible collateral type will ratably accumulate rewards in a `USDXMintingClaim` object. For example, if a user has minted 10% of all USDX for the duration of the reward period, they will earn 10% of all rewards for that period. When the reward period ends, the claim period begins immediately, at which point users can submit a message to claim their rewards. Rewards are time-locked, meaning that when a user claims rewards they will receive them as a vesting balance on their account. Vesting balances can be used to stake coins, but cannot be transferred until the vesting period ends. In addition to vesting, rewards can have multipliers that vary the number of tokens received. For example, a reward with a vesting period of 1 month may have a multiplier of 0.25, meaning that the user will receive 25% of the reward balance if they choose that vesting schedule.

View File

@ -6,24 +6,45 @@ order: 2
## Parameters and Genesis State
`Parameters` define the collateral types which are eligible for rewards, the rate at which rewards are given to users, and the amount of time rewards must vest before users can transfer them.
`Parameters` define the types of incentives that are available and the rewards that are available for each incentive.
```go
// Params governance parameters for the incentive module
type Params struct {
Active bool `json:"active" yaml:"active"` // top level governance switch to disable all rewards
Rewards Rewards `json:"rewards" yaml:"rewards"`
USDXMintingRewardPeriods RewardPeriods `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"` // rewards for minting USDX
HardSupplyRewardPeriods MultiRewardPeriods `json:"hard_supply_reward_periods" yaml:"hard_supply_reward_periods"` // rewards for hard supply
HardBorrowRewardPeriods MultiRewardPeriods `json:"hard_borrow_reward_periods" yaml:"hard_borrow_reward_periods"` // rewards for hard borrow
HardDelegatorRewardPeriods RewardPeriods `json:"hard_delegator_reward_periods" yaml:"hard_delegator_reward_periods"` // rewards for kava delegators
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the available claim multipliers that determine who much rewards are paid out and how long rewards are locked for
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"` // the time at which claims expire
}
// Reward stores the specified state for a single reward period.
// Reward stores the specified state for a single reward period.
type Reward struct {
Active bool `json:"active" yaml:"active"` // governance switch to disable a period
CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type rewards apply to, must be found in the cdp collaterals
AvailableRewards sdk.Coin `json:"available_rewards" yaml:"available_rewards"` // the total amount of coins distributed per period
Duration time.Duration `json:"duration" yaml:"duration"` // the duration of the period
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards
ClaimDuration time.Duration `json:"claim_duration" yaml:"claim_duration"` // how long users have after the period ends to claim their rewards
```
Each `RewardPeriod` defines a particular collateral for which rewards are eligible and the amount of rewards available.
```go
// RewardPeriod stores the state of an ongoing reward
type RewardPeriod struct {
Active bool `json:"active" yaml:"active"` // if the reward is active
CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type for which rewards apply
Start time.Time `json:"start" yaml:"start"` // when the rewards start
End time.Time `json:"end" yaml:"end"` // when the rewards end
RewardsPerSecond sdk.Coin `json:"rewards_per_second" yaml:"rewards_per_second"` // per second reward payouts
}
```
Each `MultiRewardPeriod` defines a particular collateral for which one or more reward tokens are eligible and the amount of rewards available
```go
// MultiRewardPeriod supports multiple reward types
type MultiRewardPeriod struct {
Active bool `json:"active" yaml:"active"`
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
Start time.Time `json:"start" yaml:"start"`
End time.Time `json:"end" yaml:"end"`
RewardsPerSecond sdk.Coins `json:"rewards_per_second" yaml:"rewards_per_second"` // per second reward payouts
}
```
@ -32,12 +53,13 @@ type Reward struct {
```go
// GenesisState is the state that must be provided at genesis.
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
RewardPeriods RewardPeriods `json:"reward_periods" yaml:"reward_periods"`
ClaimPeriods ClaimPeriods `json:"claim_periods" yaml:"claim_periods"`
Claims Claims `json:"claims" yaml:"claims"`
NextClaimPeriodIDs GenesisClaimPeriodIDs `json:"next_claim_period_ids" yaml:"next_claim_period_ids"`
Params Params `json:"params" yaml:"params"` // governance parameters
USDXAccumulationTimes GenesisAccumulationTimes `json:"usdx_accumulation_times" yaml:"usdx_accumulation_times"` // when USDX rewards were last accumulated
HardSupplyAccumulationTimes GenesisAccumulationTimes `json:"hard_supply_accumulation_times" yaml:"hard_supply_accumulation_times"` // when hard supply rewards were last accumulated
HardBorrowAccumulationTimes GenesisAccumulationTimes `json:"hard_borrow_accumulation_times" yaml:"hard_borrow_accumulation_times"` // when hard borrow rewards were last accumulated
HardDelegatorAccumulationTimes GenesisAccumulationTimes `json:"hard_delegator_accumulation_times" yaml:"hard_delegator_accumulation_times"` // when hard delegator rewards were last accumulated
USDXMintingClaims USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` // USDX minting claims at genesis, if any
HardLiquidityProviderClaims HardLiquidityProviderClaims `json:"hard_liquidity_provider_claims" yaml:"hard_liquidity_provider_claims"` // Hard liquidity provider claims at genesis, if any
}
```
@ -45,18 +67,35 @@ type GenesisState struct {
For complete details for how items are stored, see [keys.go](../types/keys.go).
### Reward Period Creation
### Claim Creation
At genesis, or when a collateral is added to rewards, a `RewardPeriod` is created in the store by adding to the existing array of `[]RewardPeriod`. If the previous period for that collateral expired, it is deleted. This implies that, for each collateral, there will only ever be one reward period.
When users take incentivized actions, the `incentive` module will create or update a `Claim` object in the store, which represents the amount of rewards that the user is eligible to claim. The two defined claim objects are `USDXMintingClaims` and `HardLiquidityProviderClaims`:
### Reward Period Deletion
```go
When a `RewardPeriod` expires, a new `ClaimPeriod` is created in the store with the next sequential ID for that collateral (ie, if the previous claim period was ID 1, the next one will be ID 2) and the current `RewardPeriod` is deleted from the array of `[]RewardPeriod`.
// BaseClaim is a common type shared by all Claims
type BaseClaim struct {
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
Reward sdk.Coin `json:"reward" yaml:"reward"`
}
### Reward Claim Creation
// BaseMultiClaim is a common type shared by all Claims with multiple reward denoms
type BaseMultiClaim struct {
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
Reward sdk.Coins `json:"reward" yaml:"reward"`
}
Every block, CDPs are iterated over and the collateral denom is checked for rewards eligibility. For eligible CDPs, a `Claim` is created in the store for all CDP owners, if one doesn't already exist. The claim object is associated with a `ClaimPeriod` via the ID. This implies that a `Claim` is created before `ClaimPeriod` are created. Therefore, a user who submits a `MsgClaimReward` will only be paid out IF 1) they have one or more active `Claim` objects, and 2) the `ClaimPeriod` with the associated ID for that object exists AND the current block time is between the start time and end time for that `ClaimPeriod`.
// USDXMintingClaim is for USDX minting rewards
type USDXMintingClaim struct {
BaseClaim `json:"base_claim" yaml:"base_claim"` // Base claim object
RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` // indexes which are used to calculate the amount of rewards a user can claim
}
### Reward Claim Deletion
For claimed rewards, the `Claim` is deleted from the store by deleting the key associated with that denom, ID, and owner. Unclaimed rewards are handled as follows: Each block, the `ClaimPeriod` objects for each denom are iterated over and checked for expiry. If expired, all `Claim` objects for that ID are deleted, as well as the `ClaimPeriod` object. Since claim periods are monotonically increasing, once a non-expired claim period is reached, the iteration can be stopped.
// HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
type HardLiquidityProviderClaim struct {
BaseMultiClaim `json:"base_claim" yaml:"base_claim"` // base claim object
SupplyRewardIndexes MultiRewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"` // indexes which are used to calculate the amount of hard supply rewards a user can claim
BorrowRewardIndexes MultiRewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"` // indexes which are used to calculate the amount of hard borrow rewards a user can claim
DelegatorRewardIndexes RewardIndexes `json:"delegator_reward_indexes" yaml:"delegator_reward_indexes"` // indexes which are used to calculate the amount of hard delegator rewards a user can claim
}
```

View File

@ -4,13 +4,18 @@ order: 3
# Messages
Users claim rewards using a `MsgClaimReward`.
Users claim rewards using `MsgClaimUSDXMintingReward` and `MsgClaimHardLiquidityProviderReward` messages.
```go
// MsgClaimReward message type used to claim rewards
type MsgClaimReward struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
// MsgClaimUSDXMintingReward message type used to claim USDX minting rewards
type MsgClaimUSDXMintingReward struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
}
// MsgClaimHardLiquidityProviderReward message type used to claim Hard liquidity provider rewards
type MsgClaimHardLiquidityProviderReward struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
}
```
@ -19,4 +24,4 @@ type MsgClaimReward struct {
* Accumulated rewards for active claims are transferred from the `kavadist` module account to the users account as vesting coins
* The number of coins transferred is determined by the multiplier in the message. For example, the multiplier equals 1.0, 100% of the claim's reward value is transferred. If the multiplier equals 0.5, 50% of the claim's reward value is transferred.
* The corresponding claim object(s) are deleted from the store
* The corresponding claim object is reset to zero in the store

View File

@ -6,19 +6,22 @@ order: 4
The `x/incentive` module emits the following events:
## MsgClaimReward
## ClaimUSDXMintingReward
| Type | Attribute Key | Attribute Value |
|----------------------|---------------------|----------------------|
| claim_reward | claimed_by | `{claiming address}' |
| claim_reward | claim_amount | `{amount claimed}' |
| message | module | incentive |
| message | sender | `{sender address}' |
| Type | Attribute Key | Attribute Value |
|----------------------|---------------------|---------------------------|
| claim_reward | claimed_by | `{claiming address}' |
| claim_reward | claim_amount | `{amount claimed}' |
| claim_reward | claim_type | `{amount claimed}' |
| message | module | incentive |
| message | sender | hard_liquidity_provider |
## BeginBlock
## MsgClaimHardLiquidityProviderReward
| Type | Attribute Key | Attribute Value |
|----------------------|---------------------|----------------------|
| new_claim_period | claim_period | `{claim period}' |
| new_reward_period | reward_period | `{reward period}' |
| claim_period_expiry | claim_period | `{claim period}' |
| Type | Attribute Key | Attribute Value |
|----------------------|---------------------|---------------------------|
| claim_reward | claimed_by | `{claiming address}' |
| claim_reward | claim_amount | `{amount claimed}' |
| claim_reward | claim_type | `{amount claimed}' |
| message | module | incentive |
| message | sender | usdx_minting |

View File

@ -6,26 +6,40 @@ order: 5
The incentive module contains the following parameters:
| Key | Type | Example | Description |
|------------|----------------|---------------|--------------------------------------------------|
| Active | bool | "true" | boolean for if this module is active |
| Rewards | array (Reward) | [{see below}] | array of params for each inflationary period |
| Key | Type | Example | Description |
|----------------------------|--------------------|------------------------|--------------------------------------------------|
| USDXMintingRewardPeriods | RewardPeriods | [{see below}] | USDX minting reward periods |
| HardSupplyRewardPeriods | MultiRewardPeriods | [{see below}] | Hard supply reward periods |
| HardBorrowRewardPeriods | MultiRewardPeriods | [{see below}] | Hard borrow reward periods |
| HardDelegatorRewardPeriods | RewardPeriods | [{see below}] | Hard delegator reward periods |
| ClaimMultipliers | Multipliers | [{see below}] | Multipliers applied when rewards are claimed |
| ClaimMultipliers | Time | "2025-12-02T14:00:00Z" | Time when reward claiming ends |
Each `Reward` has the following parameters
| Key | Type | Example | Description |
|------------------|--------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------|
| Active | bool | "true | boolean for if rewards for this collateral are active |
| Denom | string | "bnb" | the collateral for which rewards are eligible |
| AvailableRewards | object (coin) | `{"denom":"kava","amount":"1000"}` | the rewards available per reward period |
| Duration | string (time ns) | "172800000000000" | the duration of each reward period |
| ClaimMultipliers | array (Multiplier) | [{see below}] | the number of months for which claimed rewards will be vesting and the multiplier applied when rewards are claimed|
| ClaimDuration | string (time ns) | "172800000000000" | how long users have to claim rewards before they expire |
Each `RewardPeriod` has the following parameters
| Key | Type | Example | Description |
|------------------|--------------------|------------------------------------|------------------------------------------------------------------|
| Active | bool | "true | boolean for if rewards for this collateral are active |
| CollateralType | string | "bnb-a" | the collateral for which rewards are eligible |
| Start | Time | "2020-12-02T14:00:00Z" | the time at which rewards start |
| End | Time | "2023-12-02T14:00:00Z" | the time at which rewards end |
| AvailableRewards | object (coin) | `{"denom":"hard","amount":"1000"}` | the rewards available per reward period |
Each `MultiRewardPeriod` has the following parameters
| Key | Type | Example | Description |
|------------------|--------------------|-------------------------------------------------------------------------|------------------------------------------------------------------|
| Active | bool | "true | boolean for if rewards for this collateral are active |
| CollateralType | string | "bnb-a" | the collateral for which rewards are eligible |
| Start | Time | "2020-12-02T14:00:00Z" | the time at which rewards start |
| End | Time | "2023-12-02T14:00:00Z" | the time at which rewards end |
| AvailableRewards | array (coins) | `[{"denom":"hard","amount":"1000"}, {"denom":"ukava","amount":"1000"}]` | the rewards available per reward period |
Each `Multiplier` has the following parameters:
| Key | Type | Example | Description |
|-----------------------|--------------------|--------------------------|-----------------------------------------------------------------|
| Name | string | "large" | the unique name of the reward multiplier |
| MonthsLockup | int | "6" | number of months HARD tokens with this multiplier are locked |
| Factor | Dec | "0.5" | the scaling factor for HARD tokens claimed with this multiplier |
| MonthsLockup | int | "6" | number of months tokens with this multiplier are locked |
| Factor | Dec | "0.5" | the scaling factor for tokens claimed with this multiplier |

View File

@ -1,15 +0,0 @@
<!--
order: 6
-->
# Begin Block
At the start of each block, expired claims and claim periods are deleted, rewards are applied to CDPs for any ongoing reward periods, expired reward periods are deleted and replaced with a new reward period (if active), and claim periods are created for expiring reward periods. The logic is as follows:
```go
func BeginBlocker(ctx sdk.Context, k Keeper) {
k.DeleteExpiredClaimsAndClaimPeriods(ctx)
k.ApplyRewardsToCdps(ctx)
k.CreateAndDeleteRewardPeriods(ctx)
}
```

View File

@ -0,0 +1,112 @@
<!--
order: 6
-->
# Hooks
This module implements the `Hooks` interface for the following modules:
* cdp
* hard
* staking (defined in cosmos-sdk)
CDP module hooks manage the creation and synchronization of USDX minting incentives.
```go
// ------------------- Cdp Module Hooks -------------------
// AfterCDPCreated function that runs after a cdp is created
func (h Hooks) AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP) {
h.k.InitializeUSDXMintingClaim(ctx, cdp)
}
// BeforeCDPModified function that runs before a cdp is modified
// note that this is called immediately after interest is synchronized, and so could potentially
// be called AfterCDPInterestUpdated or something like that, if we we're to expand the scope of cdp hooks
func (h Hooks) BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) {
h.k.SynchronizeUSDXMintingReward(ctx, cdp)
}
```
Hard module hooks manage the creation and synchronization of hard supply and borrow rewards.
```go
// ------------------- Hard Module Hooks -------------------
// AfterDepositCreated function that runs after a deposit is created
func (h Hooks) AfterDepositCreated(ctx sdk.Context, deposit hardtypes.Deposit) {
h.k.InitializeHardSupplyReward(ctx, deposit)
}
// BeforeDepositModified function that runs before a deposit is modified
func (h Hooks) BeforeDepositModified(ctx sdk.Context, deposit hardtypes.Deposit) {
h.k.SynchronizeHardSupplyReward(ctx, deposit)
}
// AfterDepositModified function that runs after a deposit is modified
func (h Hooks) AfterDepositModified(ctx sdk.Context, deposit hardtypes.Deposit) {
h.k.UpdateHardSupplyIndexDenoms(ctx, deposit)
}
// AfterBorrowCreated function that runs after a borrow is created
func (h Hooks) AfterBorrowCreated(ctx sdk.Context, borrow hardtypes.Borrow) {
h.k.InitializeHardBorrowReward(ctx, borrow)
}
// BeforeBorrowModified function that runs before a borrow is modified
func (h Hooks) BeforeBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
h.k.SynchronizeHardBorrowReward(ctx, borrow)
}
// AfterBorrowModified function that runs after a borrow is modified
func (h Hooks) AfterBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
h.k.UpdateHardBorrowIndexDenoms(ctx, borrow)
}
```
Staking module hooks manage the creation and synchronization of hard delegator rewards.
```go
// ------------------- Staking Module Hooks -------------------
// BeforeDelegationCreated runs before a delegation is created
func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.k.InitializeHardDelegatorReward(ctx, delAddr)
}
// BeforeDelegationSharesModified runs before an existing delegation is modified
func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.k.SynchronizeHardDelegatorRewards(ctx, delAddr)
}
// NOTE: following hooks are just implemented to ensure StakingHooks interface compliance
// BeforeValidatorSlashed is called before a validator is slashed
func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {}
// AfterValidatorBeginUnbonding is called after a validator begins unbonding
func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
}
// AfterValidatorBonded is called after a validator is bonded
func (h Hooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
}
// AfterDelegationModified runs after a delegation is modified
func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
}
// BeforeDelegationRemoved runs directly before a delegation is deleted
func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
}
// AfterValidatorCreated runs after a validator is created
func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
// BeforeValidatorModified runs before a validator is modified
func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
// AfterValidatorRemoved runs after a validator is removed
func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
}
```

View File

@ -0,0 +1,38 @@
<!--
order: 7
-->
# Begin Block
At the start of each block, rewards are accumulated for each reward time. Accumulation refers to computing the total amount of rewards that have accumulated since the previous block and updating a global accumulator value such that whenever a `Claim` object is accessed, it is synchronized with the latest global state. This ensures that all rewards are accurately accounted for without having to iterate over each claim object in the begin blocker
```go
// BeginBlocker runs at the start of every block
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
params := k.GetParams(ctx)
for _, rp := range params.USDXMintingRewardPeriods {
err := k.AccumulateUSDXMintingRewards(ctx, rp)
if err != nil {
panic(err)
}
}
for _, rp := range params.HardSupplyRewardPeriods {
err := k.AccumulateHardSupplyRewards(ctx, rp)
if err != nil {
panic(err)
}
}
for _, rp := range params.HardBorrowRewardPeriods {
err := k.AccumulateHardBorrowRewards(ctx, rp)
if err != nil {
panic(err)
}
}
for _, rp := range params.HardDelegatorRewardPeriods {
err := k.AccumulateHardDelegatorRewards(ctx, rp)
if err != nil {
panic(err)
}
}
}
```

View File

@ -13,12 +13,13 @@ parent:
3. **[Messages](03_messages.md)**
4. **[Events](04_events.md)**
5. **[Params](05_params.md)**
6. **[BeginBlock](06_begin_block.md)**
6. **[Hooks](06_hooks.md)**
7. **[BeginBlock](07_begin_block.md)**
## Abstract
`x/incentive` is an implementation of a Cosmos SDK Module that allows for governance controlled user incentives for users who create stable assets by opening a collateralized debt position (CDP). Governance proposes an array of collateral rewards, with each item representing a collateral type that will be eligible for rewards. Each collateral reward specifies the number of coins awarded per period, the length of rewards periods, the length of claim periods. Governance can alter the collateral rewards using parameter change proposals as well as adding or removing collateral types. All changes to parameters would take place in the _next_ period.
`x/incentive` is an implementation of a Cosmos SDK Module that allows for governance controlled user incentives for users who take certain actions, such as opening a collateralized debt position (CDP). Governance proposes an array of rewards, with each item representing a collateral type that will be eligible for rewards. Each collateral reward specifies the number of coins awarded per second, the length of rewards periods, and the length of claim periods. Governance can alter the collateral rewards using parameter change proposals as well as adding or removing collateral types. All changes to parameters would take place in the _next_ period. User rewards are __opt in__, ie. users must claim rewards in order to receive them. If users fail to claim rewards before the claim period expiry, they are no longer eligible for rewards.
### Dependencies
This module depends on `x/cdp` for users to be able to create CDPs and on `x/kavadist`, which controls the module account from where rewards are spent. In the event that the module account is not funded, user's attempt to claim rewards will fail.
This module uses hooks to update user rewards. Currently, `incentive` implements hooks from the `cdp`, `hard`, and `staking` (comsos-sdk) modules. All rewards are paid out from the `kavadist` module account.