mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
Add hard and incentive spec updates (#817)
* wip: update hard spec * feat: updated hard spec * feat: updated incentive spec
This commit is contained in:
parent
bdbc9b9c58
commit
c5fc1c6b4f
@ -4,19 +4,11 @@ order: 1
|
|||||||
|
|
||||||
# Concepts
|
# 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.
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
[See Incentive Module](../../incentive/spec/01_concepts.md)
|
||||||
- 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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
@ -6,47 +6,57 @@ order: 2
|
|||||||
|
|
||||||
## Parameters and Genesis State
|
## 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
|
```go
|
||||||
// Params governance parameters for hard module
|
// Params governance parameters for hard module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Active bool `json:"active" yaml:"active"`
|
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"` // defines the parameters for each money market
|
||||||
LiquidityProviderSchedules DistributionSchedules `json:"liquidity_provider_schedules" yaml:"liquidity_provider_schedules"`
|
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
|
||||||
DelegatorDistributionSchedules DelegatorDistributionSchedules `json:"delegator_distribution_schedules" yaml:"delegator_distribution_schedules"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DistributionSchedule distribution schedule for liquidity providers
|
// MoneyMarket is a money market for an individual asset
|
||||||
type DistributionSchedule struct {
|
type MoneyMarket struct {
|
||||||
Active bool `json:"active" yaml:"active"`
|
Denom string `json:"denom" yaml:"denom"` // the denomination of the token for this money market
|
||||||
DepositDenom string `json:"deposit_denom" yaml:"deposit_denom"`
|
BorrowLimit BorrowLimit `json:"borrow_limit" yaml:"borrow_limit"` // the borrow limits, if any, applied to this money market
|
||||||
Start time.Time `json:"start" yaml:"start"`
|
SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // the pricefeed market where price data is fetched
|
||||||
End time.Time `json:"end" yaml:"end"`
|
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)
|
||||||
RewardsPerSecond sdk.Coin `json:"rewards_per_second" yaml:"rewards_per_second"`
|
InterestRateModel InterestRateModel `json:"interest_rate_model" yaml:"interest_rate_model"` // the model that determines the prevailing interest rate at each block
|
||||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
ReserveFactor sdk.Dec `json:"reserve_factor" yaml:"reserve_factor"` // the percentage of interest that is accumulated by the protocol as reserves
|
||||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"`
|
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
|
// MoneyMarkets slice of MoneyMarket
|
||||||
type DistributionSchedules []DistributionSchedule
|
type MoneyMarkets []MoneyMarket
|
||||||
|
|
||||||
// DelegatorDistributionSchedule distribution schedule for delegators
|
// InterestRateModel contains information about an asset's interest rate
|
||||||
type DelegatorDistributionSchedule struct {
|
type InterestRateModel struct {
|
||||||
DistributionSchedule DistributionSchedule `json:"distribution_schedule" yaml:"distribution_schedule"`
|
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.
|
||||||
DistributionFrequency time.Duration `json:"distribution_frequency" yaml:"distribution_frequency"`
|
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
|
// BorrowLimit enforces restrictions on a money market
|
||||||
type DelegatorDistributionSchedules []DelegatorDistributionSchedule
|
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
|
```go
|
||||||
// GenesisState is the state that must be provided at genesis.
|
// GenesisState is the state that must be provided at genesis.
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Params Params `json:"params" yaml:"params"`
|
Params Params `json:"params" yaml:"params"` // governance parameters
|
||||||
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
|
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
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -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.
|
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
|
```go
|
||||||
// MsgDeposit deposit asset to the hard module.
|
// MsgDeposit deposit collateral to the hard module.
|
||||||
type MsgDeposit struct {
|
type MsgDeposit struct {
|
||||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
|
||||||
Amount sdk.Coin `json:"amount" yaml:"amount"`
|
Amount sdk.Coins `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"`
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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.
|
@ -16,7 +16,6 @@ The hard module emits the following events:
|
|||||||
| message | sender | `{sender address}` |
|
| message | sender | `{sender address}` |
|
||||||
| hard_deposit | amount | `{amount}` |
|
| hard_deposit | amount | `{amount}` |
|
||||||
| hard_deposit | depositor | `{depositor address}` |
|
| hard_deposit | depositor | `{depositor address}` |
|
||||||
| hard_deposit | deposit_denom | `{deposit denom}` |
|
|
||||||
|
|
||||||
### MsgWithdraw
|
### MsgWithdraw
|
||||||
|
|
||||||
@ -24,24 +23,26 @@ The hard module emits the following events:
|
|||||||
| ------------------- | ------------- | --------------------- |
|
| ------------------- | ------------- | --------------------- |
|
||||||
| message | module | hard |
|
| message | module | hard |
|
||||||
| message | sender | `{sender address}` |
|
| message | sender | `{sender address}` |
|
||||||
| hard_deposit | amount | `{amount}` |
|
| hard_withdrawal | amount | `{amount}` |
|
||||||
| hard_deposit | depositor | `{depositor address}` |
|
| hard_withdrawal | 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}` |
|
|
||||||
|
|
||||||
### MsgClaimReward
|
### MsgBorrow
|
||||||
|
|
||||||
| Type | Attribute Key | Attribute Value |
|
| Type | Attribute Key | Attribute Value |
|
||||||
| ----------------- | ---------------- | ------------------------ |
|
| -------------- | ------------- | --------------------- |
|
||||||
| message | module | hard |
|
| message | module | hard |
|
||||||
| message | sender | `{sender address}` |
|
| message | sender | `{sender address}` |
|
||||||
| claim_hard_reward | amount | `{amount}` |
|
| hard_borrow | borrow_coins | `{amount}` |
|
||||||
| claim_hard_reward | claim_holder | `{claim holder address}` |
|
| hard_withdrawal| borrower | `{borrower address}` |
|
||||||
| claim_hard_reward | deposit_denom | `{deposit denom}` |
|
|
||||||
| claim_hard_reward | claim_type | `{claim type}` |
|
### MsgRepay
|
||||||
| claim_hard_reward | claim_multiplier | `{claim multiplier}` |
|
|
||||||
|
| Type | Attribute Key | Attribute Value |
|
||||||
|
| -------------- | ------------- | --------------------- |
|
||||||
|
| message | module | hard |
|
||||||
|
| message | sender | `{sender address}` |
|
||||||
|
| hard_repay | repay_coins | `{amount}` |
|
||||||
|
| hard_repay | sender | `{borrower address}` |
|
||||||
|
|
||||||
## BeginBlock
|
## BeginBlock
|
||||||
|
|
||||||
|
@ -6,41 +6,37 @@ order: 5
|
|||||||
|
|
||||||
The hard module has the following parameters:
|
The hard module has the following parameters:
|
||||||
|
|
||||||
| Key | Type | Example | Description |
|
| Key | Type | Example | Description |
|
||||||
| ------------------------------ | ------------------------------------- | ------------- | -------------------------------------------- |
|
| ------------------------------ | ------------------------------------- | ------------- | ----------------------------------------------------------------------------|
|
||||||
| Active | bool | "true" | boolean for if token distribution is active |
|
| MoneyMarkets | array (MoneyMarket) | [{see below}] | array of params for each supported market |
|
||||||
| LiquidityProviderSchedules | array (LiquidityProviderSchedule) | [{see below}] | array of params for each supported asset |
|
| CheckLtvIndexCount | int | 6 | Number of borrow positions to check for liquidation in each begin blocker |
|
||||||
| DelegatorDistributionSchedules | array (DelegatorDistributionSchedule) | [{see below}] | array of params for staking incentive assets |
|
|
||||||
|
|
||||||
Each `LiquidityProviderSchedules` has the following parameters
|
Each `MoneyMarket` has the following parameters
|
||||||
|
|
||||||
| Key | Type | Example | Description |
|
| Key | Type | Example | Description |
|
||||||
| ---------------- | ------------------ | ---------------------- | ------------------------------------------------------------- |
|
| ------------------------- | ------------------ | ---------------------- | --------------------------------------------------------------------- |
|
||||||
| Active | bool | "true" | boolean for if token distribution is active for this schedule |
|
| Denom | string | "bnb" | coin denom of the asset which can be deposited and borrowed |
|
||||||
| DepositDenom | string | "bnb" | coin denom of the asset which can be deposited |
|
| BorrowLimit | BorrowLimit | [{see below}] | borrow limits applied to this money market |
|
||||||
| Start | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
|
| SpotMarketID | string | "bnb:usd" | the market id which determines the price of the asset |
|
||||||
| End | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
|
| ConversionFactor | Int | "6" | conversion factor for one unit (ie BNB) to the smallest internal unit |
|
||||||
| RewardsPerSecond | Coin | "500hard" | HARD tokens per second that can be claimed by depositors |
|
| InterestRateModel | InterestRateModel | [{see below}] | Model which determines the prevailing interest rate per block |
|
||||||
| ClaimEnd | time.Time | "2022-06-01T15:20:00Z" | the time at which users can no longer claim HARD tokens |
|
| ReserveFactor | Dec | "0.01" | Percentage of interest that is kept as protocol reserves |
|
||||||
| ClaimMultipliers | array (Multiplier) | [{see below}] | reward multipliers for users claiming HARD tokens |
|
| 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 |
|
| Key | Type | Example | Description |
|
||||||
| --------------------- | ------------------ | ---------------------- | ------------------------------------------------------------- |
|
| --------------------- | ------------------ | ---------------------- | ------------------------------------------------------------------------ |
|
||||||
| Active | bool | "true" | boolean for if token distribution is active for this schedule |
|
| HasMaxLimit | bool | "true" | boolean for if a maximum limit is in effect |
|
||||||
| DepositDenom | string | "bnb" | coin denom of the asset which can be deposited |
|
| MaximumLimit | Dec | "10000000.0" | global maximum amount of coins that can be borrowed |
|
||||||
| Start | time.Time | "2020-06-01T15:20:00Z" | the time when the period will end |
|
| LoanToValue | Dec | "0.5" | the percentage amount of borrow power each unit of deposit accounts for |
|
||||||
| 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 |
|
|
||||||
|
|
||||||
Each `ClaimMultiplier` has the following parameters
|
Each `InterestRateModel` has the following parameters
|
||||||
|
|
||||||
| Key | Type | Example | Description |
|
| Key | Type | Example | Description |
|
||||||
| ------------ | ------ | ------- | --------------------------------------------------------------- |
|
| ---------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||||
| Name | string | "large" | the unique name of the reward multiplier |
|
| BaseRateAPY | Dec | "0.0" | the base rate of APY interest when borrows are zero. |
|
||||||
| MonthsLockup | int | "6" | number of months HARD tokens with this multiplier are locked |
|
| BaseMultiplier | Dec | "0.01" | the percentage rate at which the interest rate APY increases for each percentage increase in borrow utilization. |
|
||||||
| Factor | Dec | "0.5" | the scaling factor for HARD tokens claimed with this multiplier |
|
| 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 |
|
||||||
|
@ -4,16 +4,12 @@ order: 6
|
|||||||
|
|
||||||
# Begin Block
|
# 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
|
```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) {
|
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||||
k.ApplyDepositRewards(ctx)
|
k.ApplyInterestRateUpdates(ctx)
|
||||||
if k.ShouldDistributeValidatorRewards(ctx, k.BondDenom(ctx)) {
|
k.AttemptIndexLiquidations(ctx)
|
||||||
k.ApplyDelegationRewards(ctx, k.BondDenom(ctx))
|
|
||||||
k.SetPreviousDelegationDistribution(ctx, ctx.BlockTime(), k.BondDenom(ctx))
|
|
||||||
}
|
|
||||||
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -18,4 +18,4 @@ parent:
|
|||||||
|
|
||||||
## Abstract
|
## 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.
|
||||||
|
@ -4,6 +4,23 @@ order: 1
|
|||||||
|
|
||||||
# Concepts
|
# 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.
|
||||||
|
@ -6,24 +6,45 @@ order: 2
|
|||||||
|
|
||||||
## Parameters and Genesis State
|
## 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
|
```go
|
||||||
// Params governance parameters for the incentive module
|
// Params governance parameters for the incentive module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Active bool `json:"active" yaml:"active"` // top level governance switch to disable all rewards
|
USDXMintingRewardPeriods RewardPeriods `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"` // rewards for minting USDX
|
||||||
Rewards Rewards `json:"rewards" yaml:"rewards"`
|
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 {
|
Each `RewardPeriod` defines a particular collateral for which rewards are eligible and the amount of rewards available.
|
||||||
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
|
```go
|
||||||
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
|
// RewardPeriod stores the state of an ongoing reward
|
||||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards
|
type RewardPeriod struct {
|
||||||
ClaimDuration time.Duration `json:"claim_duration" yaml:"claim_duration"` // how long users have after the period ends to claim their rewards
|
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
|
```go
|
||||||
// GenesisState is the state that must be provided at genesis.
|
// GenesisState is the state that must be provided at genesis.
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Params Params `json:"params" yaml:"params"`
|
Params Params `json:"params" yaml:"params"` // governance parameters
|
||||||
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
|
USDXAccumulationTimes GenesisAccumulationTimes `json:"usdx_accumulation_times" yaml:"usdx_accumulation_times"` // when USDX rewards were last accumulated
|
||||||
RewardPeriods RewardPeriods `json:"reward_periods" yaml:"reward_periods"`
|
HardSupplyAccumulationTimes GenesisAccumulationTimes `json:"hard_supply_accumulation_times" yaml:"hard_supply_accumulation_times"` // when hard supply rewards were last accumulated
|
||||||
ClaimPeriods ClaimPeriods `json:"claim_periods" yaml:"claim_periods"`
|
HardBorrowAccumulationTimes GenesisAccumulationTimes `json:"hard_borrow_accumulation_times" yaml:"hard_borrow_accumulation_times"` // when hard borrow rewards were last accumulated
|
||||||
Claims Claims `json:"claims" yaml:"claims"`
|
HardDelegatorAccumulationTimes GenesisAccumulationTimes `json:"hard_delegator_accumulation_times" yaml:"hard_delegator_accumulation_times"` // when hard delegator rewards were last accumulated
|
||||||
NextClaimPeriodIDs GenesisClaimPeriodIDs `json:"next_claim_period_ids" yaml:"next_claim_period_ids"`
|
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).
|
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
|
// HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
|
||||||
|
type HardLiquidityProviderClaim struct {
|
||||||
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.
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -4,13 +4,18 @@ order: 3
|
|||||||
|
|
||||||
# Messages
|
# Messages
|
||||||
|
|
||||||
Users claim rewards using a `MsgClaimReward`.
|
Users claim rewards using `MsgClaimUSDXMintingReward` and `MsgClaimHardLiquidityProviderReward` messages.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// MsgClaimReward message type used to claim rewards
|
// MsgClaimUSDXMintingReward message type used to claim USDX minting rewards
|
||||||
type MsgClaimReward struct {
|
type MsgClaimUSDXMintingReward struct {
|
||||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
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"`
|
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
|
* 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 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
|
||||||
|
@ -6,19 +6,22 @@ order: 4
|
|||||||
|
|
||||||
The `x/incentive` module emits the following events:
|
The `x/incentive` module emits the following events:
|
||||||
|
|
||||||
## MsgClaimReward
|
## ClaimUSDXMintingReward
|
||||||
|
|
||||||
| Type | Attribute Key | Attribute Value |
|
| Type | Attribute Key | Attribute Value |
|
||||||
|----------------------|---------------------|----------------------|
|
|----------------------|---------------------|---------------------------|
|
||||||
| claim_reward | claimed_by | `{claiming address}' |
|
| claim_reward | claimed_by | `{claiming address}' |
|
||||||
| claim_reward | claim_amount | `{amount claimed}' |
|
| claim_reward | claim_amount | `{amount claimed}' |
|
||||||
| message | module | incentive |
|
| claim_reward | claim_type | `{amount claimed}' |
|
||||||
| message | sender | `{sender address}' |
|
| message | module | incentive |
|
||||||
|
| message | sender | hard_liquidity_provider |
|
||||||
|
|
||||||
## BeginBlock
|
## MsgClaimHardLiquidityProviderReward
|
||||||
|
|
||||||
| Type | Attribute Key | Attribute Value |
|
| Type | Attribute Key | Attribute Value |
|
||||||
|----------------------|---------------------|----------------------|
|
|----------------------|---------------------|---------------------------|
|
||||||
| new_claim_period | claim_period | `{claim period}' |
|
| claim_reward | claimed_by | `{claiming address}' |
|
||||||
| new_reward_period | reward_period | `{reward period}' |
|
| claim_reward | claim_amount | `{amount claimed}' |
|
||||||
| claim_period_expiry | claim_period | `{claim period}' |
|
| claim_reward | claim_type | `{amount claimed}' |
|
||||||
|
| message | module | incentive |
|
||||||
|
| message | sender | usdx_minting |
|
||||||
|
@ -6,26 +6,40 @@ order: 5
|
|||||||
|
|
||||||
The incentive module contains the following parameters:
|
The incentive module contains the following parameters:
|
||||||
|
|
||||||
| Key | Type | Example | Description |
|
| Key | Type | Example | Description |
|
||||||
|------------|----------------|---------------|--------------------------------------------------|
|
|----------------------------|--------------------|------------------------|--------------------------------------------------|
|
||||||
| Active | bool | "true" | boolean for if this module is active |
|
| USDXMintingRewardPeriods | RewardPeriods | [{see below}] | USDX minting reward periods |
|
||||||
| Rewards | array (Reward) | [{see below}] | array of params for each inflationary period |
|
| 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 |
|
Each `RewardPeriod` has the following parameters
|
||||||
|------------------|--------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| Active | bool | "true | boolean for if rewards for this collateral are active |
|
| Key | Type | Example | Description |
|
||||||
| Denom | string | "bnb" | the collateral for which rewards are eligible |
|
|------------------|--------------------|------------------------------------|------------------------------------------------------------------|
|
||||||
| AvailableRewards | object (coin) | `{"denom":"kava","amount":"1000"}` | the rewards available per reward period |
|
| Active | bool | "true | boolean for if rewards for this collateral are active |
|
||||||
| Duration | string (time ns) | "172800000000000" | the duration of each reward period |
|
| CollateralType | string | "bnb-a" | the collateral for which rewards are eligible |
|
||||||
| ClaimMultipliers | array (Multiplier) | [{see below}] | the number of months for which claimed rewards will be vesting and the multiplier applied when rewards are claimed|
|
| Start | Time | "2020-12-02T14:00:00Z" | the time at which rewards start |
|
||||||
| ClaimDuration | string (time ns) | "172800000000000" | how long users have to claim rewards before they expire |
|
| 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:
|
Each `Multiplier` has the following parameters:
|
||||||
|
|
||||||
| Key | Type | Example | Description |
|
| Key | Type | Example | Description |
|
||||||
|-----------------------|--------------------|--------------------------|-----------------------------------------------------------------|
|
|-----------------------|--------------------|--------------------------|-----------------------------------------------------------------|
|
||||||
| Name | string | "large" | the unique name of the reward multiplier |
|
| Name | string | "large" | the unique name of the reward multiplier |
|
||||||
| MonthsLockup | int | "6" | number of months HARD tokens with this multiplier are locked |
|
| MonthsLockup | int | "6" | number of months tokens with this multiplier are locked |
|
||||||
| Factor | Dec | "0.5" | the scaling factor for HARD tokens claimed with this multiplier |
|
| Factor | Dec | "0.5" | the scaling factor for tokens claimed with this multiplier |
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
```
|
|
112
x/incentive/spec/06_hooks.md
Normal file
112
x/incentive/spec/06_hooks.md
Normal 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) {
|
||||||
|
}
|
||||||
|
```
|
38
x/incentive/spec/07_begin_block.md
Normal file
38
x/incentive/spec/07_begin_block.md
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -13,12 +13,13 @@ parent:
|
|||||||
3. **[Messages](03_messages.md)**
|
3. **[Messages](03_messages.md)**
|
||||||
4. **[Events](04_events.md)**
|
4. **[Events](04_events.md)**
|
||||||
5. **[Params](05_params.md)**
|
5. **[Params](05_params.md)**
|
||||||
6. **[BeginBlock](06_begin_block.md)**
|
6. **[Hooks](06_hooks.md)**
|
||||||
|
7. **[BeginBlock](07_begin_block.md)**
|
||||||
|
|
||||||
## Abstract
|
## 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
|
### 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.
|
||||||
|
Loading…
Reference in New Issue
Block a user