Incentive module: claim savings reward (#1208)

* update savings module macc balances getter

* add savings keeper to incentive module

* add savings keeper to incentive module #2

* savings reward syncing

* claim savings reward

* update txs, queries

* update txs, queries #2

* update claim test

* add savings keeper to incentive module in app.go

* re-commit files to disk

* fix: replace swap with savings when querying savings rewards

* update func comment

Co-authored-by: karzak <kjydavis3@gmail.com>
This commit is contained in:
Denali Marsh 2022-04-20 13:08:57 +02:00 committed by GitHub
parent db5e839079
commit c2e53f2d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 334 additions and 68 deletions

View File

@ -526,6 +526,13 @@ func NewApp(
app.pricefeedKeeper, app.pricefeedKeeper,
app.auctionKeeper, app.auctionKeeper,
) )
savingsKeeper := savingskeeper.NewKeeper(
appCodec,
keys[savingstypes.StoreKey],
savingsSubspace,
app.accountKeeper,
app.bankKeeper,
)
app.incentiveKeeper = incentivekeeper.NewKeeper( app.incentiveKeeper = incentivekeeper.NewKeeper(
appCodec, appCodec,
keys[incentivetypes.StoreKey], keys[incentivetypes.StoreKey],
@ -536,13 +543,7 @@ func NewApp(
app.accountKeeper, app.accountKeeper,
app.stakingKeeper, app.stakingKeeper,
&swapKeeper, &swapKeeper,
) &savingsKeeper,
savingsKeeper := savingskeeper.NewKeeper(
appCodec,
keys[savingstypes.StoreKey],
savingsSubspace,
app.accountKeeper,
app.bankKeeper,
) )
// create committee keeper with router // create committee keeper with router
committeeGovRouter := govtypes.NewRouter() committeeGovRouter := govtypes.NewRouter()

View File

@ -24,6 +24,7 @@ const (
typeHard = "hard" typeHard = "hard"
typeUSDXMinting = "usdx-minting" typeUSDXMinting = "usdx-minting"
typeSwap = "swap" typeSwap = "swap"
typeSavings = "savings"
) )
var rewardTypes = []string{typeDelegator, typeHard, typeUSDXMinting, typeSwap} var rewardTypes = []string{typeDelegator, typeHard, typeUSDXMinting, typeSwap}
@ -64,13 +65,15 @@ func queryRewardsCmd() *cobra.Command {
$ %s query %s rewards --type usdx-minting $ %s query %s rewards --type usdx-minting
$ %s query %s rewards --type delegator $ %s query %s rewards --type delegator
$ %s query %s rewards --type swap $ %s query %s rewards --type swap
$ %s query %s rewards --type savings
$ %s query %s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw $ %s query %s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw
$ %s query %s rewards --type hard --unsynced $ %s query %s rewards --type hard --unsynced
`, `,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
version.AppName, types.ModuleName, version.AppName, types.ModuleName)), version.AppName, types.ModuleName, version.AppName, types.ModuleName,
version.AppName, types.ModuleName)),
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx, err := client.GetClientQueryContext(cmd) cliCtx, err := client.GetClientQueryContext(cmd)
@ -121,6 +124,13 @@ func queryRewardsCmd() *cobra.Command {
return err return err
} }
return cliCtx.PrintObjectLegacy(claims) return cliCtx.PrintObjectLegacy(claims)
case typeSavings:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
claims, err := executeSavingsRewardsQuery(cliCtx, params)
if err != nil {
return err
}
return cliCtx.PrintObjectLegacy(claims)
default: default:
params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced) params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced)
@ -140,6 +150,10 @@ func queryRewardsCmd() *cobra.Command {
if err != nil { if err != nil {
return err return err
} }
savingsClaims, err := executeSavingsRewardsQuery(cliCtx, params)
if err != nil {
return err
}
if len(hardClaims) > 0 { if len(hardClaims) > 0 {
if err := cliCtx.PrintObjectLegacy(hardClaims); err != nil { if err := cliCtx.PrintObjectLegacy(hardClaims); err != nil {
return err return err
@ -160,6 +174,11 @@ func queryRewardsCmd() *cobra.Command {
return err return err
} }
} }
if len(savingsClaims) > 0 {
if err := cliCtx.PrintObjectLegacy(savingsClaims); err != nil {
return err
}
}
} }
return nil return nil
}, },
@ -321,3 +340,25 @@ func executeSwapRewardsQuery(cliCtx client.Context, params types.QueryRewardsPar
return claims, nil return claims, nil
} }
func executeSavingsRewardsQuery(cliCtx client.Context, params types.QueryRewardsParams) (types.SavingsClaims, error) {
bz, err := cliCtx.LegacyAmino.MarshalJSON(params)
if err != nil {
return types.SavingsClaims{}, err
}
route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetSavingsRewards)
res, height, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return types.SavingsClaims{}, err
}
cliCtx = cliCtx.WithHeight(height)
var claims types.SavingsClaims
if err := cliCtx.LegacyAmino.UnmarshalJSON(res, &claims); err != nil {
return types.SavingsClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err)
}
return claims, nil
}

