diff --git a/x/incentive/spec/01_concepts.md b/x/incentive/spec/01_concepts.md index d8bb5ad7..c5089038 100644 --- a/x/incentive/spec/01_concepts.md +++ b/x/incentive/spec/01_concepts.md @@ -4,7 +4,7 @@ order: 1 # Concepts -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) +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) ## General Reward Distribution @@ -42,4 +42,7 @@ The incentive module is responsible for distribution of KAVA tokens to users who ## SWP Token Distribution -TODO \ No newline at end of file +The incentive module distributes the SWP token on the Kava blockchain. SWP tokens are distributed to two types of ecosystem participants: + +1. Kava stakers - any address that stakes (delegates) KAVA tokens will be eligible to claim SWP tokens. For each delegator, SWP 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 SWP tokens earmarked for stakers during the distribution period. Distribution periods are defined by a start date, an end date, and a number of SWP tokens that are distributed per second. +2. Liquidity providers - any address that provides liquidity to eligible Swap protocol pools will be eligible to claim SWP tokens. For each liquidity provider, SWP tokens are accumulated ratably based on the total amount of pool shares. For example, if a liquidity provider deposits "xyz" and "abc" tokens into the "abc:xyz" pool to receive 10 shares and the pool has 50 total shares, then that user will accumulate 20% of SWP tokens earmarked for liquidity providers of that pool during the distribution period. Distribution periods are defined by a start date, an end date, and a number of SWP tokens that are distributed per second. diff --git a/x/incentive/spec/02_state.md b/x/incentive/spec/02_state.md index e1ef18b9..d76bfd9d 100644 --- a/x/incentive/spec/02_state.md +++ b/x/incentive/spec/02_state.md @@ -11,12 +11,13 @@ order: 2 ```go // Params governance parameters for the incentive module type Params struct { - 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 + USDXMintingRewardPeriods RewardPeriods `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"` + HardSupplyRewardPeriods MultiRewardPeriods `json:"hard_supply_reward_periods" yaml:"hard_supply_reward_periods"` + HardBorrowRewardPeriods MultiRewardPeriods `json:"hard_borrow_reward_periods" yaml:"hard_borrow_reward_periods"` + DelegatorRewardPeriods MultiRewardPeriods `json:"delegator_reward_periods" yaml:"delegator_reward_periods"` + SwapRewardPeriods MultiRewardPeriods `json:"swap_reward_periods" yaml:"swap_reward_periods"` + ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` + ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"` } ``` @@ -24,7 +25,6 @@ type Params struct { 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 @@ -53,13 +53,18 @@ type MultiRewardPeriod struct { ```go // GenesisState is the state that must be provided at genesis. type GenesisState struct { - 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 + Params Params `json:"params" yaml:"params"` + + USDXRewardState GenesisRewardState `json:"usdx_reward_state" yaml:"usdx_reward_state"` + HardSupplyRewardState GenesisRewardState `json:"hard_supply_reward_state" yaml:"hard_supply_reward_state"` + HardBorrowRewardState GenesisRewardState `json:"hard_borrow_reward_state" yaml:"hard_borrow_reward_state"` + DelegatorRewardState GenesisRewardState `json:"delegator_reward_state" yaml:"delegator_reward_state"` + SwapRewardState GenesisRewardState `json:"swap_reward_state" yaml:"swap_reward_state"` + + USDXMintingClaims USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` + HardLiquidityProviderClaims HardLiquidityProviderClaims `json:"hard_liquidity_provider_claims" yaml:"hard_liquidity_provider_claims"` + DelegatorClaims DelegatorClaims `json:"delegator_claims" yaml:"delegator_claims"` + SwapClaims SwapClaims `json:"swap_claims" yaml:"swap_claims"` } ``` @@ -69,33 +74,68 @@ For complete details for how items are stored, see [keys.go](../types/keys.go). ### Claim Creation -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`: +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. Each `Claim` object contains one or several RewardIndexes, which are used to calculate the amount of rewards a user can claim. There are four defined claim objects: + +- `USDXMintingClaim` +- `HardLiquidityProviderClaim` +- `DelegatorClaim` +- `SwapClaim` ```go +// Claim is an interface for handling common claim actions +type Claim interface { + GetOwner() sdk.AccAddress + GetReward() sdk.Coin + GetType() string +} + // 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"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + Reward sdk.Coin `json:"reward" yaml:"reward"` } // 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"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + Reward sdk.Coins `json:"reward" yaml:"reward"` +} + +// RewardIndex stores reward accumulation information +type RewardIndex struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + RewardFactor sdk.Dec `json:"reward_factor" yaml:"reward_factor"` +} + +// MultiRewardIndex stores reward accumulation information on multiple reward types +type MultiRewardIndex struct { + CollateralType string `json:"collateral_type" yaml:"collateral_type"` + RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` } // 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 + BaseClaim `json:"base_claim" yaml:"base_claim"` + RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` } // 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 + BaseMultiClaim `json:"base_claim" yaml:"base_claim"` + SupplyRewardIndexes MultiRewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"` + BorrowRewardIndexes MultiRewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"` +} + +// DelegatorClaim stores delegation rewards that can be claimed by owner +type DelegatorClaim struct { + BaseMultiClaim `json:"base_claim" yaml:"base_claim"` + RewardIndexes MultiRewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` +} + +// SwapClaim stores the swap rewards that can be claimed by owner +type SwapClaim struct { + BaseMultiClaim `json:"base_claim" yaml:"base_claim"` + RewardIndexes MultiRewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` } ``` diff --git a/x/incentive/spec/03_messages.md b/x/incentive/spec/03_messages.md index 4859d5a5..8cc3a4da 100644 --- a/x/incentive/spec/03_messages.md +++ b/x/incentive/spec/03_messages.md @@ -4,19 +4,34 @@ order: 3 # Messages -Users claim rewards using `MsgClaimUSDXMintingReward` and `MsgClaimHardReward` messages. +Users claim rewards using messages that correspond to each claim type. ```go // 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"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` } // MsgClaimHardReward message type used to claim Hard liquidity provider rewards type MsgClaimHardReward struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` + DenomsToClaim []string `json:"denoms_to_claim" yaml:"denoms_to_claim"` +} + +// MsgClaimDelegatorReward message type used to claim delegator rewards +type MsgClaimDelegatorReward struct { + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` + DenomsToClaim []string `json:"denoms_to_claim" yaml:"denoms_to_claim"` +} + +// MsgClaimSwapReward message type used to claim delegator rewards +type MsgClaimSwapReward struct { + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` + DenomsToClaim []string `json:"denoms_to_claim" yaml:"denoms_to_claim"` } ``` diff --git a/x/incentive/spec/05_params.md b/x/incentive/spec/05_params.md index 0f77d1bc..f9debed4 100644 --- a/x/incentive/spec/05_params.md +++ b/x/incentive/spec/05_params.md @@ -6,40 +6,40 @@ order: 5 The incentive module contains the following parameters: -| 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 | - +| 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 | +| DelegatorRewardPeriods | MultiRewardPeriods | [{see below}] | Delegator reward periods | +| SwapRewardPeriods | MultiRewardPeriods | [{see below}] | Swap 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 `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 | +| 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 | +| 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 tokens with this multiplier are locked | -| Factor | Dec | "0.5" | the scaling factor for tokens claimed with this multiplier | +| Key | Type | Example | Description | +| ------------ | ------ | ------- | ---------------------------------------------------------- | +| Name | string | "large" | the unique name of the reward 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 | diff --git a/x/incentive/spec/06_hooks.md b/x/incentive/spec/06_hooks.md index 62f46255..eff8bbd6 100644 --- a/x/incentive/spec/06_hooks.md +++ b/x/incentive/spec/06_hooks.md @@ -6,9 +6,10 @@ order: 6 This module implements the `Hooks` interface for the following modules: -* cdp -* hard -* staking (defined in cosmos-sdk) +- cdp +- hard +- swap +- staking (defined in cosmos-sdk) CDP module hooks manage the creation and synchronization of USDX minting incentives. @@ -110,3 +111,17 @@ func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { } ``` + +Swap module hooks manage the creation and synchronization of Swap protocol liquidity provider rewards. + +```go +// ------------------- Swap Module Hooks ------------------- + +func (h Hooks) AfterPoolDepositCreated(ctx sdk.Context, poolID string, depositor sdk.AccAddress, _ sdk.Int) { + h.k.InitializeSwapReward(ctx, poolID, depositor) +} + +func (h Hooks) BeforePoolDepositModified(ctx sdk.Context, poolID string, depositor sdk.AccAddress, sharesOwned sdk.Int) { + h.k.SynchronizeSwapReward(ctx, poolID, depositor, sharesOwned) +} +``` diff --git a/x/incentive/spec/07_begin_block.md b/x/incentive/spec/07_begin_block.md index 72431d0d..b66af81b 100644 --- a/x/incentive/spec/07_begin_block.md +++ b/x/incentive/spec/07_begin_block.md @@ -4,35 +4,28 @@ 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 +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) - } - } + + params := k.GetParams(ctx) + + for _, rp := range params.USDXMintingRewardPeriods { + k.AccumulateUSDXMintingRewards(ctx, rp) + } + for _, rp := range params.HardSupplyRewardPeriods { + k.AccumulateHardSupplyRewards(ctx, rp) + } + for _, rp := range params.HardBorrowRewardPeriods { + k.AccumulateHardBorrowRewards(ctx, rp) + } + for _, rp := range params.DelegatorRewardPeriods { + k.AccumulateDelegatorRewards(ctx, rp) + } + for _, rp := range params.SwapRewardPeriods { + k.AccumulateSwapRewards(ctx, rp) + } } ```