Swap users accumulate rewards (#950)

* add swap claim type

* add store methods for swap claims

* add swap claims to genesis state

* tidy up cdp and hard hook doc comments

* add uncalled hooks to the swap keeper

* add swap rewards sync method

* add swap rewards init method

* connect swap rewards via swap hooks

* Update querier and client for swap claims (#951)

* refactor querier to dedupe code

* add swap claims querier endpoint

* add swap claim querying to rest

* add swap claim querying to cli

* add keeper method to iterate swap reward indexes

* simplify reward-factors query endpoint, add swap

* update swap hook to match latest swap branch

* rename func to not collide with latest swap branch

* Squash merge swap-acceptance branch (#956)

* add failing acceptance test for a user depositing into a pool

* implement GetAccount test helper

* implement swap.MsgDeposit for creating and adding liquidity to a pool

* update aliases, add event types, and fix typo/compiler errors in handler
test

* use only aliases names in handler test (don't use swap types -- ensures
we have run aliasgen), add assertion for even type message

* implement account and module account balance checks in handler test

* fill out handler assertions for testing keeper state and events

* update signed json representation and register swap/MsgDeposit for
proper encoding

* fill out boilerplate to get handler test to compile

* alias gen for pool

* add handling of message type; fill in deposit keeper method for
succesful compile; noop but test assertions now run up to module acc not
nil check

* add module account permissions for swap module -- fixes module account
creation; pass account keeper and supply keeper into swap keeper to
allow the ability to work with user and module accounts

* implement create pool logic for msg deposit; allows creation of a of new
pool, checking params to see if it is allowed.  Initi shares are set,
and senders number of shares are stored

* Swap migrations scaffolding (#925)

* swap module scaffolding

* global swap fee

* can't think of a reason for begin blocker; removing for abci.go for now;

* test pair types; refactor pair name logic; simplify pairs validation and
fix stack overflow error

* check comparison

* use test package

* init swap module genesis

* add basic marshall tests

* remove reward apy from pairs

* fix integration helpers

* use max swap fee constant; fix validation of swap fee; add tests to
cover param validation and param set setup

* use noerror over nil

* start genesis tests

* test param set validation mirrors param validation

* add genesis tests

* remove print statement

* add subtests for genesis test cases; add extra querier test for unknown
route; add keeper params testing

* add spec

* update swagger

* find replace hard -> swap in comments

* remove unused method

* rename pairs to allowed pools; pool is more commonly used, and
allowedPool makes it more clear what swap parameter is for.  In
addition, we won't conflict with Pool data structure for storing a
created pool in the store.

* remove generated link

* missed spec rename

* validate token order for allowed pools

* fix swagger

* json should be snakecase; change allowedPools to allowed_pools

* add legacy types

* add swap genesis to v0_15 migration

* add legacy types

* add swap genesis to v0_15 migration

* migration revisions

Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>

* keeper todos

* update keeper tests

* type todos

* update types tests

* tx deposit cli cmd

* tx deposit rest

* Swap module simulation scaffolding (#924)

* sims scaffolding

* add noop operation

* genesis revisions

* add param changes

* mvoe persistance methods to main keeper file, consolidate tests

* make helper methods private. they are tested via deposit method, and
unit testing them would make test suite brittle and refactoring
difficult

* use more clear coin variables

* code 1 is reserved, use code 2 and sequence all errors

* remove todo

* Implement deadline for swap module module message. This is implemented in
handler with a interface to easily apply to it to all messages, and
separate msg validation concerns from the keeper

* move allowed pools to params -- let pool and pool_test focus on pool domain logic, not
parameter & governance concerns

* update alias

* add unitless implementatin of constant product liquidity pool to
isolate and enapsulate liquidity logic.  Swap methods interfaces are
added, but implementation not yet added

* nits and todos

* add ErrInvalidPool

* add tests for edge cases around pool depletion; add explicit panic for
edge case that results in a pool reserve being zero; handle pool
reinitialization if it is empty

* touch up comments and flush out the rest of assertions

* add data structures for keeper state storage separate from pool domain
objects, and improve structure for easier querying

* rename pool name to pool key for events

* add support for a denominated pool that uses sdk.Coins and sdk.Coin
arguments, keeping tracking of the units in the base pool.  This gives
nice separation between pool logic, and coin/denom logic

* refactor keeper to use new records for storage, and implement pool
deposit using the denominated pool

* address previous PR comment - reminder for migration if changing
account permissions

* msg deposit should validate that denoms are not equal

* add godoc comments

* golint and some poolName -> poolID cleanup

* implement adding liquidity to an existing pool

* hardcode pools in sims

* touch up comment

* withdraw keeper logic

* withdraw type updates

* add withdraw msg tx handler

* initial withdraw test

* fix panic

* use new denominated pool with existing shares

* fix: check args on deposit cmd

* add slippage limit check for depositing to an existing pool

* send coins just before event emission

* check liquidity returned is greater than zero for both coins; ensure
returned number of shares are greater than zero

* add deadline to msgwithdraw

* register msgwithdraw

* scaffold msgwithdraw types test

* register the correct msg

* modify swap functions to also return the amount paid for the pool swap
fee.  This will be used to calculate slippage and for event tracking

* add slippage types

* add expected withdrawal coins

* calculate slippage against expected coins

* update withdraw keeper tests

* spelling, improve comments on add liquidity math

* typo

* typo

* grammer

* typo / grammer

* remove pool_id from withdraw msg

* add slippage to tx cmd

* TestWithdraw_Partial

* nit

* add withdraw no pool, no deposit record tests

* drop event check on partial withdraw test

* fix broken link

* fix broken link

* resolve merge conflicts

* ensure swap fee can not be equal to 1; add full implementation of swap
pool methods;  these implementation ensure that the pool invariant is
always greater or equal to the previous invariant

* refactor duplicated code into private swap methods

* add runtime assertion to always ensure invariant is greater or equal
to the previous invariant sub fee on swaps

* improve comments for base pool swap functions

* add swap exact input and output methods to denominated pool that wrap
the base pool interface for swapping

* comment touch ups

* more comment touchups

* fix msg deposit struct tag (#943)

* use better name for swap calculation private methods

* nits: golint

* fix misspelling in method name

* Add HARD token governance committee for Hard module (#941)

* add hard gov token committee

* revisions: update migration

* revisions: update test/data file

* initial revisions

* add TokenCommittee JSONMarshal test

* fix SetPermissions method

* remove BaseCommittee Type field

* add incentive params to allowed params

* Add SWP token governance committee for Swap module (#946)

* add swp token commitee to migration

* update test, add gen export utility method

* final revisions: add TODO

* remove slippage from withdraw to use min values for coins; add
additional validation test cases

* update alias for swap module

* add withdraw tests to handler for increased coverage; note: first pass,
improvements still yet to be made here

* refact withdraw keeper to use min amounts; panic for cases that do not
happen in normal situations

* lint fixes

* use total shares to track if pool should be deleted; add more in depth
withdraw comment

* add exact args for withdraw cmd

* extract record update methods

* update depositor share record if it exists -- do not overwrite an
existing record; ensures no loss of shares if the same address deposits
more than once

* Swap queries: deposit, pool, pools (#949)

* query deposits types

* implement deposit querier keeper methods

* query deposits CLI

* query deposits REST

* query types for pool/pools

* pool/pools querier keeper methods

* pool/pools CLI

* pool/pools REST

* basic pool/pools query tests

* basic deposit querier test

* iterate share records via owner bytes

* nit: add example for querying deposits by owner only

Co-authored-by: karzak <kjydavis3@gmail.com>

* feat: add REST tx handler for swap LP withdrawals

Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>
Co-authored-by: Denali Marsh <denali@kava.io>
Co-authored-by: denalimarsh <denalimarsh@gmail.com>
Co-authored-by: karzak <kjydavis3@gmail.com>

* expand incentive cli query docs

Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>
Co-authored-by: Denali Marsh <denali@kava.io>
Co-authored-by: denalimarsh <denalimarsh@gmail.com>
Co-authored-by: karzak <kjydavis3@gmail.com>

* minor update to godoc comment

Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>
Co-authored-by: Denali Marsh <denali@kava.io>
Co-authored-by: denalimarsh <denalimarsh@gmail.com>
Co-authored-by: karzak <kjydavis3@gmail.com>
This commit is contained in:
Ruaridh 2021-07-13 13:35:02 +01:00 committed by GitHub
parent 65052ce31a
commit 4beaf0de54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1427 additions and 931 deletions

View File

@ -390,7 +390,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
app.accountKeeper,
app.supplyKeeper,
)
app.swapKeeper = swap.NewKeeper(
swapKeeper := swap.NewKeeper(
app.cdc,
keys[swap.StoreKey],
swapSubspace,
@ -406,11 +406,11 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
&hardKeeper,
app.accountKeeper,
&stakingKeeper,
app.swapKeeper,
&swapKeeper,
)
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
// NOTE: These keepers are passed by reference above, so they will contain these hooks.
app.stakingKeeper = *stakingKeeper.SetHooks(
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks(), app.incentiveKeeper.Hooks()))
@ -418,6 +418,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
app.hardKeeper = *hardKeeper.SetHooks(hard.NewMultiHARDHooks(app.incentiveKeeper.Hooks()))
app.swapKeeper = *swapKeeper.SetHooks(app.incentiveKeeper.Hooks())
// create the module manager (Note: Any module instantiated in the module manager that is later modified
// must be passed by reference here.)
app.mm = module.NewManager(

View File

@ -448,9 +448,10 @@ func Incentive(incentiveGS v0_14incentive.GenesisState) v0_15incentive.GenesisSt
hardSupplyAccumulationTimes,
hardBorrowAccumulationTimes,
hardDelegatorAccumulationTimes,
v0_15incentive.DefaultGenesisAccumulationTimes, // There is no previous swap rewards to accumulation starts at genesis time.
v0_15incentive.DefaultGenesisAccumulationTimes, // There is no previous swap rewards so accumulation starts at genesis time.
usdxMintingClaims,
hardClaims,
delegatorClaims,
v0_15incentive.DefaultSwapClaims,
)
}

View File

@ -45,10 +45,10 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace,
}
}
// SetHooks sets the cdp keeper hooks
// SetHooks adds hooks to the keeper.
func (k *Keeper) SetHooks(hooks types.CDPHooks) *Keeper {
if k.hooks != nil {
panic("cannot set validator hooks twice")
panic("cannot set cdp hooks twice")
}
k.hooks = hooks
return k

View File

@ -45,10 +45,10 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace,
}
}
// SetHooks sets the cdp keeper hooks
// SetHooks adds hooks to the keeper.
func (k *Keeper) SetHooks(hooks types.HARDHooks) *Keeper {
if k.hooks != nil {
panic("cannot set validator hooks twice")
panic("cannot set hard hooks twice")
}
k.hooks = hooks
return k

View File

@ -1,8 +1,5 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/incentive/types
// ALIASGEN: github.com/kava-labs/kava/x/incentive/keeper
// Code generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen) DO NOT EDIT.
package incentive
import (
@ -11,166 +8,175 @@ import (
)
const (
USDXMintingClaimType = types.USDXMintingClaimType
HardLiquidityProviderClaimType = types.HardLiquidityProviderClaimType
BondDenom = types.BondDenom
EventTypeClaim = types.EventTypeClaim
EventTypeRewardPeriod = types.EventTypeRewardPeriod
EventTypeClaimPeriod = types.EventTypeClaimPeriod
EventTypeClaimPeriodExpiry = types.EventTypeClaimPeriodExpiry
AttributeValueCategory = types.AttributeValueCategory
AttributeKeyClaimedBy = types.AttributeKeyClaimedBy
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
AttributeKeyClaimType = types.AttributeKeyClaimType
AttributeKeyRewardPeriod = types.AttributeKeyRewardPeriod
AttributeKeyClaimPeriod = types.AttributeKeyClaimPeriod
ModuleName = types.ModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
DefaultParamspace = types.DefaultParamspace
QuerierRoute = types.QuerierRoute
Small = types.Small
Medium = types.Medium
Large = types.Large
QueryGetRewards = types.QueryGetRewards
QueryGetHardRewards = types.QueryGetHardRewards
QueryGetHardRewardsUnsynced = types.QueryGetHardRewardsUnsynced
QueryGetUSDXMintingRewards = types.QueryGetUSDXMintingRewards
QueryGetUSDXMintingRewardsUnsynced = types.QueryGetUSDXMintingRewardsUnsynced
QueryGetRewardFactors = types.QueryGetRewardFactors
QueryGetParams = types.QueryGetParams
QueryGetRewardPeriods = types.QueryGetRewardPeriods
QueryGetClaimPeriods = types.QueryGetClaimPeriods
RestClaimCollateralType = types.RestClaimCollateralType
RestClaimOwner = types.RestClaimOwner
RestClaimType = types.RestClaimType
RestUnsynced = types.RestUnsynced
BeginningOfMonth = keeper.BeginningOfMonth
MidMonth = keeper.MidMonth
PaymentHour = keeper.PaymentHour
BeginningOfMonth = keeper.BeginningOfMonth
MidMonth = keeper.MidMonth
PaymentHour = keeper.PaymentHour
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
AttributeKeyClaimPeriod = types.AttributeKeyClaimPeriod
AttributeKeyClaimType = types.AttributeKeyClaimType
AttributeKeyClaimedBy = types.AttributeKeyClaimedBy
AttributeKeyRewardPeriod = types.AttributeKeyRewardPeriod
AttributeValueCategory = types.AttributeValueCategory
BondDenom = types.BondDenom
DefaultParamspace = types.DefaultParamspace
DelegatorClaimType = types.DelegatorClaimType
EventTypeClaim = types.EventTypeClaim
EventTypeClaimPeriod = types.EventTypeClaimPeriod
EventTypeClaimPeriodExpiry = types.EventTypeClaimPeriodExpiry
EventTypeRewardPeriod = types.EventTypeRewardPeriod
HardLiquidityProviderClaimType = types.HardLiquidityProviderClaimType
Large = types.Large
Medium = types.Medium
ModuleName = types.ModuleName
QuerierRoute = types.QuerierRoute
QueryGetDelegatorRewards = types.QueryGetDelegatorRewards
QueryGetHardRewards = types.QueryGetHardRewards
QueryGetParams = types.QueryGetParams
QueryGetRewardFactors = types.QueryGetRewardFactors
QueryGetSwapRewards = types.QueryGetSwapRewards
QueryGetUSDXMintingRewards = types.QueryGetUSDXMintingRewards
RestClaimCollateralType = types.RestClaimCollateralType
RestClaimOwner = types.RestClaimOwner
RestClaimType = types.RestClaimType
RestUnsynced = types.RestUnsynced
RouterKey = types.RouterKey
Small = types.Small
StoreKey = types.StoreKey
SwapClaimType = types.SwapClaimType
USDXMintingClaimType = types.USDXMintingClaimType
)
var (
// functions aliases
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
NewUSDXMintingClaim = types.NewUSDXMintingClaim
NewHardLiquidityProviderClaim = types.NewHardLiquidityProviderClaim
NewMultiRewardPeriod = types.NewMultiRewardPeriod
NewRewardIndex = types.NewRewardIndex
NewMultiRewardIndex = types.NewMultiRewardIndex
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
NewGenesisAccumulationTime = types.NewGenesisAccumulationTime
NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward
NewMsgClaimUSDXMintingRewardVVesting = types.NewMsgClaimUSDXMintingRewardVVesting
NewMsgClaimHardReward = types.NewMsgClaimHardReward
NewMsgClaimHardRewardVVesting = types.NewMsgClaimHardRewardVVesting
NewParams = types.NewParams
DefaultParams = types.DefaultParams
ParamKeyTable = types.ParamKeyTable
NewRewardPeriod = types.NewRewardPeriod
NewMultiplier = types.NewMultiplier
NewPeriod = types.NewPeriod
NewQueryRewardsParams = types.NewQueryRewardsParams
NewQueryUSDXMintingRewardsParams = types.NewQueryUSDXMintingRewardsParams
NewQueryUSDXMintingRewardsUnsyncedParams = types.NewQueryUSDXMintingRewardsUnsyncedParams
NewQueryHardRewardsParams = types.NewQueryHardRewardsParams
NewQueryHardRewardsUnsyncedParams = types.NewQueryHardRewardsUnsyncedParams
NewQueryRewardFactorsParams = types.NewQueryRewardFactorsParams
NewRewardFactor = types.NewRewardFactor
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
CalculateTimeElapsed = keeper.CalculateTimeElapsed
// function aliases
CalculateTimeElapsed = keeper.CalculateTimeElapsed
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
DefaultGenesisState = types.DefaultGenesisState
DefaultParams = types.DefaultParams
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
NewAccumulator = types.NewAccumulator
NewDelegatorClaim = types.NewDelegatorClaim
NewGenesisAccumulationTime = types.NewGenesisAccumulationTime
NewGenesisState = types.NewGenesisState
NewHardLiquidityProviderClaim = types.NewHardLiquidityProviderClaim
NewMsgClaimDelegatorReward = types.NewMsgClaimDelegatorReward
NewMsgClaimDelegatorRewardVVesting = types.NewMsgClaimDelegatorRewardVVesting
NewMsgClaimHardReward = types.NewMsgClaimHardReward
NewMsgClaimHardRewardVVesting = types.NewMsgClaimHardRewardVVesting
NewMsgClaimUSDXMintingReward = types.NewMsgClaimUSDXMintingReward
NewMsgClaimUSDXMintingRewardVVesting = types.NewMsgClaimUSDXMintingRewardVVesting
NewMultiRewardIndex = types.NewMultiRewardIndex
NewMultiRewardPeriod = types.NewMultiRewardPeriod
NewMultiplier = types.NewMultiplier
NewParams = types.NewParams
NewPeriod = types.NewPeriod
NewQueryGetRewardFactorsResponse = types.NewQueryGetRewardFactorsResponse
NewQueryRewardsParams = types.NewQueryRewardsParams
NewRewardIndex = types.NewRewardIndex
NewRewardPeriod = types.NewRewardPeriod
NewSwapClaim = types.NewSwapClaim
NewUSDXMintingClaim = types.NewUSDXMintingClaim
ParamKeyTable = types.ParamKeyTable
RegisterCodec = types.RegisterCodec
// variable aliases
ModuleCdc = types.ModuleCdc
ErrClaimNotFound = types.ErrClaimNotFound
ErrRewardPeriodNotFound = types.ErrRewardPeriodNotFound
ErrInvalidAccountType = types.ErrInvalidAccountType
ErrNoClaimsFound = types.ErrNoClaimsFound
ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance
ErrAccountNotFound = types.ErrAccountNotFound
ErrInvalidMultiplier = types.ErrInvalidMultiplier
ErrZeroClaim = types.ErrZeroClaim
ErrClaimExpired = types.ErrClaimExpired
ErrInvalidClaimType = types.ErrInvalidClaimType
ErrInvalidClaimOwner = types.ErrInvalidClaimOwner
USDXMintingClaimKeyPrefix = types.USDXMintingClaimKeyPrefix
USDXMintingRewardFactorKeyPrefix = types.USDXMintingRewardFactorKeyPrefix
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix
HardLiquidityClaimKeyPrefix = types.HardLiquidityClaimKeyPrefix
HardSupplyRewardIndexesKeyPrefix = types.HardSupplyRewardIndexesKeyPrefix
PreviousHardSupplyRewardAccrualTimeKeyPrefix = types.PreviousHardSupplyRewardAccrualTimeKeyPrefix
HardBorrowRewardIndexesKeyPrefix = types.HardBorrowRewardIndexesKeyPrefix
PreviousHardBorrowRewardAccrualTimeKeyPrefix = types.PreviousHardBorrowRewardAccrualTimeKeyPrefix
DelegatorRewardIndexesKeyPrefix = types.DelegatorRewardIndexesKeyPrefix
PreviousDelegatorRewardAccrualTimeKeyPrefix = types.PreviousDelegatorRewardAccrualTimeKeyPrefix
USDXMintingRewardDenom = types.USDXMintingRewardDenom
HardLiquidityRewardDenom = types.HardLiquidityRewardDenom
KeyUSDXMintingRewardPeriods = types.KeyUSDXMintingRewardPeriods
KeyHardSupplyRewardPeriods = types.KeyHardSupplyRewardPeriods
KeyHardBorrowRewardPeriods = types.KeyHardBorrowRewardPeriods
KeyDelegatorRewardPeriods = types.KeyDelegatorRewardPeriods
KeyClaimEnd = types.KeyClaimEnd
KeyMultipliers = types.KeyMultipliers
DefaultActive = types.DefaultActive
DefaultRewardPeriods = types.DefaultRewardPeriods
DefaultClaimEnd = types.DefaultClaimEnd
DefaultDelegatorClaims = types.DefaultDelegatorClaims
DefaultGenesisAccumulationTimes = types.DefaultGenesisAccumulationTimes
DefaultHardClaims = types.DefaultHardClaims
DefaultMultiRewardPeriods = types.DefaultMultiRewardPeriods
DefaultMultipliers = types.DefaultMultipliers
DefaultDelegatorClaims = types.DefaultDelegatorClaims
DefaultRewardPeriods = types.DefaultRewardPeriods
DefaultSwapClaims = types.DefaultSwapClaims
DefaultUSDXClaims = types.DefaultUSDXClaims
DefaultHardClaims = types.DefaultHardClaims
DefaultGenesisAccumulationTimes = types.DefaultGenesisAccumulationTimes
DefaultClaimEnd = types.DefaultClaimEnd
DelegatorClaimKeyPrefix = types.DelegatorClaimKeyPrefix
DelegatorRewardIndexesKeyPrefix = types.DelegatorRewardIndexesKeyPrefix
ErrAccountNotFound = types.ErrAccountNotFound
ErrClaimExpired = types.ErrClaimExpired
ErrClaimNotFound = types.ErrClaimNotFound
ErrDecreasingRewardFactor = types.ErrDecreasingRewardFactor
ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance
ErrInvalidAccountType = types.ErrInvalidAccountType
ErrInvalidClaimOwner = types.ErrInvalidClaimOwner
ErrInvalidClaimType = types.ErrInvalidClaimType
ErrInvalidMultiplier = types.ErrInvalidMultiplier
ErrNoClaimsFound = types.ErrNoClaimsFound
ErrRewardPeriodNotFound = types.ErrRewardPeriodNotFound
ErrZeroClaim = types.ErrZeroClaim
GovDenom = types.GovDenom
PrincipalDenom = types.PrincipalDenom
HardBorrowRewardIndexesKeyPrefix = types.HardBorrowRewardIndexesKeyPrefix
HardLiquidityClaimKeyPrefix = types.HardLiquidityClaimKeyPrefix
HardLiquidityRewardDenom = types.HardLiquidityRewardDenom
HardSupplyRewardIndexesKeyPrefix = types.HardSupplyRewardIndexesKeyPrefix
IncentiveMacc = types.IncentiveMacc
KeyClaimEnd = types.KeyClaimEnd
KeyDelegatorRewardPeriods = types.KeyDelegatorRewardPeriods
KeyHardBorrowRewardPeriods = types.KeyHardBorrowRewardPeriods
KeyHardSupplyRewardPeriods = types.KeyHardSupplyRewardPeriods
KeyMultipliers = types.KeyMultipliers
KeySwapRewardPeriods = types.KeySwapRewardPeriods
KeyUSDXMintingRewardPeriods = types.KeyUSDXMintingRewardPeriods
ModuleCdc = types.ModuleCdc
PreviousDelegatorRewardAccrualTimeKeyPrefix = types.PreviousDelegatorRewardAccrualTimeKeyPrefix
PreviousHardBorrowRewardAccrualTimeKeyPrefix = types.PreviousHardBorrowRewardAccrualTimeKeyPrefix
PreviousHardSupplyRewardAccrualTimeKeyPrefix = types.PreviousHardSupplyRewardAccrualTimeKeyPrefix
PreviousSwapRewardAccrualTimeKeyPrefix = types.PreviousSwapRewardAccrualTimeKeyPrefix
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix
PrincipalDenom = types.PrincipalDenom
SwapClaimKeyPrefix = types.SwapClaimKeyPrefix
SwapRewardIndexesKeyPrefix = types.SwapRewardIndexesKeyPrefix
USDXMintingClaimKeyPrefix = types.USDXMintingClaimKeyPrefix
USDXMintingRewardDenom = types.USDXMintingRewardDenom
USDXMintingRewardFactorKeyPrefix = types.USDXMintingRewardFactorKeyPrefix
)
type (
Claim = types.Claim
Claims = types.Claims
BaseClaim = types.BaseClaim
BaseMultiClaim = types.BaseMultiClaim
USDXMintingClaim = types.USDXMintingClaim
USDXMintingClaims = types.USDXMintingClaims
HardLiquidityProviderClaim = types.HardLiquidityProviderClaim
HardLiquidityProviderClaims = types.HardLiquidityProviderClaims
MultiRewardPeriod = types.MultiRewardPeriod
MultiRewardPeriods = types.MultiRewardPeriods
RewardIndex = types.RewardIndex
RewardIndexes = types.RewardIndexes
MultiRewardIndex = types.MultiRewardIndex
MultiRewardIndexes = types.MultiRewardIndexes
SupplyKeeper = types.SupplyKeeper
StakingKeeper = types.StakingKeeper
CdpKeeper = types.CdpKeeper
HardKeeper = types.HardKeeper
AccountKeeper = types.AccountKeeper
CDPHooks = types.CDPHooks
HARDHooks = types.HARDHooks
GenesisState = types.GenesisState
GenesisAccumulationTime = types.GenesisAccumulationTime
GenesisAccumulationTimes = types.GenesisAccumulationTimes
MsgClaimUSDXMintingReward = types.MsgClaimUSDXMintingReward
MsgClaimUSDXMintingRewardVVesting = types.MsgClaimUSDXMintingRewardVVesting
MsgClaimHardReward = types.MsgClaimHardReward
MsgClaimHardRewardVVesting = types.MsgClaimHardRewardVVesting
Params = types.Params
RewardPeriod = types.RewardPeriod
RewardPeriods = types.RewardPeriods
Multiplier = types.Multiplier
Multipliers = types.Multipliers
MultiplierName = types.MultiplierName
QueryRewardsParams = types.QueryRewardsParams
QueryUSDXMintingRewardsParams = types.QueryUSDXMintingRewardsParams
QueryUSDXMintingRewardsUnsyncedParams = types.QueryUSDXMintingRewardsUnsyncedParams
QueryHardRewardsParams = types.QueryHardRewardsParams
QueryHardRewardsUnsyncedParams = types.QueryHardRewardsUnsyncedParams
QueryRewardFactorsParams = types.QueryRewardFactorsParams
RewardFactor = types.RewardFactor
RewardFactors = types.RewardFactors
Hooks = keeper.Hooks
Keeper = keeper.Keeper
Hooks = keeper.Hooks
Keeper = keeper.Keeper
AccountKeeper = types.AccountKeeper
Accumulator = types.Accumulator
BaseClaim = types.BaseClaim
BaseMultiClaim = types.BaseMultiClaim
CDPHooks = types.CDPHooks
CdpKeeper = types.CdpKeeper
Claim = types.Claim
Claims = types.Claims
DelegatorClaim = types.DelegatorClaim
DelegatorClaims = types.DelegatorClaims
GenesisAccumulationTime = types.GenesisAccumulationTime
GenesisAccumulationTimes = types.GenesisAccumulationTimes
GenesisState = types.GenesisState
HARDHooks = types.HARDHooks
HardKeeper = types.HardKeeper
HardLiquidityProviderClaim = types.HardLiquidityProviderClaim
HardLiquidityProviderClaims = types.HardLiquidityProviderClaims
MsgClaimDelegatorReward = types.MsgClaimDelegatorReward
MsgClaimDelegatorRewardVVesting = types.MsgClaimDelegatorRewardVVesting
MsgClaimHardReward = types.MsgClaimHardReward
MsgClaimHardRewardVVesting = types.MsgClaimHardRewardVVesting
MsgClaimUSDXMintingReward = types.MsgClaimUSDXMintingReward
MsgClaimUSDXMintingRewardVVesting = types.MsgClaimUSDXMintingRewardVVesting
MultiRewardIndex = types.MultiRewardIndex
MultiRewardIndexes = types.MultiRewardIndexes
MultiRewardPeriod = types.MultiRewardPeriod
MultiRewardPeriods = types.MultiRewardPeriods
Multiplier = types.Multiplier
MultiplierName = types.MultiplierName
Multipliers = types.Multipliers
ParamSubspace = types.ParamSubspace
Params = types.Params
QueryGetRewardFactorsResponse = types.QueryGetRewardFactorsResponse
QueryRewardsParams = types.QueryRewardsParams
RewardIndex = types.RewardIndex
RewardIndexes = types.RewardIndexes
RewardPeriod = types.RewardPeriod
RewardPeriods = types.RewardPeriods
StakingKeeper = types.StakingKeeper
SupplyKeeper = types.SupplyKeeper
SwapClaim = types.SwapClaim
SwapClaims = types.SwapClaims
SwapKeeper = types.SwapKeeper
USDXMintingClaim = types.USDXMintingClaim
USDXMintingClaims = types.USDXMintingClaims
)

View File

@ -21,8 +21,15 @@ const (
flagType = "type"
flagUnsynced = "unsynced"
flagDenom = "denom"
typeDelegator = "delegator"
typeHard = "hard"
typeUSDXMinting = "usdx-minting"
typeSwap = "swap"
)
var rewardTypes = []string{typeDelegator, typeHard, typeUSDXMinting, typeSwap}
// GetQueryCmd returns the cli query commands for the incentive module
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
incentiveQueryCmd := &cobra.Command{
@ -52,13 +59,14 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
$ %s query %s rewards --type hard
$ %s query %s rewards --type usdx-minting
$ %s query %s rewards --type delegator
$ %s query %s rewards --type swap
$ %s query %s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw
$ %s query %s rewards --type hard --unsynced true
$ %s query %s rewards --type hard --unsynced
`,
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName,
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName,
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName,
version.ClientName, types.ModuleName)),
version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
@ -76,90 +84,52 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
}
switch strings.ToLower(strType) {
case "hard":
var claims types.HardLiquidityProviderClaims
if boolUnsynced {
params := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner)
claims, err = executeHardRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
} else {
params := types.NewQueryHardRewardsParams(page, limit, owner)
claims, err = executeHardRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
case typeHard:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
claims, err := executeHardRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
return cliCtx.PrintOutput(claims)
case "usdx-minting":
var claims types.USDXMintingClaims
if boolUnsynced {
params := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner)
claims, err = executeUSDXMintingRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
} else {
params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner)
claims, err = executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
case typeUSDXMinting:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
claims, err := executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
return cliCtx.PrintOutput(claims)
case "delegator":
var claims types.DelegatorClaims
if boolUnsynced {
params := types.NewQueryDelegatorRewardsUnsyncedParams(page, limit, owner)
claims, err = executeDelegatorRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
} else {
params := types.NewQueryDelegatorRewardsParams(page, limit, owner)
claims, err = executeDelegatorRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
case typeDelegator:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
claims, err := executeDelegatorRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
return cliCtx.PrintOutput(claims)
case typeSwap:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
claims, err := executeSwapRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
return cliCtx.PrintOutput(claims)
default:
var hardClaims types.HardLiquidityProviderClaims
var usdxMintingClaims types.USDXMintingClaims
var delegatorClaims types.DelegatorClaims
if boolUnsynced {
paramsHard := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner)
hardClaims, err = executeHardRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, paramsHard)
if err != nil {
return err
}
paramsUSDXMinting := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner)
usdxMintingClaims, err = executeUSDXMintingRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, paramsUSDXMinting)
if err != nil {
return err
}
paramsDelegator := types.NewQueryDelegatorRewardsUnsyncedParams(page, limit, owner)
delegatorClaims, err = executeDelegatorRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, paramsDelegator)
if err != nil {
return err
}
} else {
paramsHard := types.NewQueryHardRewardsParams(page, limit, owner)
hardClaims, err = executeHardRewardsQuery(queryRoute, cdc, cliCtx, paramsHard)
if err != nil {
return err
}
paramsUSDXMinting := types.NewQueryUSDXMintingRewardsParams(page, limit, owner)
usdxMintingClaims, err = executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, paramsUSDXMinting)
if err != nil {
return err
}
paramsDelegator := types.NewQueryDelegatorRewardsParams(page, limit, owner)
delegatorClaims, err = executeDelegatorRewardsQuery(queryRoute, cdc, cliCtx, paramsDelegator)
if err != nil {
return err
}
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
hardClaims, err := executeHardRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
usdxMintingClaims, err := executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
delegatorClaims, err := executeDelegatorRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
swapClaims, err := executeSwapRewardsQuery(queryRoute, cdc, cliCtx, params)
if err != nil {
return err
}
if len(hardClaims) > 0 {
cliCtx.PrintOutput(hardClaims)
@ -170,13 +140,16 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
if len(delegatorClaims) > 0 {
cliCtx.PrintOutput(delegatorClaims)
}
if len(swapClaims) > 0 {
cliCtx.PrintOutput(swapClaims)
}
}
return nil
},
}
cmd.Flags().String(flagOwner, "", "(optional) filter by owner address")
cmd.Flags().String(flagType, "", "(optional) filter by reward type")
cmd.Flags().String(flagUnsynced, "", "(optional) get unsynced claims")
cmd.Flags().String(flagType, "", fmt.Sprintf("(optional) filter by a reward type: %s", strings.Join(rewardTypes, "|")))
cmd.Flags().Bool(flagUnsynced, false, "(optional) get unsynced claims")
cmd.Flags().Int(flags.FlagPage, 1, "pagination page rewards of to to query for")
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of rewards to query for")
return cmd
@ -213,47 +186,32 @@ func queryRewardFactorsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "reward-factors",
Short: "get current global reward factors",
Long: strings.TrimSpace(`get current global reward factors:
Example:
$ kvcli q hard reward-factors
$ kvcli q hard reward-factors --denom bnb`,
),
Args: cobra.NoArgs,
Long: `Get current global reward factors for all reward types.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
denom := viper.GetString(flagDenom)
// Construct query with params
params := types.NewQueryRewardFactorsParams(denom)
bz, err := cdc.MarshalJSON(params)
if err != nil {
return err
}
// Execute query
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetRewardFactors)
res, height, err := cliCtx.QueryWithData(route, bz)
res, height, err := cliCtx.QueryWithData(route, nil)
if err != nil {
return err
}
cliCtx = cliCtx.WithHeight(height)
// Decode and print results
var rewardFactors types.RewardFactors
if err := cdc.UnmarshalJSON(res, &rewardFactors); err != nil {
var response types.QueryGetRewardFactorsResponse
if err := cdc.UnmarshalJSON(res, &response); err != nil {
return fmt.Errorf("failed to unmarshal reward factors: %w", err)
}
return cliCtx.PrintOutput(rewardFactors)
return cliCtx.PrintOutput(response)
},
}
cmd.Flags().String(flagDenom, "", "(optional) filter reward factors by denom")
return cmd
}
func executeHardRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryHardRewardsParams) (types.HardLiquidityProviderClaims, error) {
func executeHardRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryRewardsParams) (types.HardLiquidityProviderClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.HardLiquidityProviderClaims{}, err
@ -275,31 +233,7 @@ func executeHardRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context
return claims, nil
}
func executeHardRewardsUnsyncedQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryHardRewardsUnsyncedParams) (types.HardLiquidityProviderClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.HardLiquidityProviderClaims{}, err
}
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetHardRewardsUnsynced)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return types.HardLiquidityProviderClaims{}, err
}
cliCtx = cliCtx.WithHeight(height)
var claims types.HardLiquidityProviderClaims
if err := cdc.UnmarshalJSON(res, &claims); err != nil {
return types.HardLiquidityProviderClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err)
}
return claims, nil
}
func executeUSDXMintingRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryUSDXMintingRewardsParams) (types.USDXMintingClaims, error) {
func executeUSDXMintingRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryRewardsParams) (types.USDXMintingClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.USDXMintingClaims{}, err
@ -321,31 +255,7 @@ func executeUSDXMintingRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx
return claims, nil
}
func executeUSDXMintingRewardsUnsyncedQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryUSDXMintingRewardsUnsyncedParams) (types.USDXMintingClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.USDXMintingClaims{}, err
}
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetUSDXMintingRewardsUnsynced)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return types.USDXMintingClaims{}, err
}
cliCtx = cliCtx.WithHeight(height)
var claims types.USDXMintingClaims
if err := cdc.UnmarshalJSON(res, &claims); err != nil {
return types.USDXMintingClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err)
}
return claims, nil
}
func executeDelegatorRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryDelegatorRewardsParams) (types.DelegatorClaims, error) {
func executeDelegatorRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryRewardsParams) (types.DelegatorClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.DelegatorClaims{}, err
@ -367,24 +277,23 @@ func executeDelegatorRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx co
return claims, nil
}
func executeDelegatorRewardsUnsyncedQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext,
params types.QueryDelegatorRewardsUnsyncedParams) (types.DelegatorClaims, error) {
func executeSwapRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryRewardsParams) (types.SwapClaims, error) {
bz, err := cdc.MarshalJSON(params)
if err != nil {
return types.DelegatorClaims{}, err
return types.SwapClaims{}, err
}
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetDelegatorRewardsUnsynced)
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetSwapRewards)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return types.DelegatorClaims{}, err
return types.SwapClaims{}, err
}
cliCtx = cliCtx.WithHeight(height)
var claims types.DelegatorClaims
var claims types.SwapClaims
if err := cdc.UnmarshalJSON(res, &claims); err != nil {
return types.DelegatorClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err)
return types.SwapClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err)
}
return claims, nil