View File

@ -29,6 +29,7 @@ func GetTxCmd() *cobra.Command {
getCmdClaimHard(), getCmdClaimHard(),
getCmdClaimDelegator(), getCmdClaimDelegator(),
getCmdClaimSwap(), getCmdClaimSwap(),
getCmdClaimSavings(),
} }
for _, cmd := range cmds { for _, cmd := range cmds {
@ -172,3 +173,38 @@ func getCmdClaimSwap() *cobra.Command {
} }
return cmd return cmd
} }
func getCmdClaimSavings() *cobra.Command {
var denomsToClaim map[string]string
cmd := &cobra.Command{
Use: "claim-savings",
Short: "claim sender's savings rewards using given multipliers",
Long: `Claim sender's outstanding savings rewards using given multipliers`,
Example: strings.Join([]string{
fmt.Sprintf(` $ %s tx %s claim-savings --%s swp=large --%s ukava=small`, version.AppName, types.ModuleName, multiplierFlag, multiplierFlag),
fmt.Sprintf(` $ %s tx %s claim-savings --%s swp=large,ukava=small`, version.AppName, types.ModuleName, multiplierFlag),
}, "\n"),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
sender := cliCtx.GetFromAddress()
selections := types.NewSelectionsFromMap(denomsToClaim)
msg := types.NewMsgClaimSavingsReward(sender.String(), selections)
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), &msg)
},
}
cmd.Flags().StringToStringVarP(&denomsToClaim, multiplierFlag, multiplierFlagShort, nil, "specify the denoms to claim, each with a multiplier lockup")
if err := cmd.MarkFlagRequired(multiplierFlag); err != nil {
panic(err)
}
return cmd
}

View File

@ -210,6 +210,49 @@ func (k Keeper) ClaimSwapReward(ctx sdk.Context, owner, receiver sdk.AccAddress,
// ClaimSavingsReward is a stub method for MsgServer interface compliance // ClaimSavingsReward is a stub method for MsgServer interface compliance
func (k Keeper) ClaimSavingsReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error { func (k Keeper) ClaimSavingsReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error {
// TODO: implement savings claim logic multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}
claimEnd := k.GetClaimEnd(ctx)
if ctx.BlockTime().After(claimEnd) {
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd)
}
k.SynchronizeSavingsClaim(ctx, owner)
syncedClaim, found := k.GetSavingsClaim(ctx, owner)
if !found {
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", owner)
}
amt := syncedClaim.Reward.AmountOf(denom)
claimingCoins := sdk.NewCoins(sdk.NewCoin(denom, amt))
rewardCoins := sdk.NewCoins(sdk.NewCoin(denom, amt.ToDec().Mul(multiplier.Factor).RoundInt()))
if rewardCoins.IsZero() {
return types.ErrZeroClaim
}
length := k.GetPeriodLength(ctx.BlockTime(), multiplier.MonthsLockup)
err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, receiver, rewardCoins, length)
if err != nil {
return err
}
// remove claimed coins (NOT reward coins)
syncedClaim.Reward = syncedClaim.Reward.Sub(claimingCoins)
k.SetSavingsClaim(ctx, syncedClaim)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeClaim,
sdk.NewAttribute(types.AttributeKeyClaimedBy, owner.String()),
sdk.NewAttribute(types.AttributeKeyClaimAmount, claimingCoins.String()),
sdk.NewAttribute(types.AttributeKeyClaimType, syncedClaim.GetType()),
),
)
return nil return nil
} }

