mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-25 07:45:18 +00:00
fix: Use correct share values for earn incentive hooks (#1347)
* Call earn hooks with correct share values User's shares instead of total vault shares * Use different amounts for different accounts * Add claim test with staking claims * Remove logging statements * Remove log * Pass suite.T() to mock earn hooks * Use begin blocker for staking reward distribution * Remove unused beginblocker * Remove log
This commit is contained in:
parent
aa2fedaf78
commit
e8242ace80
@ -79,8 +79,8 @@ func (k *Keeper) Deposit(
|
||||
|
||||
isNew := vaultShareRecord.Shares.AmountOf(amount.Denom).IsZero()
|
||||
if !isNew {
|
||||
// If deposits for this vault already exists
|
||||
k.BeforeVaultDepositModified(ctx, amount.Denom, depositor, vaultRecord.TotalShares.Amount)
|
||||
// If deposits for this vault already exists, call hook with user's existing shares
|
||||
k.BeforeVaultDepositModified(ctx, amount.Denom, depositor, vaultShareRecord.Shares.AmountOf(amount.Denom))
|
||||
}
|
||||
|
||||
// Increment VaultRecord total shares and account shares
|
||||
|
@ -27,13 +27,16 @@ func TestHookTestSuite(t *testing.T) {
|
||||
|
||||
func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
suite.Keeper.ClearHooks()
|
||||
earnHooks := &mocks.EarnHooks{}
|
||||
earnHooks := mocks.NewEarnHooks(suite.T())
|
||||
suite.Keeper.SetHooks(earnHooks)
|
||||
|
||||
vault1Denom := "usdx"
|
||||
vault2Denom := "ukava"
|
||||
deposit1Amount := sdk.NewInt64Coin(vault1Denom, 100)
|
||||
deposit2Amount := sdk.NewInt64Coin(vault2Denom, 100)
|
||||
acc1deposit1Amount := sdk.NewInt64Coin(vault1Denom, 100)
|
||||
acc1deposit2Amount := sdk.NewInt64Coin(vault2Denom, 200)
|
||||
|
||||
acc2deposit1Amount := sdk.NewInt64Coin(vault1Denom, 200)
|
||||
acc2deposit2Amount := sdk.NewInt64Coin(vault2Denom, 300)
|
||||
|
||||
suite.CreateVault(vault1Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
|
||||
suite.CreateVault(vault2Denom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
|
||||
@ -43,19 +46,24 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
sdk.NewInt64Coin(vault2Denom, 1000),
|
||||
), 0)
|
||||
|
||||
acc2 := suite.CreateAccount(sdk.NewCoins(
|
||||
sdk.NewInt64Coin(vault1Denom, 1000),
|
||||
sdk.NewInt64Coin(vault2Denom, 1000),
|
||||
), 1)
|
||||
|
||||
// first deposit creates vault - calls AfterVaultDepositCreated with initial shares
|
||||
// shares are 1:1
|
||||
earnHooks.On(
|
||||
"AfterVaultDepositCreated",
|
||||
suite.Ctx,
|
||||
deposit1Amount.Denom,
|
||||
acc1deposit1Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
deposit1Amount.Amount.ToDec(),
|
||||
acc1deposit1Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err := suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit1Amount,
|
||||
acc1deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -65,14 +73,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit1Amount.Denom,
|
||||
acc1deposit1Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
deposit1Amount.Amount.ToDec(),
|
||||
acc1deposit1Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit1Amount,
|
||||
acc1deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -89,14 +97,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit1Amount.Denom,
|
||||
acc1deposit1Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit1Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit1Amount.Denom),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit1Amount,
|
||||
acc1deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -105,14 +113,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"AfterVaultDepositCreated",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount.Amount.ToDec(),
|
||||
acc1deposit2Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -121,14 +129,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount.Amount.ToDec(),
|
||||
acc1deposit2Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -144,14 +152,131 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit2Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit2Amount.Denom),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Second account deposits
|
||||
|
||||
// first deposit by user - calls AfterVaultDepositCreated with user's shares
|
||||
// not total shares
|
||||
earnHooks.On(
|
||||
"AfterVaultDepositCreated",
|
||||
suite.Ctx,
|
||||
acc2deposit1Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit1Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// second deposit adds to vault - calls BeforeVaultDepositModified
|
||||
// shares given are the initial shares, not new the shares added to the vault
|
||||
// and not the total vault shares
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit1Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit1Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// get the shares from the store from the last deposit
|
||||
shareRecord2, found := suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// third deposit adds to vault - calls BeforeVaultDepositModified
|
||||
// shares given are the shares added in previous deposit, not the shares added to the vault now
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit1Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord2.AmountOf(acc2deposit1Amount.Denom),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit1Amount,
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// new deposit denom into vault creates the deposit and calls AfterVaultDepositCreated
|
||||
earnHooks.On(
|
||||
"AfterVaultDepositCreated",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// second deposit into vault calls BeforeVaultDepositModified with initial shares given
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount.Amount.ToDec(),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// get the shares from the store from the last deposit
|
||||
shareRecord2, found = suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// third deposit into vault calls BeforeVaultDepositModified with shares from last deposit
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord2.AmountOf(acc2deposit2Amount.Denom),
|
||||
).Once()
|
||||
err = suite.Keeper.Deposit(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -168,15 +293,15 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit1Amount.Denom,
|
||||
acc1deposit1Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit1Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit1Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
// 3 deposits, multiply original deposit amount by 3
|
||||
sdk.NewCoin(deposit1Amount.Denom, deposit1Amount.Amount.MulRaw(3)),
|
||||
sdk.NewCoin(acc1deposit1Amount.Denom, acc1deposit1Amount.Amount.MulRaw(3)),
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -192,14 +317,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit2Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -215,14 +340,14 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit2Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
@ -238,19 +363,111 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
deposit2Amount.Denom,
|
||||
acc1deposit2Amount.Denom,
|
||||
acc.GetAddress(),
|
||||
shareRecord.AmountOf(deposit2Amount.Denom),
|
||||
shareRecord.AmountOf(acc1deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc.GetAddress(),
|
||||
deposit2Amount,
|
||||
acc1deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
earnHooks.AssertExpectations(suite.T())
|
||||
// ------------------------------------------------------------
|
||||
// withdraw from acc2
|
||||
shareRecord, found = suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// all shares given to BeforeVaultDepositModified
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit1Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord.AmountOf(acc2deposit1Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
// 3 deposits, multiply original deposit amount by 3
|
||||
sdk.NewCoin(acc2deposit1Amount.Denom, acc2deposit1Amount.Amount.MulRaw(3)),
|
||||
types.STRATEGY_TYPE_HARD,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// test hooks on partial withdraw
|
||||
shareRecord2, found = suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// all shares given to before deposit modified even with partial withdraw
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord2.AmountOf(acc2deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// test hooks on second partial withdraw
|
||||
shareRecord2, found = suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// all shares given to before deposit modified even with partial withdraw
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord2.AmountOf(acc2deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// test hooks withdraw all remaining shares
|
||||
shareRecord2, found = suite.Keeper.GetVaultAccountShares(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
)
|
||||
suite.Require().True(found)
|
||||
|
||||
// all shares given to before deposit modified even with partial withdraw
|
||||
earnHooks.On(
|
||||
"BeforeVaultDepositModified",
|
||||
suite.Ctx,
|
||||
acc2deposit2Amount.Denom,
|
||||
acc2.GetAddress(),
|
||||
shareRecord2.AmountOf(acc2deposit2Amount.Denom),
|
||||
).Once()
|
||||
_, err = suite.Keeper.Withdraw(
|
||||
suite.Ctx,
|
||||
acc2.GetAddress(),
|
||||
acc2deposit2Amount,
|
||||
types.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (suite *hookTestSuite) TestHooks_NoPanicsOnNilHooks() {
|
||||
|
@ -126,8 +126,8 @@ func (k *Keeper) Withdraw(
|
||||
withdrawShares = vaultShareRecord.Shares.GetShare(withdrawAmount.Denom)
|
||||
}
|
||||
|
||||
// Call hook before record is modified
|
||||
k.BeforeVaultDepositModified(ctx, wantAmount.Denom, from, vaultRecord.TotalShares.Amount)
|
||||
// Call hook before record is modified with the user's current shares
|
||||
k.BeforeVaultDepositModified(ctx, wantAmount.Denom, from, accCurrentShares)
|
||||
|
||||
// Decrement VaultRecord and VaultShareRecord supplies - must delete same
|
||||
// amounts
|
||||
|
197
x/incentive/keeper/msg_server_earn_test.go
Normal file
197
x/incentive/keeper/msg_server_earn_test.go
Normal file
@ -0,0 +1,197 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
earntypes "github.com/kava-labs/kava/x/earn/types"
|
||||
"github.com/kava-labs/kava/x/incentive/testutil"
|
||||
"github.com/kava-labs/kava/x/incentive/types"
|
||||
liquidtypes "github.com/kava-labs/kava/x/liquid/types"
|
||||
)
|
||||
|
||||
func (suite *HandlerTestSuite) TestEarnLiquidClaim() {
|
||||
userAddr1, userAddr2, validatorAddr1, validatorAddr2 := suite.addrs[0], suite.addrs[1], suite.addrs[2], suite.addrs[3]
|
||||
|
||||
valAddr1 := sdk.ValAddress(validatorAddr1)
|
||||
valAddr2 := sdk.ValAddress(validatorAddr2)
|
||||
|
||||
authBuilder := suite.authBuilder().
|
||||
WithSimpleAccount(userAddr1, cs(c("ukava", 1e12))).
|
||||
WithSimpleAccount(userAddr2, cs(c("ukava", 1e12))).
|
||||
WithSimpleAccount(validatorAddr1, cs(c("ukava", 1e12))).
|
||||
WithSimpleAccount(validatorAddr2, cs(c("ukava", 1e12)))
|
||||
|
||||
incentBuilder := suite.incentiveBuilder()
|
||||
|
||||
savingsBuilder := testutil.NewSavingsGenesisBuilder().
|
||||
WithSupportedDenoms("bkava")
|
||||
|
||||
earnBuilder := suite.earnBuilder().
|
||||
WithVault(earntypes.AllowedVault{
|
||||
Denom: "bkava",
|
||||
Strategies: earntypes.StrategyTypes{earntypes.STRATEGY_TYPE_SAVINGS},
|
||||
IsPrivateVault: false,
|
||||
AllowedDepositors: nil,
|
||||
})
|
||||
|
||||
suite.SetupWithGenState(authBuilder, incentBuilder, earnBuilder, savingsBuilder)
|
||||
|
||||
// ak := suite.App.GetAccountKeeper()
|
||||
// bk := suite.App.GetBankKeeper()
|
||||
sk := suite.App.GetStakingKeeper()
|
||||
lq := suite.App.GetLiquidKeeper()
|
||||
mk := suite.App.GetMintKeeper()
|
||||
dk := suite.App.GetDistrKeeper()
|
||||
ik := suite.App.GetIncentiveKeeper()
|
||||
|
||||
// Use ukava for mint denom
|
||||
mParams := mk.GetParams(suite.Ctx)
|
||||
mParams.MintDenom = "ukava"
|
||||
mk.SetParams(suite.Ctx, mParams)
|
||||
|
||||
bkavaDenom1 := lq.GetLiquidStakingTokenDenom(valAddr1)
|
||||
bkavaDenom2 := lq.GetLiquidStakingTokenDenom(valAddr2)
|
||||
|
||||
err := suite.App.FundModuleAccount(suite.Ctx, distrtypes.ModuleName, cs(c("ukava", 1e12)))
|
||||
suite.NoError(err)
|
||||
|
||||
// Create validators
|
||||
err = suite.DeliverMsgCreateValidator(valAddr1, c("ukava", 1e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverMsgCreateValidator(valAddr2, c("ukava", 1e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// new block required to bond validator
|
||||
suite.NextBlockAfter(7 * time.Second)
|
||||
// Now the delegation is bonded, accumulate some delegator rewards
|
||||
suite.NextBlockAfter(7 * time.Second)
|
||||
|
||||
// Create delegations from users
|
||||
// User 1: 1e9 ukava to validator 1
|
||||
// User 2: 99e9 ukava to validator 1 AND 2
|
||||
err = suite.DeliverMsgDelegate(userAddr1, valAddr1, c("ukava", 1e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverMsgDelegate(userAddr2, valAddr1, c("ukava", 99e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverMsgDelegate(userAddr2, valAddr2, c("ukava", 99e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Mint liquid tokens
|
||||
err = suite.DeliverMsgMintDerivative(userAddr1, valAddr1, c("ukava", 1e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverMsgMintDerivative(userAddr2, valAddr1, c("ukava", 99e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverMsgMintDerivative(userAddr2, valAddr2, c("ukava", 99e9))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Deposit liquid tokens to earn
|
||||
err = suite.DeliverEarnMsgDeposit(userAddr1, c(bkavaDenom1, 1e9), earntypes.STRATEGY_TYPE_SAVINGS)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverEarnMsgDeposit(userAddr2, c(bkavaDenom1, 99e9), earntypes.STRATEGY_TYPE_SAVINGS)
|
||||
suite.Require().NoError(err)
|
||||
err = suite.DeliverEarnMsgDeposit(userAddr2, c(bkavaDenom2, 99e9), earntypes.STRATEGY_TYPE_SAVINGS)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// BeginBlocker to update minter annual provisions as it starts at 0 which results in no minted coins
|
||||
_ = suite.App.BeginBlocker(suite.Ctx, abci.RequestBeginBlock{})
|
||||
|
||||
// DeliverMsgCreateValidator uses a generated pubkey, so we need to fetch
|
||||
// the validator to get the correct pubkey
|
||||
validator1, found := sk.GetValidator(suite.Ctx, valAddr1)
|
||||
suite.Require().True(found)
|
||||
|
||||
pk, err := validator1.ConsPubKey()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
val := abci.Validator{
|
||||
Address: pk.Address(),
|
||||
Power: 100,
|
||||
}
|
||||
|
||||
suite.Ctx = suite.Ctx.
|
||||
WithBlockHeight(suite.Ctx.BlockHeight() + 1).
|
||||
WithBlockTime(suite.Ctx.BlockTime().Add(1 * time.Hour))
|
||||
// Accumulate some staking rewards
|
||||
_ = suite.App.BeginBlocker(suite.Ctx, abci.RequestBeginBlock{
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
Votes: []abci.VoteInfo{{
|
||||
Validator: val,
|
||||
SignedLastBlock: true,
|
||||
}},
|
||||
},
|
||||
})
|
||||
|
||||
liquidMacc := suite.App.GetAccountKeeper().GetModuleAccount(suite.Ctx, liquidtypes.ModuleAccountName)
|
||||
delegation, found := sk.GetDelegation(suite.Ctx, liquidMacc.GetAddress(), valAddr1)
|
||||
suite.Require().True(found)
|
||||
|
||||
// Get amount of rewards
|
||||
endingPeriod := dk.IncrementValidatorPeriod(suite.Ctx, validator1)
|
||||
delegationRewards := dk.CalculateDelegationRewards(suite.Ctx, validator1, delegation, endingPeriod)
|
||||
|
||||
// Accumulate rewards - claim rewards
|
||||
rewardPeriod := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava", // reward period is set for "bkava" to apply to all vaults
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(), // no incentives, so only the staking rewards are distributed
|
||||
)
|
||||
err = ik.AccumulateEarnRewards(suite.Ctx, rewardPeriod)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
preClaimBal1 := suite.GetBalance(userAddr1)
|
||||
preClaimBal2 := suite.GetBalance(userAddr2)
|
||||
|
||||
// Claim ukava staking rewards
|
||||
denomsToClaim := map[string]string{"ukava": "large"}
|
||||
selections := types.NewSelectionsFromMap(denomsToClaim)
|
||||
|
||||
msg1 := types.NewMsgClaimEarnReward(userAddr1.String(), selections)
|
||||
msg2 := types.NewMsgClaimEarnReward(userAddr2.String(), selections)
|
||||
|
||||
err = suite.DeliverIncentiveMsg(&msg1)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.DeliverIncentiveMsg(&msg2)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Check rewards were paid out
|
||||
// User 1 gets 1% of rewards
|
||||
// User 2 gets 99% of rewards
|
||||
stakingRewards1 := delegationRewards.
|
||||
AmountOf("ukava").
|
||||
QuoInt64(100).
|
||||
RoundInt()
|
||||
suite.BalanceEquals(userAddr1, preClaimBal1.Add(sdk.NewCoin("ukava", stakingRewards1)))
|
||||
|
||||
// Total * 99 / 100
|
||||
stakingRewards2 := delegationRewards.
|
||||
AmountOf("ukava").
|
||||
MulInt64(99).
|
||||
QuoInt64(100).
|
||||
TruncateInt()
|
||||
suite.BalanceEquals(userAddr2, preClaimBal2.Add(sdk.NewCoin("ukava", stakingRewards2)))
|
||||
|
||||
suite.Equal(delegationRewards.AmountOf("ukava").TruncateInt(), stakingRewards1.Add(stakingRewards2))
|
||||
|
||||
// Check that claimed coins have been removed from a claim's reward
|
||||
suite.EarnRewardEquals(userAddr1, cs())
|
||||
suite.EarnRewardEquals(userAddr2, cs())
|
||||
}
|
||||
|
||||
// earnBuilder returns a new earn genesis builder with a genesis time and multipliers set
|
||||
func (suite *HandlerTestSuite) earnBuilder() testutil.EarnGenesisBuilder {
|
||||
return testutil.NewEarnGenesisBuilder().
|
||||
WithGenesisTime(suite.genesisTime)
|
||||
}
|
@ -7,8 +7,10 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
earntypes "github.com/kava-labs/kava/x/earn/types"
|
||||
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||
"github.com/kava-labs/kava/x/incentive/types"
|
||||
savingstypes "github.com/kava-labs/kava/x/savings/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -168,6 +170,24 @@ func (builder IncentiveGenesisBuilder) WithSimpleUSDXRewardPeriod(ctype string,
|
||||
))
|
||||
}
|
||||
|
||||
// WithInitializedEarnRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
|
||||
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
|
||||
func (builder IncentiveGenesisBuilder) WithInitializedEarnRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder {
|
||||
builder.Params.EarnRewardPeriods = append(builder.Params.EarnRewardPeriods, period)
|
||||
|
||||
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
|
||||
builder.EarnRewardState.AccumulationTimes = append(
|
||||
builder.EarnRewardState.AccumulationTimes,
|
||||
accumulationTimeForPeriod,
|
||||
)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder IncentiveGenesisBuilder) WithSimpleEarnRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
|
||||
return builder.WithInitializedEarnRewardPeriod(builder.simpleRewardPeriod(ctype, rewardsPerSecond))
|
||||
}
|
||||
|
||||
func (builder IncentiveGenesisBuilder) WithMultipliers(multipliers types.MultipliersPerDenoms) IncentiveGenesisBuilder {
|
||||
builder.Params.ClaimMultipliers = multipliers
|
||||
|
||||
@ -281,3 +301,75 @@ func (builder IncentiveGenesisBuilder) WithInitializedSavingsRewardPeriod(period
|
||||
func (builder IncentiveGenesisBuilder) WithSimpleSavingsRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
|
||||
return builder.WithInitializedSavingsRewardPeriod(builder.simpleRewardPeriod(ctype, rewardsPerSecond))
|
||||
}
|
||||
|
||||
// EarnGenesisBuilder is a tool for creating a earn genesis state.
|
||||
// Helper methods add values onto a default genesis state.
|
||||
// All methods are immutable and return updated copies of the builder.
|
||||
type EarnGenesisBuilder struct {
|
||||
earntypes.GenesisState
|
||||
genesisTime time.Time
|
||||
}
|
||||
|
||||
func NewEarnGenesisBuilder() EarnGenesisBuilder {
|
||||
return EarnGenesisBuilder{
|
||||
GenesisState: earntypes.DefaultGenesisState(),
|
||||
}
|
||||
}
|
||||
|
||||
func (builder EarnGenesisBuilder) Build() earntypes.GenesisState {
|
||||
return builder.GenesisState
|
||||
}
|
||||
|
||||
func (builder EarnGenesisBuilder) BuildMarshalled(cdc codec.JSONCodec) app.GenesisState {
|
||||
built := builder.Build()
|
||||
|
||||
return app.GenesisState{
|
||||
earntypes.ModuleName: cdc.MustMarshalJSON(&built),
|
||||
}
|
||||
}
|
||||
|
||||
func (builder EarnGenesisBuilder) WithGenesisTime(genTime time.Time) EarnGenesisBuilder {
|
||||
builder.genesisTime = genTime
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder EarnGenesisBuilder) WithVault(vault earntypes.AllowedVault) EarnGenesisBuilder {
|
||||
builder.Params.AllowedVaults = append(builder.Params.AllowedVaults, vault)
|
||||
return builder
|
||||
}
|
||||
|
||||
// SavingsGenesisBuilder is a tool for creating a savings genesis state.
|
||||
// Helper methods add values onto a default genesis state.
|
||||
// All methods are immutable and return updated copies of the builder.
|
||||
type SavingsGenesisBuilder struct {
|
||||
savingstypes.GenesisState
|
||||
genesisTime time.Time
|
||||
}
|
||||
|
||||
func NewSavingsGenesisBuilder() SavingsGenesisBuilder {
|
||||
return SavingsGenesisBuilder{
|
||||
GenesisState: savingstypes.DefaultGenesisState(),
|
||||
}
|
||||
}
|
||||
|
||||
func (builder SavingsGenesisBuilder) Build() savingstypes.GenesisState {
|
||||
return builder.GenesisState
|
||||
}
|
||||
|
||||
func (builder SavingsGenesisBuilder) BuildMarshalled(cdc codec.JSONCodec) app.GenesisState {
|
||||
built := builder.Build()
|
||||
|
||||
return app.GenesisState{
|
||||
savingstypes.ModuleName: cdc.MustMarshalJSON(&built),
|
||||
}
|
||||
}
|
||||
|
||||
func (builder SavingsGenesisBuilder) WithGenesisTime(genTime time.Time) SavingsGenesisBuilder {
|
||||
builder.genesisTime = genTime
|
||||
return builder
|
||||
}
|
||||
|
||||
func (builder SavingsGenesisBuilder) WithSupportedDenoms(denoms ...string) SavingsGenesisBuilder {
|
||||
builder.Params.SupportedDenoms = append(builder.Params.SupportedDenoms, denoms...)
|
||||
return builder
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
||||
@ -21,10 +22,14 @@ import (
|
||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||
committeekeeper "github.com/kava-labs/kava/x/committee/keeper"
|
||||
committeetypes "github.com/kava-labs/kava/x/committee/types"
|
||||
earnkeeper "github.com/kava-labs/kava/x/earn/keeper"
|
||||
earntypes "github.com/kava-labs/kava/x/earn/types"
|
||||
hardkeeper "github.com/kava-labs/kava/x/hard/keeper"
|
||||
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||
incentivekeeper "github.com/kava-labs/kava/x/incentive/keeper"
|
||||
"github.com/kava-labs/kava/x/incentive/types"
|
||||
liquidkeeper "github.com/kava-labs/kava/x/liquid/keeper"
|
||||
liquidtypes "github.com/kava-labs/kava/x/liquid/types"
|
||||
swapkeeper "github.com/kava-labs/kava/x/swap/keeper"
|
||||
swaptypes "github.com/kava-labs/kava/x/swap/types"
|
||||
)
|
||||
@ -87,6 +92,8 @@ func (suite *IntegrationTester) DeliverIncentiveMsg(msg sdk.Msg) error {
|
||||
_, err = msgServer.ClaimUSDXMintingReward(sdk.WrapSDKContext(suite.Ctx), msg)
|
||||
case *types.MsgClaimDelegatorReward:
|
||||
_, err = msgServer.ClaimDelegatorReward(sdk.WrapSDKContext(suite.Ctx), msg)
|
||||
case *types.MsgClaimEarnReward:
|
||||
_, err = msgServer.ClaimEarnReward(sdk.WrapSDKContext(suite.Ctx), msg)
|
||||
default:
|
||||
panic("unhandled incentive msg")
|
||||
}
|
||||
@ -194,6 +201,30 @@ func (suite *IntegrationTester) DeliverCDPMsgBorrow(owner sdk.AccAddress, collat
|
||||
return err
|
||||
}
|
||||
|
||||
func (suite *IntegrationTester) DeliverMsgMintDerivative(
|
||||
sender sdk.AccAddress,
|
||||
validator sdk.ValAddress,
|
||||
amount sdk.Coin,
|
||||
) error {
|
||||
msg := liquidtypes.NewMsgMintDerivative(sender, validator, amount)
|
||||
msgServer := liquidkeeper.NewMsgServerImpl(suite.App.GetLiquidKeeper())
|
||||
|
||||
_, err := msgServer.MintDerivative(sdk.WrapSDKContext(suite.Ctx), &msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (suite *IntegrationTester) DeliverEarnMsgDeposit(
|
||||
depositor sdk.AccAddress,
|
||||
amount sdk.Coin,
|
||||
strategy earntypes.StrategyType,
|
||||
) error {
|
||||
msg := earntypes.NewMsgDeposit(depositor.String(), amount, strategy)
|
||||
msgServer := earnkeeper.NewMsgServerImpl(suite.App.GetEarnKeeper())
|
||||
|
||||
_, err := msgServer.Deposit(sdk.WrapSDKContext(suite.Ctx), msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (suite *IntegrationTester) ProposeAndVoteOnNewParams(voter sdk.AccAddress, committeeID uint64, changes []proposaltypes.ParamChange) {
|
||||
propose, err := committeetypes.NewMsgSubmitProposal(
|
||||
proposaltypes.NewParameterChangeProposal(
|
||||
@ -292,3 +323,18 @@ func (suite *IntegrationTester) USDXRewardEquals(owner sdk.AccAddress, expected
|
||||
suite.Require().Truef(found, "expected delegator claim to be found for %s", owner)
|
||||
suite.Equalf(expected, claim.Reward, "expected delegator claim reward to be %s, but got %s", expected, claim.Reward)
|
||||
}
|
||||
|
||||
func (suite *IntegrationTester) EarnRewardEquals(owner sdk.AccAddress, expected sdk.Coins) {
|
||||
claim, found := suite.App.GetIncentiveKeeper().GetEarnClaim(suite.Ctx, owner)
|
||||
suite.Require().Truef(found, "expected earn claim to be found for %s", owner)
|
||||
suite.Truef(expected.IsEqual(claim.Reward), "expected earn claim reward to be %s, but got %s", expected, claim.Reward)
|
||||
}
|
||||
|
||||
// AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys.
|
||||
func (suite *IntegrationTester) AddTestAddrsFromPubKeys(ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) {
|
||||
initCoins := sdk.NewCoins(sdk.NewCoin(suite.App.GetStakingKeeper().BondDenom(ctx), accAmt))
|
||||
|
||||
for _, pk := range pubKeys {
|
||||
suite.App.FundAccount(ctx, sdk.AccAddress(pk.Address()), initCoins)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user