View File

@ -58,40 +58,18 @@ func queryRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
}
}
if unsynced {
switch strings.ToLower(rewardType) {
case "hard":
params := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner)
executeHardRewardsUnsyncedQuery(w, cliCtx, params)
case "usdx_minting":
params := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner)
executeUSDXMintingRewardsUnsyncedQuery(w, cliCtx, params)
case "delegator":
params := types.NewQueryDelegatorRewardsUnsyncedParams(page, limit, owner)
executeDelegatorRewardsUnsyncedQuery(w, cliCtx, params)
default:
hardParams := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner)
usdxMintingParams := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner)
delegatorParams := types.NewQueryDelegatorRewardsUnsyncedParams(page, limit, owner)
executeAllUnsyncedRewardQueries(w, cliCtx, hardParams, usdxMintingParams, delegatorParams)
}
} else {
switch strings.ToLower(rewardType) {
case "hard":
params := types.NewQueryHardRewardsParams(page, limit, owner)
executeHardRewardsQuery(w, cliCtx, params)
case "usdx_minting":
params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner)
executeUSDXMintingRewardsQuery(w, cliCtx, params)
case "delegator":
params := types.NewQueryDelegatorRewardsParams(page, limit, owner)
executeDelegatorRewardsQuery(w, cliCtx, params)
default:
hardParams := types.NewQueryHardRewardsParams(page, limit, owner)
usdxMintingParams := types.NewQueryUSDXMintingRewardsParams(page, limit, owner)
delegatorParams := types.NewQueryDelegatorRewardsParams(page, limit, owner)
executeAllRewardQueries(w, cliCtx, hardParams, usdxMintingParams, delegatorParams)
}
params := types.NewQueryRewardsParams(page, limit, owner, unsynced)
switch strings.ToLower(rewardType) {
case "hard":
executeHardRewardsQuery(w, cliCtx, params)
case "usdx_minting":
executeUSDXMintingRewardsQuery(w, cliCtx, params)
case "delegator":
executeDelegatorRewardsQuery(w, cliCtx, params)
case "swap":
executeSwapRewardsQuery(w, cliCtx, params)
default:
executeAllRewardQueries(w, cliCtx, params)
}
}
}
@ -118,43 +96,25 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
func queryRewardFactorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
_, _, _, err := rest.ParseHTTPArgsWithLimit(r, 0)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// Parse the query height
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
var denom string
if x := r.URL.Query().Get(RestDenom); len(x) != 0 {
denom = strings.TrimSpace(x)
}
params := types.NewQueryRewardFactorsParams(denom)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetRewardFactors)
res, height, err := cliCtx.QueryWithData(route, bz)
cliCtx = cliCtx.WithHeight(height)
res, height, err := cliCtx.QueryWithData(route, nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
}
func executeHardRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryHardRewardsParams) {
func executeHardRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryRewardsParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
@ -171,24 +131,7 @@ func executeHardRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, p
rest.PostProcessResponse(w, cliCtx, res)
}
func executeHardRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryHardRewardsUnsyncedParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardRewardsUnsynced), bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
func executeUSDXMintingRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryUSDXMintingRewardsParams) {
func executeUSDXMintingRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryRewardsParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
@ -205,24 +148,7 @@ func executeUSDXMintingRewardsQuery(w http.ResponseWriter, cliCtx context.CLICon
rest.PostProcessResponse(w, cliCtx, res)
}
func executeUSDXMintingRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryUSDXMintingRewardsUnsyncedParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetUSDXMintingRewardsUnsynced), bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
func executeDelegatorRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryDelegatorRewardsParams) {
func executeDelegatorRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryRewardsParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
@ -239,14 +165,14 @@ func executeDelegatorRewardsQuery(w http.ResponseWriter, cliCtx context.CLIConte
rest.PostProcessResponse(w, cliCtx, res)
}
func executeDelegatorRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryDelegatorRewardsUnsyncedParams) {
func executeSwapRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryRewardsParams) {
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetDelegatorRewardsUnsynced), bz)
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetSwapRewards), bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -256,16 +182,14 @@ func executeDelegatorRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.
rest.PostProcessResponse(w, cliCtx, res)
}
func executeAllRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext,
hardParams types.QueryHardRewardsParams, usdxMintingParams types.QueryUSDXMintingRewardsParams,
delegatorParams types.QueryDelegatorRewardsParams) {
hardBz, err := cliCtx.Codec.MarshalJSON(hardParams)
func executeAllRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryRewardsParams) {
paramsBz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
hardRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardRewards), hardBz)
hardRes, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardRewards), paramsBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -273,13 +197,7 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext,
var hardClaims types.HardLiquidityProviderClaims
cliCtx.Codec.MustUnmarshalJSON(hardRes, &hardClaims)
usdxMintingBz, err := cliCtx.Codec.MarshalJSON(usdxMintingParams)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
usdxMintingRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetUSDXMintingRewards), usdxMintingBz)
usdxMintingRes, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetUSDXMintingRewards), paramsBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -287,81 +205,7 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext,
var usdxMintingClaims types.USDXMintingClaims
cliCtx.Codec.MustUnmarshalJSON(usdxMintingRes, &usdxMintingClaims)
delegatorBz, err := cliCtx.Codec.MarshalJSON(delegatorParams)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
delegatorRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetDelegatorRewards), delegatorBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
var delegatorClaims types.DelegatorClaims
cliCtx.Codec.MustUnmarshalJSON(delegatorRes, &delegatorClaims)
cliCtx = cliCtx.WithHeight(height)
type rewardResult struct {
HardClaims types.HardLiquidityProviderClaims `json:"hard_claims" yaml:"hard_claims"`
UsdxMintingClaims types.USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"`
DelegatorClaims types.DelegatorClaims `json:"delegator_claims" yaml:"delegator_claims"`
}
res := rewardResult{
HardClaims: hardClaims,
UsdxMintingClaims: usdxMintingClaims,
DelegatorClaims: delegatorClaims,
}
resBz, err := cliCtx.Codec.MarshalJSON(res)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal result: %s", err))
return
}
rest.PostProcessResponse(w, cliCtx, resBz)
}
func executeAllUnsyncedRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext,
hardParams types.QueryHardRewardsUnsyncedParams, usdxMintingParams types.QueryUSDXMintingRewardsUnsyncedParams,
delegatorParams types.QueryDelegatorRewardsUnsyncedParams) {
hardBz, err := cliCtx.Codec.MarshalJSON(hardParams)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
hardRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardRewardsUnsynced), hardBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
var hardClaims types.HardLiquidityProviderClaims
cliCtx.Codec.MustUnmarshalJSON(hardRes, &hardClaims)
usdxMintingBz, err := cliCtx.Codec.MarshalJSON(usdxMintingParams)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
usdxMintingRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetUSDXMintingRewardsUnsynced), usdxMintingBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
var usdxMintingClaims types.USDXMintingClaims
cliCtx.Codec.MustUnmarshalJSON(usdxMintingRes, &usdxMintingClaims)
delegatorBz, err := cliCtx.Codec.MarshalJSON(delegatorParams)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
return
}
delegatorRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetDelegatorRewardsUnsynced), delegatorBz)
delegatorRes, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetDelegatorRewards), paramsBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -369,18 +213,28 @@ func executeAllUnsyncedRewardQueries(w http.ResponseWriter, cliCtx context.CLICo
var delegatorClaims types.DelegatorClaims
cliCtx.Codec.MustUnmarshalJSON(delegatorRes, &delegatorClaims)
swapRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetSwapRewards), paramsBz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
var swapClaims types.SwapClaims
cliCtx.Codec.MustUnmarshalJSON(swapRes, &swapClaims)
cliCtx = cliCtx.WithHeight(height)
type rewardResult struct {
HardClaims types.HardLiquidityProviderClaims `json:"hard_claims" yaml:"hard_claims"`
UsdxMintingClaims types.USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"`
DelegatorClaims types.DelegatorClaims `json:"delegator_claims" yaml:"delegator_claims"`
SwapClaims types.SwapClaims `json:"swap_claims" yaml:"swap_claims"`
}
res := rewardResult{
HardClaims: hardClaims,
UsdxMintingClaims: usdxMintingClaims,
DelegatorClaims: delegatorClaims,
SwapClaims: swapClaims,
}
resBz, err := cliCtx.Codec.MarshalJSON(res)