View File

@ -36,7 +36,7 @@ func (suite *ClaimTests) TestCannotClaimWhenMultiplierNotRecognised() {
}, },
}, },
} }
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -70,7 +70,7 @@ func (suite *ClaimTests) TestCannotClaimAfterEndTime() {
ClaimEnd: endTime, ClaimEnd: endTime,
}, },
} }
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil)
suite.ctx = suite.ctx.WithBlockTime(endTime.Add(time.Nanosecond)) suite.ctx = suite.ctx.WithBlockTime(endTime.Add(time.Nanosecond))

View File

@ -21,13 +21,14 @@ type Keeper struct {
hardKeeper types.HardKeeper hardKeeper types.HardKeeper
stakingKeeper types.StakingKeeper stakingKeeper types.StakingKeeper
swapKeeper types.SwapKeeper swapKeeper types.SwapKeeper
savingsKeeper types.SavingsKeeper
} }
// NewKeeper creates a new keeper // NewKeeper creates a new keeper
func NewKeeper( func NewKeeper(
cdc codec.Codec, key sdk.StoreKey, paramstore types.ParamSubspace, bk types.BankKeeper, cdc codec.Codec, key sdk.StoreKey, paramstore types.ParamSubspace, bk types.BankKeeper,
cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper,
swpk types.SwapKeeper, swpk types.SwapKeeper, svk types.SavingsKeeper,
) Keeper { ) Keeper {
if !paramstore.HasKeyTable() { if !paramstore.HasKeyTable() {
@ -44,6 +45,7 @@ func NewKeeper(
hardKeeper: hk, hardKeeper: hk,
stakingKeeper: stk, stakingKeeper: stk,
swapKeeper: swpk, swapKeeper: swpk,
savingsKeeper: svk,
} }
} }

View File

@ -25,7 +25,8 @@ func NewQuerier(k Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
return queryGetDelegatorRewards(ctx, req, k, legacyQuerierCdc) return queryGetDelegatorRewards(ctx, req, k, legacyQuerierCdc)
case types.QueryGetSwapRewards: case types.QueryGetSwapRewards:
return queryGetSwapRewards(ctx, req, k, legacyQuerierCdc) return queryGetSwapRewards(ctx, req, k, legacyQuerierCdc)
case types.QueryGetSavingsRewards:
return queryGetSavingsRewards(ctx, req, k, legacyQuerierCdc)
case types.QueryGetRewardFactors: case types.QueryGetRewardFactors:
return queryGetRewardFactors(ctx, req, k, legacyQuerierCdc) return queryGetRewardFactors(ctx, req, k, legacyQuerierCdc)
default: default:
@ -215,6 +216,51 @@ func queryGetSwapRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper, legac
return bz, nil return bz, nil
} }
func queryGetSavingsRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var params types.QueryRewardsParams
err := legacyQuerierCdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
owner := len(params.Owner) > 0
var claims types.SavingsClaims
switch {
case owner:
claim, found := k.GetSavingsClaim(ctx, params.Owner)
if found {
claims = append(claims, claim)
}
default:
claims = k.GetAllSavingsClaims(ctx)
}
var paginatedClaims types.SavingsClaims
startH, endH := client.Paginate(len(claims), params.Page, params.Limit, 100)
if startH < 0 || endH < 0 {
paginatedClaims = types.SavingsClaims{}
} else {
paginatedClaims = claims[startH:endH]
}
if !params.Unsynchronized {
for i, claim := range paginatedClaims {
syncedClaim, found := k.GetSynchronizedSavingsClaim(ctx, claim.Owner)
if !found {
panic("previously found claim should still be found")
}
paginatedClaims[i] = syncedClaim
}
}
// Marshal claims
bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, 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, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) {
var usdxFactors types.RewardIndexes var usdxFactors types.RewardIndexes
@ -247,12 +293,19 @@ func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper, leg
return false return false
}) })
var savingsFactors types.MultiRewardIndexes
k.IterateSavingsRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) {
savingsFactors = savingsFactors.With(denom, indexes)
return false
})
response := types.NewQueryGetRewardFactorsResponse( response := types.NewQueryGetRewardFactorsResponse(
usdxFactors, usdxFactors,
supplyFactors, supplyFactors,
borrowFactors, borrowFactors,
delegatorFactors, delegatorFactors,
swapFactors, swapFactors,
savingsFactors,
) )
bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, response) bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, response)