View File

@ -115,6 +115,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
}
k.SetDelegatorClaim(ctx, claim)
}
// TODO no synchronization of swap claims as it is about to be removed in a subsequent PR
for _, claim := range gs.SwapClaims {
k.SetSwapClaim(ctx, claim)
}
}
// ExportGenesis export genesis state for incentive module
@ -124,10 +129,12 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState {
usdxClaims := k.GetAllUSDXMintingClaims(ctx)
hardClaims := k.GetAllHardLiquidityProviderClaims(ctx)
delegatorClaims := k.GetAllDelegatorClaims(ctx)
swapClaims := k.GetAllSwapClaims(ctx)
synchronizedUsdxClaims := types.USDXMintingClaims{}
synchronizedHardClaims := types.HardLiquidityProviderClaims{}
synchronizedDelegatorClaims := types.DelegatorClaims{}
// TODO no synchronization of swap claims as it is about to be removed in a subsequent PR
for _, usdxClaim := range usdxClaims {
claim, err := k.SynchronizeUSDXMintingClaim(ctx, usdxClaim)
@ -222,7 +229,9 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState {
swapGats = append(swapGats, gat)
}
return types.NewGenesisState(params, usdxMintingGats, hardSupplyGats,
hardBorrowGats, delegatorGats, swapGats, synchronizedUsdxClaims,
synchronizedHardClaims, synchronizedDelegatorClaims)
return types.NewGenesisState(
params,
usdxMintingGats, hardSupplyGats, hardBorrowGats, delegatorGats, swapGats,
synchronizedUsdxClaims, synchronizedHardClaims, synchronizedDelegatorClaims, swapClaims,
)
}

View File

@ -77,6 +77,7 @@ func (suite *GenesisTestSuite) SetupTest() {
incentive.DefaultUSDXClaims,
incentive.DefaultHardClaims,
incentive.DefaultDelegatorClaims,
incentive.DefaultSwapClaims,
)
tApp.InitializeFromGenesisStatesWithTime(
suite.genesisTime,

View File

@ -60,6 +60,7 @@ func (suite *HandlerTestSuite) SetupTest() {
incentive.DefaultUSDXClaims,
incentive.DefaultHardClaims,
incentive.DefaultDelegatorClaims,
incentive.DefaultSwapClaims,
)
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{incentive.ModuleName: incentive.ModuleCdc.MustMarshalJSON(incentiveGS)}, NewCDPGenStateMulti(), NewPricefeedGenStateMulti())

View File

@ -6,6 +6,7 @@ import (
cdptypes "github.com/kava-labs/kava/x/cdp/types"
hardtypes "github.com/kava-labs/kava/x/hard/types"
swaptypes "github.com/kava-labs/kava/x/swap/types"
)
// Hooks wrapper struct for hooks
@ -16,6 +17,7 @@ type Hooks struct {
var _ cdptypes.CDPHooks = Hooks{}
var _ hardtypes.HARDHooks = Hooks{}
var _ stakingtypes.StakingHooks = Hooks{}
var _ swaptypes.SwapHooks = Hooks{}
// Hooks create new incentive hooks
func (k Keeper) Hooks() Hooks { return Hooks{k} }
@ -149,3 +151,13 @@ 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) {
}
// ------------------- 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)
}

View File

@ -259,6 +259,55 @@ func (k Keeper) GetAllDelegatorClaims(ctx sdk.Context) types.DelegatorClaims {
return cs
}
// GetSwapClaim returns the claim in the store corresponding the the input address.
func (k Keeper) GetSwapClaim(ctx sdk.Context, addr sdk.AccAddress) (types.SwapClaim, bool) {
store := prefix.NewStore(ctx.KVStore(k.key), types.SwapClaimKeyPrefix)
bz := store.Get(addr)
if bz == nil {
return types.SwapClaim{}, false
}
var c types.SwapClaim
k.cdc.MustUnmarshalBinaryBare(bz, &c)
return c, true
}
// SetSwapClaim sets the claim in the store corresponding to the input address.
func (k Keeper) SetSwapClaim(ctx sdk.Context, c types.SwapClaim) {
store := prefix.NewStore(ctx.KVStore(k.key), types.SwapClaimKeyPrefix)
bz := k.cdc.MustMarshalBinaryBare(c)
store.Set(c.Owner, bz)
}
// DeleteSwapClaim deletes the claim in the store corresponding to the input address.
func (k Keeper) DeleteSwapClaim(ctx sdk.Context, owner sdk.AccAddress) {
store := prefix.NewStore(ctx.KVStore(k.key), types.SwapClaimKeyPrefix)
store.Delete(owner)
}
// IterateSwapClaims iterates over all claim objects in the store and preforms a callback function
func (k Keeper) IterateSwapClaims(ctx sdk.Context, cb func(c types.SwapClaim) (stop bool)) {
store := prefix.NewStore(ctx.KVStore(k.key), types.SwapClaimKeyPrefix)
iterator := sdk.KVStorePrefixIterator(store, []byte{})
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var c types.SwapClaim
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &c)
if cb(c) {
break
}
}
}
// GetAllSwapClaims returns all Claim objects in the store
func (k Keeper) GetAllSwapClaims(ctx sdk.Context) types.SwapClaims {
cs := types.SwapClaims{}
k.IterateSwapClaims(ctx, func(c types.SwapClaim) (stop bool) {
cs = append(cs, c)
return false
})
return cs
}
// SetHardSupplyRewardIndexes sets the current reward indexes for an individual denom
func (k Keeper) SetHardSupplyRewardIndexes(ctx sdk.Context, denom string, indexes types.RewardIndexes) {
store := prefix.NewStore(ctx.KVStore(k.key), types.HardSupplyRewardIndexesKeyPrefix)
@ -428,6 +477,20 @@ func (k Keeper) GetSwapRewardIndexes(ctx sdk.Context, poolID string) (types.Rewa
return rewardIndexes, true
}
// IterateSwapRewardIndexes iterates over all swap reward index objects in the store and preforms a callback function
func (k Keeper) IterateSwapRewardIndexes(ctx sdk.Context, cb func(poolID string, indexes types.RewardIndexes) (stop bool)) {
store := prefix.NewStore(ctx.KVStore(k.key), types.SwapRewardIndexesKeyPrefix)
iterator := sdk.KVStorePrefixIterator(store, []byte{})
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var indexes types.RewardIndexes
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &indexes)
if cb(string(iterator.Key()), indexes) {
break
}
}
}
// GetSwapRewardAccrualTime fetches the last time rewards were accrued for a swap pool.
func (k Keeper) GetSwapRewardAccrualTime(ctx sdk.Context, poolID string) (blockTime time.Time, found bool) {
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousSwapRewardAccrualTimeKeyPrefix)

View File