View File

@ -39,7 +39,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
suite.storeGlobalBorrowIndexes(types.MultiRewardIndexes{ suite.storeGlobalBorrowIndexes(types.MultiRewardIndexes{
{ {
@ -91,7 +91,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUnchangedWhenBlockTimeHasNot
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -136,7 +136,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenSourceSharesAre
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper() // zero total borrows hardKeeper := newFakeHardKeeper() // zero total borrows
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -182,7 +182,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateAddedWhenStateDoesNotExist()
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -225,7 +225,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoPanicWhenStateDoesNotExist() {
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper() hardKeeper := newFakeHardKeeper()
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -253,7 +253,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenBeforeStartTime
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -299,7 +299,7 @@ func (suite *AccumulateBorrowRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, previousAccrualTime) suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, previousAccrualTime)

View File

@ -37,7 +37,7 @@ func TestAccumulateDelegatorRewards(t *testing.T) {
func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() { func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() {
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
suite.storeGlobalDelegatorIndexes(types.MultiRewardIndexes{ suite.storeGlobalDelegatorIndexes(types.MultiRewardIndexes{
{ {
@ -88,7 +88,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIn
func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() { func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() {
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -132,7 +132,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHas
func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() { func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() {
stakingKeeper := newFakeStakingKeeper() // zero total bonded stakingKeeper := newFakeStakingKeeper() // zero total bonded
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -177,7 +177,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceShares
func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExist() { func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExist() {
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -219,7 +219,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExis
func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist() { func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist() {
stakingKeeper := newFakeStakingKeeper() stakingKeeper := newFakeStakingKeeper()
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -246,7 +246,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist()
func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartTime() { func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartTime() {
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -291,7 +291,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartT
func (suite *AccumulateDelegatorRewardsTests) TestPanicWhenCurrentTimeLessThanPrevious() { func (suite *AccumulateDelegatorRewardsTests) TestPanicWhenCurrentTimeLessThanPrevious() {
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.keeper.SetPreviousDelegatorRewardAccrualTime(suite.ctx, types.BondDenom, previousAccrualTime) suite.keeper.SetPreviousDelegatorRewardAccrualTime(suite.ctx, types.BondDenom, previousAccrualTime)

View File

@ -58,7 +58,7 @@ func (suite *InitializeDelegatorRewardTests) TestClaimIsSyncedAndIndexesAreSetWh
DelegatorShares: d("1000"), DelegatorShares: d("1000"),
}}, }},
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{

View File

@ -37,7 +37,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl
delegator := arbitraryAddress() delegator := arbitraryAddress()
stakingKeeper := &fakeStakingKeeper{} // use an empty staking keeper that returns no delegations stakingKeeper := &fakeStakingKeeper{} // use an empty staking keeper that returns no delegations
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -58,7 +58,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl
func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUpdatedWhenGlobalFactorIncreased() { func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUpdatedWhenGlobalFactorIncreased() {
delegator := arbitraryAddress() delegator := arbitraryAddress()
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -97,7 +97,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsUnchangedWhenGlobalFac
unslashedBondedValidator(validatorAddress), unslashedBondedValidator(validatorAddress),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -142,7 +142,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenNewReward
unslashedBondedValidator(validatorAddress), unslashedBondedValidator(validatorAddress),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -192,7 +192,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenGlobalFac
unslashedBondedValidator(validatorAddress), unslashedBondedValidator(validatorAddress),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
claim := types.DelegatorClaim{ claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -298,7 +298,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenValAddrIsNil()
unslashedNotBondedValidator(validatorAddresses[3]), unslashedNotBondedValidator(validatorAddresses[3]),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
suite.Equal( suite.Equal(
d("11"), // delegation to bonded validators d("11"), // delegation to bonded validators
@ -341,7 +341,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenExcludingAVali
unslashedNotBondedValidator(validatorAddresses[3]), unslashedNotBondedValidator(validatorAddresses[3]),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
suite.Equal( suite.Equal(
d("10"), d("10"),
@ -384,7 +384,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenIncludingAVali
unslashedNotBondedValidator(validatorAddresses[3]), unslashedNotBondedValidator(validatorAddresses[3]),
}, },
} }
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil)
suite.Equal( suite.Equal(
d("111"), d("111"),

View File

@ -1,6 +1,8 @@
package keeper package keeper
import ( import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/incentive/types" "github.com/kava-labs/kava/x/incentive/types"
@ -35,3 +37,81 @@ func (k Keeper) AccumulateSavingsRewards(ctx sdk.Context, rewardPeriod types.Mul
k.SetSavingsRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes) k.SetSavingsRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes)
} }
} }
func (k Keeper) SynchronizeSavingsClaim(ctx sdk.Context, owner sdk.AccAddress) {
deposit, found := k.savingsKeeper.GetDeposit(ctx, owner)
if !found {
return
}
k.SynchronizeSavingsReward(ctx, deposit)
}
// SynchronizeSavingsReward updates the claim object by adding any accumulated rewards
// and updating the reward index value
func (k Keeper) SynchronizeSavingsReward(ctx sdk.Context, deposit savingstypes.Deposit) {
claim, found := k.GetSavingsClaim(ctx, deposit.Depositor)
if !found {
return
}
// Source shares for savings deposits is the deposit amount
for _, coin := range deposit.Amount {
claim = k.synchronizeSingleSavingsReward(ctx, claim, coin.Denom, coin.Amount.ToDec())
}
k.SetSavingsClaim(ctx, claim)
}
// synchronizeSingleSavingsReward synchronizes a single rewarded savings denom in a s claim.
// It returns the claim without setting in the store.
// The public methods for accessing and modifying claims are preferred over this one. Direct modification of claims is easy to get wrong.
func (k Keeper) synchronizeSingleSavingsReward(ctx sdk.Context, claim types.SavingsClaim, denom string, sourceShares sdk.Dec) types.SavingsClaim {
globalRewardIndexes, found := k.GetSavingsRewardIndexes(ctx, denom)
if !found {
// The global factor is only not found if
// - the savings denom 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 denoms.
// 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(denom)
if !found {
// Normally the reward indexes should always be found.
// But if a denom was not rewarded then becomes rewarded (ie a reward period is added to params), then the indexes will be missing from claims for that supplied denom.
// 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, sourceShares)
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(denom, globalRewardIndexes)
return claim
}
// GetSynchronizedSavingsClaim fetches a savings claim from the store and syncs rewards for all rewarded pools.
func (k Keeper) GetSynchronizedSavingsClaim(ctx sdk.Context, owner sdk.AccAddress) (types.SavingsClaim, bool) {
claim, found := k.GetSavingsClaim(ctx, owner)
if !found {
return types.SavingsClaim{}, false
}
deposit, found := k.savingsKeeper.GetDeposit(ctx, owner)
if !found {
return types.SavingsClaim{}, false
}
for _, coin := range deposit.Amount {
claim = k.synchronizeSingleSavingsReward(ctx, claim, coin.Denom, coin.Amount.ToDec())
}
return claim, true
}

View File

@ -38,7 +38,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
suite.storeGlobalSupplyIndexes(types.MultiRewardIndexes{ suite.storeGlobalSupplyIndexes(types.MultiRewardIndexes{
{ {
@ -90,7 +90,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUnchangedWhenBlockTimeHasNot
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -135,7 +135,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenSourceSharesAre
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper() // zero total supplys hardKeeper := newFakeHardKeeper() // zero total supplys
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -181,7 +181,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateAddedWhenStateDoesNotExist()
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -224,7 +224,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoPanicWhenStateDoesNotExist() {
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper() hardKeeper := newFakeHardKeeper()
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -252,7 +252,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenBeforeStartTime
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -298,7 +298,7 @@ func (suite *AccumulateSupplyRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi
denom := "bnb" denom := "bnb"
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil)
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, previousAccrualTime) suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, previousAccrualTime)

View File

@ -37,7 +37,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
suite.storeGlobalSwapIndexes(types.MultiRewardIndexes{ suite.storeGlobalSwapIndexes(types.MultiRewardIndexes{
{ {
@ -89,7 +89,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -134,7 +134,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenSourceSharesAreZe
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper() // no pools, so no source shares swapKeeper := newFakeSwapKeeper() // no pools, so no source shares
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -180,7 +180,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateAddedWhenStateDoesNotExist() {
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -223,7 +223,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoPanicWhenStateDoesNotExist() {
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper() swapKeeper := newFakeSwapKeeper()
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
period := types.NewMultiRewardPeriod( period := types.NewMultiRewardPeriod(
true, true,
@ -251,7 +251,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenBeforeStartTime()
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
previousIndexes := types.MultiRewardIndexes{ previousIndexes := types.MultiRewardIndexes{
{ {
@ -297,7 +297,7 @@ func (suite *AccumulateSwapRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou
pool := "btc:usdx" pool := "btc:usdx"
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.keeper.SetSwapRewardAccrualTime(suite.ctx, pool, previousAccrualTime) suite.keeper.SetSwapRewardAccrualTime(suite.ctx, pool, previousAccrualTime)

View File

@ -322,7 +322,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUnchangedWhenNo
swapKeeper := newFakeSwapKeeper(). swapKeeper := newFakeSwapKeeper().
addDeposit(poolID_1, owner, i(1e9)) addDeposit(poolID_1, owner, i(1e9))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
claim := types.SwapClaim{ claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -355,7 +355,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
owner := arbitraryAddress() owner := arbitraryAddress()
// owner has no shares in any pool // owner has no shares in any pool
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper()) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper(), nil)
claim := types.SwapClaim{ claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{
@ -415,7 +415,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
swapKeeper := newFakeSwapKeeper(). swapKeeper := newFakeSwapKeeper().
addDeposit(poolID_1, owner, i(1e9)). addDeposit(poolID_1, owner, i(1e9)).
addDeposit(poolID_2, owner, i(1e9)) addDeposit(poolID_2, owner, i(1e9))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil)
claim := types.SwapClaim{ claim := types.SwapClaim{
BaseMultiClaim: types.BaseMultiClaim{ BaseMultiClaim: types.BaseMultiClaim{

View File

@ -34,7 +34,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
suite.storeGlobalUSDXIndexes(types.RewardIndexes{ suite.storeGlobalUSDXIndexes(types.RewardIndexes{
{ {
@ -68,7 +68,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
previousIndexes := types.RewardIndexes{ previousIndexes := types.RewardIndexes{
{ {
@ -104,7 +104,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenSourceSharesAreZe
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper() // zero total borrows cdpKeeper := newFakeCDPKeeper() // zero total borrows
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
previousIndexes := types.RewardIndexes{ previousIndexes := types.RewardIndexes{
{ {
@ -141,7 +141,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateAddedWhenStateDoesNotExist() {
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
period := types.NewRewardPeriod( period := types.NewRewardPeriod(
true, true,
@ -174,7 +174,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenBeforeStartTime()
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
previousIndexes := types.RewardIndexes{ previousIndexes := types.RewardIndexes{
{ {
@ -211,7 +211,7 @@ func (suite *AccumulateUSDXRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou
cType := "bnb-a" cType := "bnb-a"
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil)
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, cType, previousAccrualTime) suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, cType, previousAccrualTime)

View File

@ -60,7 +60,7 @@ func (suite *unitTester) SetupSuite() {
func (suite *unitTester) SetupTest() { func (suite *unitTester) SetupTest() {
suite.ctx = NewTestContext(suite.incentiveStoreKey) suite.ctx = NewTestContext(suite.incentiveStoreKey)
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil) suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil)
} }
func (suite *unitTester) TearDownTest() { func (suite *unitTester) TearDownTest() {
@ -68,8 +68,8 @@ func (suite *unitTester) TearDownTest() {
suite.ctx = sdk.Context{} suite.ctx = sdk.Context{}
} }
func (suite *unitTester) NewKeeper(paramSubspace types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper) keeper.Keeper { func (suite *unitTester) NewKeeper(paramSubspace types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper, svk types.SavingsKeeper) keeper.Keeper {
return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk) return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk)
} }
func (suite *unitTester) storeGlobalBorrowIndexes(indexes types.MultiRewardIndexes) { func (suite *unitTester) storeGlobalBorrowIndexes(indexes types.MultiRewardIndexes) {

View File

@ -7,6 +7,7 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
cdptypes "github.com/kava-labs/kava/x/cdp/types" cdptypes "github.com/kava-labs/kava/x/cdp/types"
hardtypes "github.com/kava-labs/kava/x/hard/types" hardtypes "github.com/kava-labs/kava/x/hard/types"
savingstypes "github.com/kava-labs/kava/x/savings/types"
) )
// ParamSubspace defines the expected Subspace interfacace // ParamSubspace defines the expected Subspace interfacace
@ -56,6 +57,12 @@ type SwapKeeper interface {
GetDepositorSharesAmount(ctx sdk.Context, depositor sdk.AccAddress, poolID string) (shares sdk.Int, found bool) GetDepositorSharesAmount(ctx sdk.Context, depositor sdk.AccAddress, poolID string) (shares sdk.Int, found bool)
} }
// SavingsKeeper defines the required methods needed by this module's keeper
type SavingsKeeper interface {
GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (savingstypes.Deposit, bool)
GetSavingsModuleAccountBalances(ctx sdk.Context) sdk.Coins
}
// AccountKeeper expected interface for the account keeper (noalias) // AccountKeeper expected interface for the account keeper (noalias)
type AccountKeeper interface { type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI

View File

@ -10,6 +10,7 @@ const (
QueryGetUSDXMintingRewards = "usdx-minting-rewards" QueryGetUSDXMintingRewards = "usdx-minting-rewards"
QueryGetDelegatorRewards = "delegator-rewards" QueryGetDelegatorRewards = "delegator-rewards"
QueryGetSwapRewards = "swap-rewards" QueryGetSwapRewards = "swap-rewards"
QueryGetSavingsRewards = "savings-rewards"
QueryGetRewardFactors = "reward-factors" QueryGetRewardFactors = "reward-factors"
QueryGetParams = "parameters" QueryGetParams = "parameters"
@ -44,16 +45,18 @@ type QueryGetRewardFactorsResponse struct {
HardBorrowRewardFactors MultiRewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"` HardBorrowRewardFactors MultiRewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"`
DelegatorRewardFactors MultiRewardIndexes `json:"delegator_reward_factors" yaml:"delegator_reward_factors"` DelegatorRewardFactors MultiRewardIndexes `json:"delegator_reward_factors" yaml:"delegator_reward_factors"`
SwapRewardFactors MultiRewardIndexes `json:"swap_reward_factors" yaml:"swap_reward_factors"` SwapRewardFactors MultiRewardIndexes `json:"swap_reward_factors" yaml:"swap_reward_factors"`
SavingsRewardFactors MultiRewardIndexes `json:"savings_reward_factors" yaml:"savings_reward_factors"`
} }
// NewQueryGetRewardFactorsResponse returns a new instance of QueryAllRewardFactorsResponse // NewQueryGetRewardFactorsResponse returns a new instance of QueryAllRewardFactorsResponse
func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFactors, func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFactors,
hardBorrowFactors, delegatorFactors, swapFactors MultiRewardIndexes) QueryGetRewardFactorsResponse { hardBorrowFactors, delegatorFactors, swapFactors, savingsFactors MultiRewardIndexes) QueryGetRewardFactorsResponse {
return QueryGetRewardFactorsResponse{ return QueryGetRewardFactorsResponse{
USDXMintingRewardFactors: usdxMintingFactors, USDXMintingRewardFactors: usdxMintingFactors,
HardSupplyRewardFactors: supplyFactors, HardSupplyRewardFactors: supplyFactors,
HardBorrowRewardFactors: hardBorrowFactors, HardBorrowRewardFactors: hardBorrowFactors,
DelegatorRewardFactors: delegatorFactors, DelegatorRewardFactors: delegatorFactors,
SwapRewardFactors: swapFactors, SwapRewardFactors: swapFactors,
SavingsRewardFactors: savingsFactors,
} }
} }

View File

@ -51,7 +51,7 @@ func SolvencyInvariant(k Keeper) sdk.Invariant {
message := sdk.FormatInvariant(types.ModuleName, "module solvency broken", "total deposited amount does not match module account") message := sdk.FormatInvariant(types.ModuleName, "module solvency broken", "total deposited amount does not match module account")
return func(ctx sdk.Context) (string, bool) { return func(ctx sdk.Context) (string, bool) {
balance := k.bankKeeper.GetAllBalances(ctx, k.GetSavingsModuleAccount(ctx).GetAddress()) balance := k.GetSavingsModuleAccountBalances(ctx)
deposited := sdk.Coins{} deposited := sdk.Coins{}
k.IterateDeposits(ctx, func(deposit types.Deposit) bool { k.IterateDeposits(ctx, func(deposit types.Deposit) bool {

View File

@ -6,7 +6,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
@ -51,9 +50,10 @@ func (k *Keeper) SetHooks(hooks types.MultiSavingsHooks) *Keeper {
return k return k
} }
// GetSavingsModuleAccount returns the savings ModuleAccount // GetSavingsModuleAccountBalances returns the savings module account balances
func (k Keeper) GetSavingsModuleAccount(ctx sdk.Context) authtypes.ModuleAccountI { func (k Keeper) GetSavingsModuleAccountBalances(ctx sdk.Context) sdk.Coins {
return k.accountKeeper.GetModuleAccount(ctx, types.ModuleAccountName) savingMacc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleAccountName)
return k.bankKeeper.GetAllBalances(ctx, savingMacc.GetAddress())
} }
// GetDeposit returns a deposit from the store for a particular depositor address, deposit denom // GetDeposit returns a deposit from the store for a particular depositor address, deposit denom