@ -82,6 +82,46 @@ func (suite *KeeperTestSuite) TestIterateUSDXMintingClaims() {
suite.Require().Equal(len(suite.addrs), len(claims))
}
func (suite *KeeperTestSuite) TestGetSetDeleteSwapClaims() {
suite.SetupApp()
c := types.NewSwapClaim(suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes)
_, found := suite.keeper.GetSwapClaim(suite.ctx, suite.addrs[0])
suite.Require().False(found)
suite.Require().NotPanics(func() {
suite.keeper.SetSwapClaim(suite.ctx, c)
})
testC, found := suite.keeper.GetSwapClaim(suite.ctx, suite.addrs[0])
suite.Require().True(found)
suite.Require().Equal(c, testC)
suite.Require().NotPanics(func() {
suite.keeper.DeleteSwapClaim(suite.ctx, suite.addrs[0])
})
_, found = suite.keeper.GetSwapClaim(suite.ctx, suite.addrs[0])
suite.Require().False(found)
}
func (suite *KeeperTestSuite) TestIterateSwapClaims() {
suite.SetupApp()
claims := types.SwapClaims{
types.NewSwapClaim(suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes),
types.NewSwapClaim(suite.addrs[1], nil, nil), // different claim to the first
}
for _, claim := range claims {
suite.keeper.SetSwapClaim(suite.ctx, claim)
}
var actualClaims types.SwapClaims
suite.keeper.IterateSwapClaims(suite.ctx, func(c types.SwapClaim) bool {
actualClaims = append(actualClaims, c)
return false
})
suite.Require().Equal(claims, actualClaims)
}
func (suite *KeeperTestSuite) TestGetSetSwapRewardIndexes() {
testCases := []struct {
name string
@ -155,6 +195,45 @@ func (suite *KeeperTestSuite) TestGetSetSwapRewardIndexes() {
}
}
func (suite *KeeperTestSuite) TestIterateSwapRewardIndexes() {
suite.SetupApp()
multiIndexes := types.MultiRewardIndexes{
{
CollateralType: "bnb/usdx",
RewardIndexes: types.RewardIndexes{
{
CollateralType: "swap",
RewardFactor: d("0.0000002"),
},
{
CollateralType: "ukava",
RewardFactor: d("0.04"),
},
},
},
{
CollateralType: "btcb/usdx",
RewardIndexes: types.RewardIndexes{
{
CollateralType: "hard",
RewardFactor: d("0.02"),
},
},
},
}
for _, mi := range multiIndexes {
suite.keeper.SetSwapRewardIndexes(suite.ctx, mi.CollateralType, mi.RewardIndexes)
}
var actualMultiIndexes types.MultiRewardIndexes
suite.keeper.IterateSwapRewardIndexes(suite.ctx, func(poolID string, i types.RewardIndexes) bool {
actualMultiIndexes = actualMultiIndexes.With(poolID, i)
return false
})
suite.Require().Equal(multiIndexes, actualMultiIndexes)
}
func (suite *KeeperTestSuite) TestGetSetSwapRewardAccrualTimes() {
testCases := []struct {
name string

View File

@ -17,18 +17,16 @@ func NewQuerier(k Keeper) sdk.Querier {
switch path[0] {
case types.QueryGetParams:
return queryGetParams(ctx, req, k)
case types.QueryGetHardRewards:
return queryGetHardRewards(ctx, req, k)
case types.QueryGetHardRewardsUnsynced:
return queryGetHardRewardsUnsynced(ctx, req, k)
case types.QueryGetUSDXMintingRewards:
return queryGetUSDXMintingRewards(ctx, req, k)
case types.QueryGetUSDXMintingRewardsUnsynced:
return queryGetUSDXMintingRewardsUnsynced(ctx, req, k)
case types.QueryGetDelegatorRewards:
return queryGetDelegatorRewards(ctx, req, k)
case types.QueryGetDelegatorRewardsUnsynced:
return queryGetDelegatorRewardsUnsynced(ctx, req, k)
case types.QueryGetSwapRewards:
return queryGetSwapRewards(ctx, req, k)
case types.QueryGetRewardFactors:
return queryGetRewardFactors(ctx, req, k)
default:
@ -51,7 +49,7 @@ func queryGetParams(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e
}
func queryGetHardRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryHardRewardsParams
var params types.QueryRewardsParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
@ -77,45 +75,10 @@ func queryGetHardRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by
paginatedHardClaims = hardClaims[startH:endH]
}
var augmentedHardClaims types.HardLiquidityProviderClaims
for _, claim := range paginatedHardClaims {
augmentedClaim := k.SimulateHardSynchronization(ctx, claim)
augmentedHardClaims = append(augmentedHardClaims, augmentedClaim)
}
// Marshal Hard claims
bz, err := codec.MarshalJSONIndent(k.cdc, augmentedHardClaims)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryGetHardRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryHardRewardsUnsyncedParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
owner := len(params.Owner) > 0
var hardClaims types.HardLiquidityProviderClaims
switch {
case owner:
hardClaim, foundHardClaim := k.GetHardLiquidityProviderClaim(ctx, params.Owner)
if foundHardClaim {
hardClaims = append(hardClaims, hardClaim)
if !params.Unsynchronized {
for i, claim := range paginatedHardClaims {
paginatedHardClaims[i] = k.SimulateHardSynchronization(ctx, claim)
}
default:
hardClaims = k.GetAllHardLiquidityProviderClaims(ctx)
}
var paginatedHardClaims types.HardLiquidityProviderClaims
startH, endH := client.Paginate(len(hardClaims), params.Page, params.Limit, 100)
if startH < 0 || endH < 0 {
paginatedHardClaims = types.HardLiquidityProviderClaims{}
} else {
paginatedHardClaims = hardClaims[startH:endH]
}
// Marshal Hard claims
@ -127,7 +90,7 @@ func queryGetHardRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keepe
}
func queryGetUSDXMintingRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryUSDXMintingRewardsParams
var params types.QueryRewardsParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
@ -153,45 +116,10 @@ func queryGetUSDXMintingRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper
paginatedUsdxMintingClaims = usdxMintingClaims[startU:endU]
}
var augmentedUsdxMintingClaims types.USDXMintingClaims
for _, claim := range paginatedUsdxMintingClaims {
augmentedClaim := k.SimulateUSDXMintingSynchronization(ctx, claim)
augmentedUsdxMintingClaims = append(augmentedUsdxMintingClaims, augmentedClaim)
}
// Marshal USDX minting claims
bz, err := codec.MarshalJSONIndent(k.cdc, augmentedUsdxMintingClaims)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryGetUSDXMintingRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryUSDXMintingRewardsUnsyncedParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
owner := len(params.Owner) > 0
var usdxMintingClaims types.USDXMintingClaims
switch {
case owner:
usdxMintingClaim, foundUsdxMintingClaim := k.GetUSDXMintingClaim(ctx, params.Owner)
if foundUsdxMintingClaim {
usdxMintingClaims = append(usdxMintingClaims, usdxMintingClaim)
if !params.Unsynchronized {
for i, claim := range paginatedUsdxMintingClaims {
paginatedUsdxMintingClaims[i] = k.SimulateUSDXMintingSynchronization(ctx, claim)
}
default:
usdxMintingClaims = k.GetAllUSDXMintingClaims(ctx)
}
var paginatedUsdxMintingClaims types.USDXMintingClaims
startU, endU := client.Paginate(len(usdxMintingClaims), params.Page, params.Limit, 100)
if startU < 0 || endU < 0 {
paginatedUsdxMintingClaims = types.USDXMintingClaims{}
} else {
paginatedUsdxMintingClaims = usdxMintingClaims[startU:endU]
}
// Marshal USDX minting claims
@ -203,7 +131,7 @@ func queryGetUSDXMintingRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery,
}
func queryGetDelegatorRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryDelegatorRewardsParams
var params types.QueryRewardsParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
@ -229,45 +157,10 @@ func queryGetDelegatorRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper)
paginatedDelegatorClaims = delegatorClaims[startH:endH]
}
var augmentedDelegatorClaims types.DelegatorClaims
for _, claim := range paginatedDelegatorClaims {
augmentedClaim := k.SimulateDelegatorSynchronization(ctx, claim)
augmentedDelegatorClaims = append(augmentedDelegatorClaims, augmentedClaim)
}
// Marshal Hard claims
bz, err := codec.MarshalJSONIndent(k.cdc, augmentedDelegatorClaims)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryGetDelegatorRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryDelegatorRewardsUnsyncedParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
owner := len(params.Owner) > 0
var delegatorClaims types.DelegatorClaims
switch {
case owner:
delegatorClaim, foundHardClaim := k.GetDelegatorClaim(ctx, params.Owner)
if foundHardClaim {
delegatorClaims = append(delegatorClaims, delegatorClaim)
if !params.Unsynchronized {
for i, claim := range paginatedDelegatorClaims {
paginatedDelegatorClaims[i] = k.SimulateDelegatorSynchronization(ctx, claim)
}
default:
delegatorClaims = k.GetAllDelegatorClaims(ctx)
}
var paginatedDelegatorClaims types.DelegatorClaims
startH, endH := client.Paginate(len(delegatorClaims), params.Page, params.Limit, 100)
if startH < 0 || endH < 0 {
paginatedDelegatorClaims = types.DelegatorClaims{}
} else {
paginatedDelegatorClaims = delegatorClaims[startH:endH]
}
// Marshal Hard claims
@ -278,89 +171,92 @@ func queryGetDelegatorRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k
return bz, nil
}
func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryRewardFactorsParams
func queryGetSwapRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryRewardsParams
err := types.ModuleCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
owner := len(params.Owner) > 0
var rewardFactors types.RewardFactors
if len(params.Denom) > 0 {
// Fetch reward factors for a single denom
rewardFactor := types.RewardFactor{}
rewardFactor.Denom = params.Denom
var claims types.SwapClaims
switch {
case owner:
claim, found := k.GetSwapClaim(ctx, params.Owner)
if found {
claims = append(claims, claim)
}
default:
claims = k.GetAllSwapClaims(ctx)
}
usdxMintingRewardFactor, found := k.GetUSDXMintingRewardFactor(ctx, params.Denom)
if found {
rewardFactor.USDXMintingRewardFactor = usdxMintingRewardFactor
}
hardSupplyRewardIndexes, found := k.GetHardSupplyRewardIndexes(ctx, params.Denom)
if found {
rewardFactor.HardSupplyRewardFactors = hardSupplyRewardIndexes
}
hardBorrowRewardIndexes, found := k.GetHardBorrowRewardIndexes(ctx, params.Denom)
if found {
rewardFactor.HardBorrowRewardFactors = hardBorrowRewardIndexes
}
delegatorRewardIndexes, found := k.GetDelegatorRewardIndexes(ctx, params.Denom)
if found {
rewardFactor.DelegatorRewardFactors = delegatorRewardIndexes
}
rewardFactors = append(rewardFactors, rewardFactor)
var paginatedClaims types.SwapClaims
startH, endH := client.Paginate(len(claims), params.Page, params.Limit, 100)
if startH < 0 || endH < 0 {
paginatedClaims = types.SwapClaims{}
} else {
rewardFactorMap := make(map[string]types.RewardFactor)
paginatedClaims = claims[startH:endH]
}
// Populate mapping with usdx minting reward factors
k.IterateUSDXMintingRewardFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) {
rewardFactor := types.RewardFactor{Denom: denom, USDXMintingRewardFactor: factor}
rewardFactorMap[denom] = rewardFactor
return false
})
// Populate mapping with Hard supply reward factors
k.IterateHardSupplyRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
rewardFactor, ok := rewardFactorMap[denom]
if !ok {
rewardFactor = types.RewardFactor{Denom: denom, HardSupplyRewardFactors: indexes}
} else {
rewardFactor.HardSupplyRewardFactors = indexes
if !params.Unsynchronized {
for i, claim := range paginatedClaims {
syncedClaim, found := k.GetSynchronizedSwapClaim(ctx, claim.Owner)
if !found {
panic("previously found claim should still be found")
}
rewardFactorMap[denom] = rewardFactor
return false
})
// Populate mapping with Hard borrow reward factors
k.IterateHardBorrowRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
rewardFactor, ok := rewardFactorMap[denom]
if !ok {
rewardFactor = types.RewardFactor{Denom: denom, HardBorrowRewardFactors: indexes}
} else {
rewardFactor.HardBorrowRewardFactors = indexes
}
rewardFactorMap[denom] = rewardFactor
return false
})
// Populate mapping with delegator reward factors
k.IterateDelegatorRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
rewardFactor, ok := rewardFactorMap[denom]
if !ok {
rewardFactor = types.RewardFactor{Denom: denom, DelegatorRewardFactors: indexes}
} else {
rewardFactor.DelegatorRewardFactors = indexes
}
rewardFactorMap[denom] = rewardFactor
return false
})
// Translate mapping to slice
for _, val := range rewardFactorMap {
rewardFactors = append(rewardFactors, val)
paginatedClaims[i] = syncedClaim
}
}
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, rewardFactors)
// Marshal claims
bz, err := codec.MarshalJSONIndent(k.cdc, paginatedClaims)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var usdxFactors types.RewardIndexes
k.IterateUSDXMintingRewardFactors(ctx, func(collateralType string, factor sdk.Dec) (stop bool) {
usdxFactors = usdxFactors.With(collateralType, factor)
return false
})
var supplyFactors types.MultiRewardIndexes
k.IterateHardSupplyRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
supplyFactors = supplyFactors.With(denom, indexes)
return false
})
var borrowFactors types.MultiRewardIndexes
k.IterateHardBorrowRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
borrowFactors = borrowFactors.With(denom, indexes)
return false
})
var delegatorFactors types.MultiRewardIndexes
k.IterateDelegatorRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
delegatorFactors = delegatorFactors.With(denom, indexes)
return false
})
var swapFactors types.MultiRewardIndexes
k.IterateSwapRewardIndexes(ctx, func(poolID string, indexes types.RewardIndexes) (stop bool) {
swapFactors = swapFactors.With(poolID, indexes)
return false
})
response := types.NewQueryGetRewardFactorsResponse(
usdxFactors,
supplyFactors,
borrowFactors,
delegatorFactors,
swapFactors,
)
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, response)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}

View File

@ -1,6 +1,8 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/incentive/types"
@ -24,10 +26,10 @@ func (k Keeper) AccumulateSwapRewards(ctx sdk.Context, rewardPeriod types.MultiR
totalShares, found := k.swapKeeper.GetPoolShares(ctx, rewardPeriod.CollateralType)
if !found {
totalShares = sdk.ZeroDec()
totalShares = sdk.ZeroInt()
}
acc.Accumulate(rewardPeriod, totalShares, ctx.BlockTime())
acc.Accumulate(rewardPeriod, totalShares.ToDec(), ctx.BlockTime())
k.SetSwapRewardAccrualTime(ctx, rewardPeriod.CollateralType, acc.PreviousAccumulationTime)
if len(acc.Indexes) > 0 {
@ -35,3 +37,85 @@ func (k Keeper) AccumulateSwapRewards(ctx sdk.Context, rewardPeriod types.MultiR
k.SetSwapRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes)
}
}
// InitializeSwapReward creates a new claim with zero rewards and indexes matching the global indexes.
// If the claim already exists it just updates the indexes.
func (k Keeper) InitializeSwapReward(ctx sdk.Context, poolID string, owner sdk.AccAddress) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
claim = types.NewSwapClaim(owner, sdk.Coins{}, nil)
}
globalRewardIndexes, found := k.GetSwapRewardIndexes(ctx, poolID)
if !found {
globalRewardIndexes = types.RewardIndexes{}
}
claim.RewardIndexes = claim.RewardIndexes.With(poolID, globalRewardIndexes)
k.SetSwapClaim(ctx, claim)
}
// SynchronizeSwapReward updates the claim object by adding any accumulated rewards
// and updating the reward index value.
func (k Keeper) SynchronizeSwapReward(ctx sdk.Context, poolID string, owner sdk.AccAddress, shares sdk.Int) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
return
}
claim = k.synchronizeSwapReward(ctx, claim, poolID, owner, shares)
k.SetSwapClaim(ctx, claim)
}
// synchronizeSwapReward updates the reward in a swap claim for one pool.
func (k *Keeper) synchronizeSwapReward(ctx sdk.Context, claim types.SwapClaim, poolID string, owner sdk.AccAddress, shares sdk.Int) types.SwapClaim {
globalRewardIndexes, found := k.GetSwapRewardIndexes(ctx, poolID)
if !found {
// The global factor is only not found if
// - the pool has not started accumulating rewards yet (either there is no reward specified in params, or the reward start time hasn't been hit)
// - OR it was wrongly deleted from state (factors should never be removed while unsynced claims exist)
// If not found we could either skip this sync, or assume the global factor is zero.
// Skipping will avoid storing unnecessary factors in the claim for non rewarded pools.
// And in the event a global factor is wrongly deleted, it will avoid this function panicking when calculating rewards.
return claim
}
userRewardIndexes, found := claim.RewardIndexes.Get(poolID)
if !found {
// Normally the reward indexes should always be found.
// But if a pool was not rewarded then becomes rewarded (ie a reward period is added to params), then the indexes will be missing from claims for that pool.
// So given the reward period was just added, assume the starting value for any global reward indexes, which is an empty slice.
userRewardIndexes = types.RewardIndexes{}
}
newRewards, err := k.CalculateRewards(userRewardIndexes, globalRewardIndexes, shares.ToDec())
if err != nil {
// Global reward factors should never decrease, as it would lead to a negative update to claim.Rewards.
// This panics if a global reward factor decreases or disappears between the old and new indexes.
panic(fmt.Sprintf("corrupted global reward indexes found: %v", err))
}
claim.Reward = claim.Reward.Add(newRewards...)
claim.RewardIndexes = claim.RewardIndexes.With(poolID, globalRewardIndexes)
return claim
}
// GetSynchronizedSwapClaim fetches a swap claim from the store and syncs rewards for all pools.
func (k Keeper) GetSynchronizedSwapClaim(ctx sdk.Context, owner sdk.AccAddress) (types.SwapClaim, bool) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
return types.SwapClaim{}, false
}
for _, indexes := range claim.RewardIndexes {
poolID := indexes.CollateralType
shares, found := k.swapKeeper.GetDepositorSharesInPool(ctx, owner, poolID)
if !found {
shares = sdk.ZeroInt()
}
claim = k.synchronizeSwapReward(ctx, claim, poolID, owner, shares)
}
return claim, true
}

View File

@ -0,0 +1,195 @@
package keeper_test
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
"github.com/kava-labs/kava/x/incentive/types"
)
// InitializeSwapRewardTests runs unit tests for the keeper.InitializeSwapReward method
//
// inputs
// - claim in store if it exists
// - global indexes in store
//
// outputs
// - sets or creates a claim
type InitializeSwapRewardTests struct {
unitTester
}
func TestInitializeSwapReward(t *testing.T) {
suite.Run(t, new(InitializeSwapRewardTests))
}
func (suite *InitializeSwapRewardTests) TestClaimAddedWhenClaimDoesNotExistAndNoRewards() {
// When a claim doesn't exist, and a user deposits to a non-rewarded pool;
// then a claim is added with no rewards and no indexes
poolID := "base/quote"
// no global indexes stored as this pool is not rewarded
owner := arbitraryAddress()
suite.keeper.InitializeSwapReward(suite.ctx, poolID, owner)
syncedClaim, found := suite.keeper.GetSwapClaim(suite.ctx, owner)
suite.True(found)
// A new claim should have empty indexes. It doesn't strictly need the poolID either.
expectedIndexes := types.MultiRewardIndexes{{
CollateralType: poolID,
RewardIndexes: nil,
}}
suite.Equal(expectedIndexes, syncedClaim.RewardIndexes)
// a new claim should start with 0 rewards
suite.Equal(sdk.Coins(nil), syncedClaim.Reward)
}
func (suite *InitializeSwapRewardTests) TestClaimAddedWhenClaimDoesNotExistAndRewardsExist() {
// When a claim doesn't exist, and a user deposits to a rewarded pool;
// then a claim is added with no rewards and indexes matching the global indexes
poolID := "base/quote"
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
},
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
owner := arbitraryAddress()
suite.keeper.InitializeSwapReward(suite.ctx, poolID, owner)
syncedClaim, found := suite.keeper.GetSwapClaim(suite.ctx, owner)
suite.True(found)
// a new claim should start with the current global indexes
suite.Equal(globalIndexes, syncedClaim.RewardIndexes)
// a new claim should start with 0 rewards
suite.Equal(sdk.Coins(nil), syncedClaim.Reward)
}
func (suite *InitializeSwapRewardTests) TestClaimUpdatedWhenClaimExistsAndNoRewards() {
// When a claim exists, and a user deposits to a new non-rewarded pool;
// then the claim's rewards don't change
preexistingPoolID := "preexisting"
preexistingIndexes := types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
}
newPoolID := "btcb/usdx"
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: arbitraryCoins(),
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: preexistingPoolID,
RewardIndexes: preexistingIndexes,
},
},
}
suite.storeSwapClaim(claim)
// no global indexes stored as the new pool is not rewarded
suite.keeper.InitializeSwapReward(suite.ctx, newPoolID, claim.Owner)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// The preexisting indexes shouldn't be changed. It doesn't strictly need the new poolID either.
expectedIndexes := types.MultiRewardIndexes{
{
CollateralType: preexistingPoolID,
RewardIndexes: preexistingIndexes,
},
{
CollateralType: newPoolID,
RewardIndexes: nil,
},
}
suite.Equal(expectedIndexes, syncedClaim.RewardIndexes)
// init should never alter the rewards
suite.Equal(claim.Reward, syncedClaim.Reward)
}
func (suite *InitializeSwapRewardTests) TestClaimUpdatedWhenClaimExistsAndRewardsExist() {
// When a claim exists, and a user deposits to a new rewarded pool;
// then the claim's rewards don't change and the indexes are updated to match the global indexes
preexistingPoolID := "preexisting"
preexistingIndexes := types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
}
newPoolID := "btcb/usdx"
newIndexes := types.RewardIndexes{
{
CollateralType: "otherrewarddenom",
RewardFactor: d("1000.001"),
},
}
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: arbitraryCoins(),
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: preexistingPoolID,
RewardIndexes: preexistingIndexes,
},
},
}
suite.storeSwapClaim(claim)
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: preexistingPoolID,
RewardIndexes: increaseRewardFactors(preexistingIndexes),
},
{
CollateralType: newPoolID,
RewardIndexes: newIndexes,
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
suite.keeper.InitializeSwapReward(suite.ctx, newPoolID, claim.Owner)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// only the indexes for the new pool should be updated
expectedIndexes := types.MultiRewardIndexes{
{
CollateralType: preexistingPoolID,
RewardIndexes: preexistingIndexes,
},
{
CollateralType: newPoolID,
RewardIndexes: newIndexes,
},
}
suite.Equal(expectedIndexes, syncedClaim.RewardIndexes)
// init should never alter the rewards
suite.Equal(claim.Reward, syncedClaim.Reward)
}

View File

@ -0,0 +1,317 @@
package keeper_test
import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/kava-labs/kava/x/incentive/types"
)
// SynchronizeSwapRewardTests runs unit tests for the keeper.SynchronizeSwapReward method
//
// inputs
// - claim in store (only claim.RewardIndexes, claim.Reward)
// - global indexes in store
// - shares function arg
//
// outputs
// - sets a claim
type SynchronizeSwapRewardTests struct {
unitTester
}
func TestSynchronizeSwapReward(t *testing.T) {
suite.Run(t, new(SynchronizeSwapRewardTests))
}
func (suite *SynchronizeSwapRewardTests) TestClaimUpdatedWhenGlobalIndexesHaveIncreased() {
// This is the normal case
// Given some time has passed (meaning the global indexes have increased)
// When the claim is synced
// The user earns rewards for the time passed, and the claim indexes are updated
originalReward := arbitraryCoins()
poolID := "base/quote"
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: originalReward,
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
},
},
},
}
suite.storeSwapClaim(claim)
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("2000.002"),
},
},
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
userShares := i(1e9)
suite.keeper.SynchronizeSwapReward(suite.ctx, poolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// indexes updated from global
suite.Equal(globalIndexes, syncedClaim.RewardIndexes)
// new reward is (new index - old index) * user shares
suite.Equal(
cs(c("rewarddenom", 1_000_001_000_000)).Add(originalReward...),
syncedClaim.Reward,
)
}
func (suite *SynchronizeSwapRewardTests) TestClaimUnchangedWhenGlobalIndexesUnchanged() {
// It should be safe to call SynchronizeSwapReward multiple times
poolID := "base/quote"
unchangingIndexes := types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
},
},
}
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: arbitraryCoins(),
},
RewardIndexes: unchangingIndexes,
}
suite.storeSwapClaim(claim)
suite.storeGlobalSwapIndexes(unchangingIndexes)
userShares := i(1e9)
suite.keeper.SynchronizeSwapReward(suite.ctx, poolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// claim should have the same rewards and indexes as before
suite.Equal(claim, syncedClaim)
}
func (suite *SynchronizeSwapRewardTests) TestClaimUpdatedWhenNewRewardAdded() {
// When a new reward is added (via gov) for a pool the user has already deposited to, and the claim is synced;
// Then the user earns rewards for the time since the reward was added, and the indexes are added to the claim.
originalReward := arbitraryCoins()
newlyRewardPoolID := "newlyRewardedPool"
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: originalReward,
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: "currentlyRewardedPool",
RewardIndexes: types.RewardIndexes{
{
CollateralType: "reward",
RewardFactor: d("1000.001"),
},
},
},
},
}
suite.storeSwapClaim(claim)
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: "currentlyRewardedPool",
RewardIndexes: types.RewardIndexes{
{
CollateralType: "reward",
RewardFactor: d("2000.002"),
},
},
},
{
CollateralType: newlyRewardPoolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "otherreward",
// Indexes start at 0 when the reward is added by gov,
// so this represents the syncing happening some time later.
RewardFactor: d("1000.001"),
},
},
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
userShares := i(1e9)
suite.keeper.SynchronizeSwapReward(suite.ctx, newlyRewardPoolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// the new indexes should be added to the claim, but the old ones should be unchanged
newlyRewrdedIndexes, _ := globalIndexes.Get(newlyRewardPoolID)
expectedIndexes := claim.RewardIndexes.With(newlyRewardPoolID, newlyRewrdedIndexes)
suite.Equal(expectedIndexes, syncedClaim.RewardIndexes)
// new reward is (new index - old index) * shares for the synced pool
// The old index for `newlyrewarded` isn't in the claim, so it's added starting at 0 for calculating the reward.
suite.Equal(
cs(c("otherreward", 1_000_001_000_000)).Add(originalReward...),
syncedClaim.Reward,
)
}
func (suite *SynchronizeSwapRewardTests) TestClaimUnchangedWhenNoReward() {
// When a pool is not rewarded but the user has deposited to that pool, and the claim is synced;
// Then the claim should be the same.
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: arbitraryCoins(),
},
RewardIndexes: nonEmptyMultiRewardIndexes,
}
suite.storeSwapClaim(claim)
poolID := "nonRewardPool"
// No global indexes stored as this pool is not rewarded
userShares := i(1e9)
suite.keeper.SynchronizeSwapReward(suite.ctx, poolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
suite.Equal(claim, syncedClaim)
}
func (suite *SynchronizeSwapRewardTests) TestClaimUpdatedWhenNewRewardDenomAdded() {
// When a new reward coin is added (via gov) to an already rewarded pool (that the user has already deposited to), and the claim is synced;
// Then the user earns rewards for the time since the reward was added, and the new indexes are added.
originalReward := arbitraryCoins()
poolID := "base/quote"
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: originalReward,
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "reward",
RewardFactor: d("1000.001"),
},
},
},
},
}
suite.storeSwapClaim(claim)
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "reward",
RewardFactor: d("2000.002"),
},
{
CollateralType: "otherreward",
// Indexes start at 0 when the reward is added by gov,
// so this represents the syncing happening some time later.
RewardFactor: d("1000.001"),
},
},
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
userShares := i(1e9)
suite.keeper.SynchronizeSwapReward(suite.ctx, poolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// indexes should have the new reward denom added
suite.Equal(globalIndexes, syncedClaim.RewardIndexes)
// new reward is (new index - old index) * shares
// The old index for `otherreward` isn't in the claim, so it's added starting at 0 for calculating the reward.
suite.Equal(
cs(c("reward", 1_000_001_000_000), c("otherreward", 1_000_001_000_000)).Add(originalReward...),
syncedClaim.Reward,
)
}
func (suite *SynchronizeSwapRewardTests) TestClaimUpdatedWhenGlobalIndexesIncreasedAndSourceIsZero() {
// Given some time has passed (meaning the global indexes have increased)
// When the claim is synced, but the user has no shares
// The user earns no rewards for the time passed, but the claim indexes are updated
poolID := "base/quote"
claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: arbitraryAddress(),
Reward: arbitraryCoins(),
},
RewardIndexes: types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("1000.001"),
},
},
},
},
}
suite.storeSwapClaim(claim)
globalIndexes := types.MultiRewardIndexes{
{
CollateralType: poolID,
RewardIndexes: types.RewardIndexes{
{
CollateralType: "rewarddenom",
RewardFactor: d("2000.002"),
},
},
},
}
suite.storeGlobalSwapIndexes(globalIndexes)
userShares := i(0)
suite.keeper.SynchronizeSwapReward(suite.ctx, poolID, claim.Owner, userShares)
syncedClaim, _ := suite.keeper.GetSwapClaim(suite.ctx, claim.Owner)
// indexes updated from global
suite.Equal(globalIndexes, syncedClaim.RewardIndexes)
// reward is unchanged
suite.Equal(claim.Reward, syncedClaim.Reward)
}

View File

@ -31,7 +31,7 @@ func TestAccumulateSwapRewards(t *testing.T) {
}
func (suite *AccumulateSwapRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() {
swapKeeper := &fakeSwapKeeper{d("1000000")}
swapKeeper := &fakeSwapKeeper{i(1e6)}
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper)
pool := "btc/usdx"
@ -84,7 +84,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
}
func (suite *AccumulateSwapRewardsTests) TestLimitsOfAccumulationPrecision() {
swapKeeper := &fakeSwapKeeper{d("100000000000000000")} // approximate shares in a $1B pool of 10^8 precision assets
swapKeeper := &fakeSwapKeeper{i(1e17)} // approximate shares in a $1B pool of 10^8 precision ~$1 asset
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper)
pool := "btc/usdx"
@ -130,7 +130,7 @@ func (suite *AccumulateSwapRewardsTests) TestLimitsOfAccumulationPrecision() {
}
func (suite *AccumulateSwapRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() {
swapKeeper := &fakeSwapKeeper{d("1000000")}
swapKeeper := &fakeSwapKeeper{i(1e6)}
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper)
pool := "btc/usdx"
@ -182,7 +182,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
}
func (suite *AccumulateSwapRewardsTests) TestStateAddedWhenStateDoesNotExist() {
swapKeeper := &fakeSwapKeeper{d("1000000")}
swapKeeper := &fakeSwapKeeper{i(1e6)}
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper)
pool := "btc/usdx"
@ -225,7 +225,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateAddedWhenStateDoesNotExist() {
suite.checkStoredIndexesEqual(pool, expectedIndexes)
}
func (suite *AccumulateSwapRewardsTests) TestNoPanicWhenStateDoesNotExist() {
swapKeeper := &fakeSwapKeeper{d("0")}
swapKeeper := &fakeSwapKeeper{i(0)}
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper)
pool := "btc/usdx"
@ -252,12 +252,16 @@ func (suite *AccumulateSwapRewardsTests) TestNoPanicWhenStateDoesNotExist() {
}
type fakeSwapKeeper struct {
poolShares sdk.Dec
poolShares sdk.Int
}
func (k fakeSwapKeeper) GetPoolShares(ctx sdk.Context, poolID string) (sdk.Dec, bool) {
func (k fakeSwapKeeper) GetPoolShares(ctx sdk.Context, poolID string) (sdk.Int, bool) {
return k.poolShares, true
}
func (k fakeSwapKeeper) GetDepositorSharesInPool(ctx sdk.Context, depositor sdk.AccAddress, poolID string) (sdk.Int, bool) {
// This is just to implement the swap keeper interface.
return sdk.Int{}, false
}
// note: amino panics when encoding times ≥ the start of year 10000.
var distantFuture = time.Date(9000, 1, 1, 0, 0, 0, 0, time.UTC)

View File

@ -87,10 +87,12 @@ func (suite *unitTester) storeGlobalSwapIndexes(indexes types.MultiRewardIndexes
func (suite *unitTester) storeHardClaim(claim types.HardLiquidityProviderClaim) {
suite.keeper.SetHardLiquidityProviderClaim(suite.ctx, claim)
}
func (suite *unitTester) storeDelegatorClaim(claim types.DelegatorClaim) {
suite.keeper.SetDelegatorClaim(suite.ctx, claim)
}
func (suite *unitTester) storeSwapClaim(claim types.SwapClaim) {
suite.keeper.SetSwapClaim(suite.ctx, claim)
}
type fakeParamSubspace struct {
params types.Params

View File

@ -12,6 +12,7 @@ const (
USDXMintingClaimType = "usdx_minting"
HardLiquidityProviderClaimType = "hard_liquidity_provider"
DelegatorClaimType = "delegator_claim"
SwapClaimType = "swap"
BondDenom = "ukava"
)
@ -314,6 +315,71 @@ func (cs DelegatorClaims) Validate() error {
return nil
}
// 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"`
}
// NewSwapClaim returns a new SwapClaim
func NewSwapClaim(owner sdk.AccAddress, rewards sdk.Coins, rewardIndexes MultiRewardIndexes) SwapClaim {
return SwapClaim{
BaseMultiClaim: BaseMultiClaim{
Owner: owner,
Reward: rewards,
},
RewardIndexes: rewardIndexes,
}
}
// GetType returns the claim's type
func (c SwapClaim) GetType() string { return SwapClaimType }
// GetReward returns the claim's reward coin
func (c SwapClaim) GetReward() sdk.Coins { return c.Reward }
// GetOwner returns the claim's owner
func (c SwapClaim) GetOwner() sdk.AccAddress { return c.Owner }
// Validate performs a basic check of a SwapClaim fields
func (c SwapClaim) Validate() error {
if err := c.RewardIndexes.Validate(); err != nil {
return err
}
return c.BaseMultiClaim.Validate()
}
// String implements fmt.Stringer
func (c SwapClaim) String() string {
return fmt.Sprintf(`%s
Reward Indexes: %s,
`, c.BaseMultiClaim, c.RewardIndexes)
}
// HasRewardIndex check if a claim has a reward index for the input pool ID.
func (c SwapClaim) HasRewardIndex(poolID string) (int64, bool) {
for index, ri := range c.RewardIndexes {
if ri.CollateralType == poolID {
return int64(index), true
}
}
return 0, false
}
// SwapClaims slice of SwapClaim
type SwapClaims []SwapClaim
// Validate checks if all the claims are valid.
func (cs SwapClaims) Validate() error {
for _, c := range cs {
if err := c.Validate(); err != nil {
return err
}
}
return nil
}
// ---------------------- Reward indexes are used internally in the store ----------------------
// RewardIndex stores reward accumulation information

View File

@ -18,67 +18,125 @@ func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amo
// c is a helper function for created sdk.Coins types in tests
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
func TestClaimsValidate(t *testing.T) {
func TestClaims_Validate(t *testing.T) {
owner := sdk.AccAddress(crypto.AddressHash([]byte("KavaTestUser1")))
testCases := []struct {
msg string
claims USDXMintingClaims
expPass bool
}{
{
"valid",
USDXMintingClaims{
NewUSDXMintingClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), RewardIndexes{NewRewardIndex("bnb-a", sdk.ZeroDec())}),
},
true,
},
{
"invalid owner",
USDXMintingClaims{
USDXMintingClaim{
BaseClaim: BaseClaim{
Owner: nil,
},
},
},
false,
},
{
"invalid reward",
USDXMintingClaims{
{
BaseClaim: BaseClaim{
Owner: owner,
Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
},
},
},
false,
},
{
"invalid collateral type",
USDXMintingClaims{
{
BaseClaim: BaseClaim{
Owner: owner,
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
},
RewardIndexes: []RewardIndex{{"", sdk.ZeroDec()}},
},
},
false,
},
}
t.Run("USDXMintingClaims", func(t *testing.T) {
for _, tc := range testCases {
err := tc.claims.Validate()
if tc.expPass {
require.NoError(t, err, tc.msg)
} else {
require.Error(t, err, tc.msg)
testCases := []struct {
name string
claims USDXMintingClaims
expPass bool
}{
{
"valid",
USDXMintingClaims{
NewUSDXMintingClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), RewardIndexes{NewRewardIndex("bnb-a", sdk.ZeroDec())}),
},
true,
},
{
"invalid owner",
USDXMintingClaims{
USDXMintingClaim{
BaseClaim: BaseClaim{
Owner: nil,
},
},
},
false,
},
{
"invalid reward",
USDXMintingClaims{
{
BaseClaim: BaseClaim{
Owner: owner,
Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
},
},
},
false,
},
{
"invalid collateral type",
USDXMintingClaims{
{
BaseClaim: BaseClaim{
Owner: owner,
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
},
RewardIndexes: []RewardIndex{{"", sdk.ZeroDec()}},
},
},
false,
},
}
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.claims.Validate()
if tc.expPass {
require.NoError(t, err)
} else {
require.Error(t, err)
}
})
}
})
t.Run("SwapClaims", func(t *testing.T) {
validRewardIndexes := RewardIndexes{}.With("swap", d("0.002"))
validMultiRewardIndexes := MultiRewardIndexes{}.With("btcb/usdx", validRewardIndexes)
invalidRewardIndexes := RewardIndexes{}.With("swap", d("-0.002"))
invalidMultiRewardIndexes := MultiRewardIndexes{}.With("btcb/usdx", invalidRewardIndexes)
testCases := []struct {
name string
claims SwapClaims
expPass bool
}{
{
name: "valid",
claims: SwapClaims{
NewSwapClaim(owner, cs(c("bnb", 1)), validMultiRewardIndexes),
},
expPass: true,
},
{
name: "invalid owner",
claims: SwapClaims{
NewSwapClaim(nil, cs(c("bnb", 1)), validMultiRewardIndexes),
},
expPass: false,
},
{
name: "invalid reward",
claims: SwapClaims{
NewSwapClaim(owner, sdk.Coins{sdk.Coin{Denom: "invalid😫"}}, validMultiRewardIndexes),
},
expPass: false,
},
{
name: "invalid indexes",
claims: SwapClaims{
NewSwapClaim(nil, cs(c("bnb", 1)), invalidMultiRewardIndexes),
},
expPass: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.claims.Validate()
if tc.expPass {
require.NoError(t, err)
} else {
require.Error(t, err)
}
})
}
})
}
func TestRewardIndexes(t *testing.T) {

View File

@ -53,7 +53,8 @@ type HardKeeper interface {
// SwapKeeper defines the required methods needed by this modules keeper
type SwapKeeper interface {
GetPoolShares(ctx sdk.Context, poolID string) (shares sdk.Dec, found bool)
GetPoolShares(ctx sdk.Context, poolID string) (shares sdk.Int, found bool)
GetDepositorSharesInPool(ctx sdk.Context, depositor sdk.AccAddress, poolID string) (shares sdk.Int, found bool)
}
// AccountKeeper defines the expected keeper interface for interacting with account

View File

@ -17,11 +17,12 @@ type GenesisState struct {
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"`
}
// NewGenesisState returns a new genesis state
func NewGenesisState(params Params, usdxAccumTimes, hardSupplyAccumTimes, hardBorrowAccumTimes, delegatorAccumTimes,
swapAccumTimes GenesisAccumulationTimes, c USDXMintingClaims, hc HardLiquidityProviderClaims, dc DelegatorClaims) GenesisState {
swapAccumTimes GenesisAccumulationTimes, c USDXMintingClaims, hc HardLiquidityProviderClaims, dc DelegatorClaims, sc SwapClaims) GenesisState {
return GenesisState{
Params: params,
USDXAccumulationTimes: usdxAccumTimes,
@ -32,6 +33,7 @@ func NewGenesisState(params Params, usdxAccumTimes, hardSupplyAccumTimes, hardBo
USDXMintingClaims: c,
HardLiquidityProviderClaims: hc,
DelegatorClaims: dc,
SwapClaims: sc,
}
}
@ -47,6 +49,7 @@ func DefaultGenesisState() GenesisState {
USDXMintingClaims: DefaultUSDXClaims,
HardLiquidityProviderClaims: DefaultHardClaims,
DelegatorClaims: DefaultDelegatorClaims,
SwapClaims: DefaultSwapClaims,
}
}
@ -72,13 +75,16 @@ func (gs GenesisState) Validate() error {
return err
}
if err := gs.HardLiquidityProviderClaims.Validate(); err != nil {
return err
}
if err := gs.USDXMintingClaims.Validate(); err != nil {
return err
}
return gs.DelegatorClaims.Validate()
if err := gs.HardLiquidityProviderClaims.Validate(); err != nil {
return err
}
if err := gs.DelegatorClaims.Validate(); err != nil {
return err
}
return gs.SwapClaims.Validate()
}
// Equal checks whether two gov GenesisState structs are equivalent

View File

@ -141,6 +141,7 @@ func TestGenesisStateValidate(t *testing.T) {
tc.args.claims,
DefaultHardClaims,
DefaultDelegatorClaims,
DefaultSwapClaims,
)
err := gs.Validate()
if tc.errArgs.expectPass {

View File

@ -34,8 +34,9 @@ var (
DelegatorClaimKeyPrefix = []byte{0x09} // prefix for keys that store delegator claims
DelegatorRewardIndexesKeyPrefix = []byte{0x10} // prefix for key that stores delegator reward indexes
PreviousDelegatorRewardAccrualTimeKeyPrefix = []byte{0x11} // prefix for key that stores the previous time delegator rewards accrued
SwapRewardIndexesKeyPrefix = []byte{0x12} // prefix for key that stores swap reward indexes
PreviousSwapRewardAccrualTimeKeyPrefix = []byte{0x13} // prefix for key that stores the previous time swap rewards accrued
SwapClaimKeyPrefix = []byte{0x12} // prefix for keys that store swap claims
SwapRewardIndexesKeyPrefix = []byte{0x13} // prefix for key that stores swap reward indexes
PreviousSwapRewardAccrualTimeKeyPrefix = []byte{0x14} // prefix for key that stores the previous time swap rewards accrued
USDXMintingRewardDenom = "ukava"
HardLiquidityRewardDenom = "hard"

View File

@ -38,6 +38,7 @@ var (
DefaultUSDXClaims = USDXMintingClaims{}
DefaultHardClaims = HardLiquidityProviderClaims{}
DefaultDelegatorClaims = DelegatorClaims{}
DefaultSwapClaims = SwapClaims{}
DefaultGenesisAccumulationTimes = GenesisAccumulationTimes{}
DefaultClaimEnd = tmtime.Canonical(time.Unix(1, 0))
GovDenom = cdptypes.DefaultGovDenom

View File

@ -6,169 +6,54 @@ import (
// Querier routes for the incentive module
const (
QueryGetRewards = "rewards"
QueryGetHardRewards = "hard-rewards"
QueryGetHardRewardsUnsynced = "hard-rewards-unsynced"
QueryGetUSDXMintingRewards = "usdx-minting-rewards"
QueryGetUSDXMintingRewardsUnsynced = "usdx-minting-rewards-unsynced"
QueryGetDelegatorRewards = "delegator-rewards"
QueryGetDelegatorRewardsUnsynced = "delegator-rewards-unsynced"
QueryGetRewardFactors = "reward-factors"
QueryGetParams = "parameters"
QueryGetRewardPeriods = "reward-periods"
QueryGetClaimPeriods = "claim-periods"
RestClaimCollateralType = "collateral_type"
RestClaimOwner = "owner"
RestClaimType = "type"
RestUnsynced = "unsynced"
QueryGetHardRewards = "hard-rewards"
QueryGetUSDXMintingRewards = "usdx-minting-rewards"
QueryGetDelegatorRewards = "delegator-rewards"
QueryGetSwapRewards = "swap-rewards"
QueryGetRewardFactors = "reward-factors"
QueryGetParams = "parameters"
RestClaimCollateralType = "collateral_type"
RestClaimOwner = "owner"
RestClaimType = "type"
RestUnsynced = "unsynced"
)
// QueryRewardsParams params for query /incentive/rewards
// QueryRewardsParams params for query /incentive/rewards/<claim type>
type QueryRewardsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
Type string
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
Unsynchronized bool `json:"unsynchronized" yaml:"unsynchronized"`
}
// NewQueryRewardsParams returns QueryRewardsParams
func NewQueryRewardsParams(page, limit int, owner sdk.AccAddress, rewardType string) QueryRewardsParams {
func NewQueryRewardsParams(page, limit int, owner sdk.AccAddress, unsynchronized bool) QueryRewardsParams {
return QueryRewardsParams{
Page: page,
Limit: limit,
Owner: owner,
Type: rewardType,
Page: page,
Limit: limit,
Owner: owner,
Unsynchronized: unsynchronized,
}
}
// QueryUSDXMintingRewardsParams params for query /incentive/rewards type usdx-minting
type QueryUSDXMintingRewardsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
// QueryGetRewardFactorsResponse holds the response to a reward factor query
type QueryGetRewardFactorsResponse struct {
USDXMintingRewardFactors RewardIndexes `json:"usdx_minting_reward_factors" yaml:"usdx_minting_reward_factors"`
HardSupplyRewardFactors MultiRewardIndexes `json:"hard_supply_reward_factors" yaml:"hard_supply_reward_factors"`
HardBorrowRewardFactors MultiRewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"`
DelegatorRewardFactors MultiRewardIndexes `json:"delegator_reward_factors" yaml:"delegator_reward_factors"`
SwapRewardFactors MultiRewardIndexes `json:"swap_reward_factors" yaml:"swap_reward_factors"`
}
// NewQueryUSDXMintingRewardsParams returns QueryUSDXMintingRewardsParams
func NewQueryUSDXMintingRewardsParams(page, limit int, owner sdk.AccAddress) QueryUSDXMintingRewardsParams {
return QueryUSDXMintingRewardsParams{
Page: page,
Limit: limit,
Owner: owner,
// NewQueryGetRewardFactorsResponse returns a new instance of QueryAllRewardFactorsResponse
func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFactors,
hardBorrowFactors, delegatorFactors, swapFactors MultiRewardIndexes) QueryGetRewardFactorsResponse {
return QueryGetRewardFactorsResponse{
USDXMintingRewardFactors: usdxMintingFactors,
HardSupplyRewardFactors: supplyFactors,
HardBorrowRewardFactors: hardBorrowFactors,
DelegatorRewardFactors: delegatorFactors,
SwapRewardFactors: swapFactors,
}
}
// QueryUSDXMintingRewardsUnsyncedParams params for query unsynced /incentive/rewards type usdx-minting
type QueryUSDXMintingRewardsUnsyncedParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
}
// NewQueryUSDXMintingRewardsUnsyncedParams returns QueryUSDXMintingRewardsUnsyncedParams
func NewQueryUSDXMintingRewardsUnsyncedParams(page, limit int, owner sdk.AccAddress) QueryUSDXMintingRewardsUnsyncedParams {
return QueryUSDXMintingRewardsUnsyncedParams{
Page: page,
Limit: limit,
Owner: owner,
}
}
// QueryHardRewardsParams params for query /incentive/rewards type hard
type QueryHardRewardsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
}
// NewQueryHardRewardsParams returns QueryHardRewardsParams
func NewQueryHardRewardsParams(page, limit int, owner sdk.AccAddress) QueryHardRewardsParams {
return QueryHardRewardsParams{
Page: page,
Limit: limit,
Owner: owner,
}
}
// QueryHardRewardsUnsyncedParams params for query unsynced /incentive/rewards type hard
type QueryHardRewardsUnsyncedParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
}
// NewQueryHardRewardsUnsyncedParams returns QueryHardRewardsUnsyncedParams
func NewQueryHardRewardsUnsyncedParams(page, limit int, owner sdk.AccAddress) QueryHardRewardsUnsyncedParams {
return QueryHardRewardsUnsyncedParams{
Page: page,
Limit: limit,
Owner: owner,
}
}
// QueryRewardFactorsParams is the params for a filtered reward factors query
type QueryRewardFactorsParams struct {
Denom string `json:"denom" yaml:"denom"`
}
// NewQueryRewardFactorsParams creates a new QueryRewardFactorsParams
func NewQueryRewardFactorsParams(denom string) QueryRewardFactorsParams {
return QueryRewardFactorsParams{
Denom: denom,
}
}
// QueryDelegatorRewardsParams params for query /incentive/rewards type delegator
type QueryDelegatorRewardsParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
}
// NewQueryDelegatorRewardsParams returns QueryDelegatorRewardsParams
func NewQueryDelegatorRewardsParams(page, limit int, owner sdk.AccAddress) QueryDelegatorRewardsParams {
return QueryDelegatorRewardsParams{
Page: page,
Limit: limit,
Owner: owner,
}
}
// QueryDelegatorRewardsUnsyncedParams params for query unsynced /incentive/rewards type delegator
type QueryDelegatorRewardsUnsyncedParams struct {
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
Owner sdk.AccAddress
}
// NewQueryDelegatorRewardsUnsyncedParams returns QueryDelegatorRewardsUnsyncedParams
func NewQueryDelegatorRewardsUnsyncedParams(page, limit int, owner sdk.AccAddress) QueryDelegatorRewardsUnsyncedParams {
return QueryDelegatorRewardsUnsyncedParams{
Page: page,
Limit: limit,
Owner: owner,
}
}
// RewardFactor is a unique type returned by reward factor queries
type RewardFactor struct {
Denom string `json:"denom" yaml:"denom"`
USDXMintingRewardFactor sdk.Dec `json:"usdx_minting_reward_factor" yaml:"usdx_minting_reward_factor"`
HardSupplyRewardFactors RewardIndexes `json:"hard_supply_reward_factors" yaml:"hard_supply_reward_factors"`
HardBorrowRewardFactors RewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"`
DelegatorRewardFactors RewardIndexes `json:"delegator_reward_factors" yaml:"delegator_reward_factors"`
}
// NewRewardFactor returns a new instance of RewardFactor
func NewRewardFactor(denom string, usdxMintingRewardFactor sdk.Dec, hardSupplyRewardFactors,
hardBorrowRewardFactors, delegatorRewardFactors RewardIndexes) RewardFactor {
return RewardFactor{
Denom: denom,
USDXMintingRewardFactor: usdxMintingRewardFactor,
HardSupplyRewardFactors: hardSupplyRewardFactors,
HardBorrowRewardFactors: hardBorrowRewardFactors,
DelegatorRewardFactors: delegatorRewardFactors,
}
}
// RewardFactors is a slice of RewardFactor
type RewardFactors = []RewardFactor

View File

@ -2,9 +2,35 @@ package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/swap/types"
)
func (k Keeper) GetPoolShares(ctx sdk.Context, poolID string) (sdk.Dec, bool) {
func (k Keeper) GetPoolShares(ctx sdk.Context, poolID string) (sdk.Int, bool) {
// FIXME return pool shares once merged with acceptance branch
return sdk.Dec{}, false
return sdk.Int{}, false
}
func (k *Keeper) GetDepositorSharesInPool(ctx sdk.Context, depositor sdk.AccAddress, poolID string) (sdk.Int, bool) {
// FIXME return depositor shares once merged with acceptance branch
return sdk.Int{}, false
}
// Implements SwapHooks interface
var _ types.SwapHooks = Keeper{}
// FIXME call hooks within pool logic
// AfterPoolDepositCreated - call hook if registered
func (k Keeper) AfterPoolDepositCreated(ctx sdk.Context, poolID string, depositor sdk.AccAddress, sharesOwned sdk.Int) {
if k.hooks != nil {
k.hooks.AfterPoolDepositCreated(ctx, poolID, depositor, sharesOwned)
}
}
// BeforePoolDepositModified - call hook if registered
func (k Keeper) BeforePoolDepositModified(ctx sdk.Context, poolID string, depositor sdk.AccAddress, sharesOwned sdk.Int) {
if k.hooks != nil {
k.hooks.BeforePoolDepositModified(ctx, poolID, depositor, sharesOwned)
}
}

View File

@ -14,6 +14,7 @@ type Keeper struct {
key sdk.StoreKey
cdc *codec.Codec
paramSubspace subspace.Subspace
hooks types.SwapHooks
accountKeeper types.AccountKeeper
supplyKeeper types.SupplyKeeper
}
@ -39,6 +40,15 @@ func NewKeeper(
}
}
// SetHooks adds hooks to the keeper.
func (k *Keeper) SetHooks(sh types.SwapHooks) *Keeper {
if k.hooks != nil {
panic("cannot set swap hooks twice")
}
k.hooks = sh
return k
}
// GetParams returns the params from the store
func (k Keeper) GetParams(ctx sdk.Context) types.Params {
var p types.Params

View File

@ -1,4 +1,4 @@
package types // noalias
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
@ -20,3 +20,9 @@ type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
SetAccount(ctx sdk.Context, acc authexported.Account)
}
// SwapHooks are event hooks called when a user's deposit to a swap pool changes.
type SwapHooks interface {
AfterPoolDepositCreated(ctx sdk.Context, poolID string, depositor sdk.AccAddress, sharedOwned sdk.Int)
BeforePoolDepositModified(ctx sdk.Context, poolID string, depositor sdk.AccAddress, sharedOwned sdk.Int)
}