Skip to content

Commit

Permalink
Usdc high apr fix for Elys/Eden staking (#386)
Browse files Browse the repository at this point in the history
* usdc high apr fix and some simplification in incentive module

* add migration script to migrate distribution interval from 10 to 1200

* fixing unit test failure

* resolve unit test failure

---------

Co-authored-by: Cosmic Vagabond <121588426+cosmic-vagabond@users.noreply.github.com>
  • Loading branch information
jelysn and cosmic-vagabond authored Feb 23, 2024
1 parent ff37a2f commit 8e1f1b7
Show file tree
Hide file tree
Showing 14 changed files with 66 additions and 72 deletions.
1 change: 0 additions & 1 deletion proto/elys/incentive/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ message GenesisState {
// fee_pool defines the fee pool at genesis.
FeePool fee_pool = 2 [(gogoproto.nullable) = false];
}

10 changes: 5 additions & 5 deletions x/amm/keeper/calc_in_route_by_denom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@ func TestCalcInRouteByDenom(t *testing.T) {
SetupMockPools(&k, ctx)

// Test direct pool route
route, err := k.CalcInRouteByDenom(ctx, "denom1", "denom2", "baseCurrency")
route, err := k.CalcInRouteByDenom(ctx, "denom1", "denom2", "uusdc")
require.NoError(t, err)
require.Len(t, route, 1)
require.Equal(t, route[0].TokenOutDenom, "denom2")

// Test route via base currency
route, err = k.CalcInRouteByDenom(ctx, "denom1", "denom3", "baseCurrency")
route, err = k.CalcInRouteByDenom(ctx, "denom1", "denom3", "uusdc")
require.NoError(t, err)
require.Len(t, route, 2)
require.Equal(t, route[0].TokenOutDenom, "baseCurrency")
require.Equal(t, route[0].TokenOutDenom, "uusdc")
require.Equal(t, route[1].TokenOutDenom, "denom3")

// Test no available pool
_, err = k.CalcInRouteByDenom(ctx, "denom1", "nonexistent", "baseCurrency")
_, err = k.CalcInRouteByDenom(ctx, "denom1", "nonexistent", "uusdc")
require.Error(t, err)

// Test same input and output denomination
route, err = k.CalcInRouteByDenom(ctx, "denom1", "denom1", "baseCurrency")
route, err = k.CalcInRouteByDenom(ctx, "denom1", "denom1", "uusdc")
require.NoError(t, err)
require.Len(t, route, 1)
require.Equal(t, route[0].TokenOutDenom, "denom1")
Expand Down
10 changes: 5 additions & 5 deletions x/amm/keeper/calc_out_route_by_denom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ func TestCalcOutRouteByDenom(t *testing.T) {
SetupMockPools(&k, ctx)

// Test direct pool route
route, err := k.CalcOutRouteByDenom(ctx, "denom2", "denom1", "baseCurrency")
route, err := k.CalcOutRouteByDenom(ctx, "denom2", "denom1", "uusdc")
require.NoError(t, err)
require.Len(t, route, 1)
require.Equal(t, route[0].TokenInDenom, "denom1")

// Test route via base currency
route, err = k.CalcOutRouteByDenom(ctx, "denom3", "denom1", "baseCurrency")
route, err = k.CalcOutRouteByDenom(ctx, "denom3", "denom1", "uusdc")
require.NoError(t, err)
require.Len(t, route, 2)
require.Equal(t, route[0].TokenInDenom, "baseCurrency")
require.Equal(t, route[0].TokenInDenom, "uusdc")
require.Equal(t, route[1].TokenInDenom, "denom1")

// Test no available pool
_, err = k.CalcOutRouteByDenom(ctx, "nonexistent", "denom1", "baseCurrency")
_, err = k.CalcOutRouteByDenom(ctx, "nonexistent", "denom1", "uusdc")
require.Error(t, err)

// Test same input and output denomination
_, err = k.CalcOutRouteByDenom(ctx, "denom1", "denom1", "baseCurrency")
_, err = k.CalcOutRouteByDenom(ctx, "denom1", "denom1", "uusdc")
require.Error(t, err)
}
4 changes: 2 additions & 2 deletions x/amm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func SetupMockPools(k *keeper.Keeper, ctx sdk.Context) {
{
PoolId: 2,
PoolAssets: []types.PoolAsset{
{Token: sdk.NewCoin("baseCurrency", sdk.NewInt(1000)), Weight: sdk.OneInt()},
{Token: sdk.NewCoin("uusdc", sdk.NewInt(1000)), Weight: sdk.OneInt()},
{Token: sdk.NewCoin("denom1", sdk.NewInt(1000)), Weight: sdk.OneInt()},
},
TotalWeight: sdk.NewInt(2),
Expand All @@ -108,7 +108,7 @@ func SetupMockPools(k *keeper.Keeper, ctx sdk.Context) {
{
PoolId: 3,
PoolAssets: []types.PoolAsset{
{Token: sdk.NewCoin("baseCurrency", sdk.NewInt(1000)), Weight: sdk.OneInt()},
{Token: sdk.NewCoin("uusdc", sdk.NewInt(1000)), Weight: sdk.OneInt()},
{Token: sdk.NewCoin("denom3", sdk.NewInt(1000)), Weight: sdk.OneInt()},
},
TotalWeight: sdk.NewInt(2),
Expand Down
8 changes: 1 addition & 7 deletions x/commitment/keeper/claim_reward.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
aptypes "github.com/elys-network/elys/x/assetprofile/types"
"github.com/elys-network/elys/x/commitment/types"
)
Expand Down Expand Up @@ -70,12 +69,7 @@ func (k Keeper) RecordClaimReward(ctx sdk.Context, creator string, denom string,

withdrawCoins := sdk.NewCoins(sdk.NewCoin(denom, amount))

addr, err := sdk.AccAddressFromBech32(commitments.Creator)
if err != nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "unable to convert address from bech32")
}

err = k.HandleWithdrawFromCommitment(ctx, &commitments, addr, withdrawCoins, false)
err := k.HandleWithdrawFromCommitment(ctx, &commitments, withdrawCoins, false, sdk.AccAddress{})
if err != nil {
return err
}
Expand Down
12 changes: 6 additions & 6 deletions x/commitment/keeper/commitments.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,21 +164,21 @@ func (k Keeper) BurnEdenBoost(ctx sdk.Context, creator string, denom string, amo
return commitments, nil
}

func (k Keeper) HandleWithdrawFromCommitment(ctx sdk.Context, commitments *types.Commitments, addr sdk.AccAddress, amount sdk.Coins, sendCoins bool) error {
func (k Keeper) HandleWithdrawFromCommitment(ctx sdk.Context, commitments *types.Commitments, amount sdk.Coins, sendCoins bool, addr sdk.AccAddress) error {
edenAmount := amount.AmountOf(ptypes.Eden)
edenBAmount := amount.AmountOf(ptypes.EdenB)
commitments.AddClaimed(sdk.NewCoin(ptypes.Eden, edenAmount))
commitments.AddClaimed(sdk.NewCoin(ptypes.EdenB, edenBAmount))
k.SetCommitments(ctx, *commitments)

// Emit Hook commitment changed
k.AfterCommitmentChange(ctx, commitments.Creator, amount)

withdrawCoins := amount.
Sub(sdk.NewCoin(ptypes.Eden, edenAmount)).
Sub(sdk.NewCoin(ptypes.EdenB, edenBAmount))

// Emit Hook commitment changed
k.AfterCommitmentChange(ctx, addr.String(), withdrawCoins)

if sendCoins {
if sendCoins && !withdrawCoins.Empty() {
return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, withdrawCoins)
}
return nil
Expand Down Expand Up @@ -212,7 +212,7 @@ func (k Keeper) RecordWithdrawValidatorCommission(ctx sdk.Context, delegator str
}

commitments = k.GetCommitments(ctx, delegator)
err = k.HandleWithdrawFromCommitment(ctx, &commitments, addr, withdrawCoins, false)
err = k.HandleWithdrawFromCommitment(ctx, &commitments, withdrawCoins, false, addr)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion x/commitment/keeper/msg_server_uncommit_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (k msgServer) UncommitTokens(goCtx context.Context, msg *types.MsgUncommitT
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "unable to convert address from bech32")
}

err = k.HandleWithdrawFromCommitment(ctx, &commitments, addr, liquidCoins, true)
err = k.HandleWithdrawFromCommitment(ctx, &commitments, liquidCoins, true, addr)
if err != nil {
return nil, err
}
Expand Down
35 changes: 5 additions & 30 deletions x/commitment/types/commitments.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,52 +118,27 @@ func (c *Commitments) DeductFromCommitted(denom string, amount math.Int, currTim
}

func (c *Commitments) GetRewardUnclaimedForDenom(denom string) math.Int {
for _, token := range c.RewardsUnclaimed {
if token.Denom == denom {
return token.Amount
}
}
return sdk.ZeroInt()
return c.RewardsUnclaimed.AmountOf(denom)
}

// Sub bucket rewards query - Elys
func (c *Commitments) GetElysSubBucketRewardUnclaimedForDenom(denom string) math.Int {
for _, token := range c.RewardsByElysUnclaimed {
if token.Denom == denom {
return token.Amount
}
}
return sdk.ZeroInt()
return c.RewardsByElysUnclaimed.AmountOf(denom)
}

// Sub bucket rewards query - Eden
func (c *Commitments) GetEdenSubBucketRewardUnclaimedForDenom(denom string) math.Int {
for _, token := range c.RewardsByEdenUnclaimed {
if token.Denom == denom {
return token.Amount
}
}
return sdk.ZeroInt()
return c.RewardsByEdenUnclaimed.AmountOf(denom)
}

// Sub bucket rewards query - EdenB
func (c *Commitments) GetEdenBSubBucketRewardUnclaimedForDenom(denom string) math.Int {
for _, token := range c.RewardsByEdenbUnclaimed {
if token.Denom == denom {
return token.Amount
}
}
return sdk.ZeroInt()
return c.RewardsByEdenbUnclaimed.AmountOf(denom)
}

// Sub bucket rewards query - Usdc
func (c *Commitments) GetUsdcSubBucketRewardUnclaimedForDenom(denom string) math.Int {
for _, token := range c.RewardsByUsdcUnclaimed {
if token.Denom == denom {
return token.Amount
}
}
return sdk.ZeroInt()
return c.RewardsByUsdcUnclaimed.AmountOf(denom)
}

func (c *Commitments) AddRewardsUnclaimed(amount sdk.Coin) {
Expand Down
1 change: 0 additions & 1 deletion x/incentive/keeper/apr.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ func (k Keeper) CalculateApr(ctx sdk.Context, query *types.QueryAprRequest) (mat
apr := dailyDexRewardAmount.
MulInt(sdk.NewInt(ptypes.DaysPerYear)).
MulInt(sdk.NewInt(100)).
MulInt(sdk.NewInt(1000000)).
Quo(edenPrice).
QuoInt(totalStakedSnapshot)

Expand Down
4 changes: 3 additions & 1 deletion x/incentive/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ func (k Keeper) UpdateStakersRewardsUnclaimed(ctx sdk.Context, stakeIncentive ty
// Reset amount from other tracker
params.DexRewardsStakers.AmountCollectedByOtherTracker = sdk.ZeroDec()
// Don't increase Lps rewards blocks, it will be increased whenever LP distribution epoch happens.
params.DexRewardsLps.AmountCollectedByOtherTracker = params.DexRewardsLps.AmountCollectedByOtherTracker.Add(dexRevenueLPsAmtPerDistribution).Add(gasFeesLPsAmtPerDistribution)
params.DexRewardsLps.AmountCollectedByOtherTracker = params.DexRewardsLps.AmountCollectedByOtherTracker.
Add(dexRevenueLPsAmtPerDistribution).
Add(gasFeesLPsAmtPerDistribution)
k.SetParams(ctx, params)

totalEdenGiven := sdk.ZeroInt()
Expand Down
23 changes: 15 additions & 8 deletions x/incentive/keeper/keeper_withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,19 @@ func (k Keeper) ProcessWithdrawRewards(ctx sdk.Context, delegator string, withdr
unclaimed := k.CalcAmountSubbucketsPerProgram(ctx, delegator, ptypes.Eden, withdrawType, commitments)
if !unclaimed.IsZero() {
err = k.cmk.RecordClaimReward(ctx, delegator, ptypes.Eden, unclaimed, withdrawType)
if err != nil {
return err
}
}

// Claim EdenB
// ---------------------------------------------------
unclaimed = k.CalcAmountSubbucketsPerProgram(ctx, delegator, ptypes.EdenB, withdrawType, commitments)
if !unclaimed.IsZero() {
err = k.cmk.RecordClaimReward(ctx, delegator, ptypes.EdenB, unclaimed, withdrawType)
if err != nil {
return err
}
}

// Claim USDC
Expand All @@ -134,7 +140,7 @@ func (k Keeper) ProcessWithdrawRewards(ctx sdk.Context, delegator string, withdr
}
baseCurrency := entry.Denom

// Get available usdc amount can be withdrew
// Get available usdc amount can be withdraw
unclaimedUsdc := k.CalcAmountSubbucketsPerProgram(ctx, delegator, baseCurrency, withdrawType, commitments)
if unclaimedUsdc.IsZero() {
return nil
Expand Down Expand Up @@ -190,12 +196,18 @@ func (k Keeper) RecordWithdrawValidatorCommission(ctx sdk.Context, delegator str
unclaimed := commitments.GetRewardUnclaimedForDenom(ptypes.Eden)
if !unclaimed.IsZero() {
err = k.cmk.RecordWithdrawValidatorCommission(ctx, delegator, validator, ptypes.Eden, unclaimed)
if err != nil {
return err
}
}

// EdenB
unclaimed = commitments.GetRewardUnclaimedForDenom(ptypes.EdenB)
if !unclaimed.IsZero() {
err = k.cmk.RecordWithdrawValidatorCommission(ctx, delegator, validator, ptypes.EdenB, unclaimed)
if err != nil {
return err
}
}

entry, found := k.assetProfileKeeper.GetEntry(ctx, ptypes.BaseCurrency)
Expand Down Expand Up @@ -223,7 +235,7 @@ func (k Keeper) RecordWithdrawValidatorCommission(ctx sdk.Context, delegator str
// This function call will deduct the accounting in commitment module only.
err = k.cmk.RecordClaimReward(ctx, validator, baseCurrency, unclaimedUsdc, commitmenttypes.EarnType_ALL_PROGRAM)
if err != nil {
return errorsmod.Wrapf(types.ErrIntOverflowTx, "Internal error with amount: %d", unclaimedUsdc)
return err
}

// Get Bech32 address for delegator
Expand All @@ -235,10 +247,5 @@ func (k Keeper) RecordWithdrawValidatorCommission(ctx sdk.Context, delegator str
// Set withdraw usdc amount
revenue := sdk.NewCoin(baseCurrency, unclaimedUsdc)
// Transfer revenue from a single wallet of DEX revenue wallet to user's wallet.
err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, k.dexRevCollectorName, addr, sdk.NewCoins(revenue))
if err != nil {
panic(err)
}

return err
return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, k.dexRevCollectorName, addr, sdk.NewCoins(revenue))
}
6 changes: 3 additions & 3 deletions x/incentive/keeper/keeper_withdraw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ func TestRecordWithdrawValidatorCommission(t *testing.T) {
app.CommitmentKeeper.BeforeDelegationCreated(ctx, delegator, valAddress.String())

// Set assetprofile entry for denom
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.BaseCurrency, CommitEnabled: false, WithdrawEnabled: true})
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.Eden, CommitEnabled: true, WithdrawEnabled: true})
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.EdenB, CommitEnabled: true, WithdrawEnabled: true})
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.BaseCurrency, Denom: ptypes.BaseCurrency, CommitEnabled: false, WithdrawEnabled: true})
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.Eden, Denom: ptypes.Eden, CommitEnabled: true, WithdrawEnabled: true})
app.AssetprofileKeeper.SetEntry(ctx, aptypes.Entry{BaseDenom: ptypes.EdenB, Denom: ptypes.EdenB, CommitEnabled: true, WithdrawEnabled: true})

// Give commission to validators ( Eden from stakers and Dex rewards from stakers. )
edenCommissionGiven, dexRewardsCommissionGiven := ik.GiveCommissionToValidators(ctx, delegator, delegatedAmt, newUnclaimedEdenTokens, dexRewardsByStakers, ptypes.BaseCurrency)
Expand Down
18 changes: 18 additions & 0 deletions x/incentive/migrations/v10_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package migrations

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func (m Migrator) V10Migration(ctx sdk.Context) error {
params := m.keeper.GetParams(ctx)
params.DistributionInterval = 1200
if params.LpIncentives != nil {
params.LpIncentives.DistributionEpochInBlocks = sdk.NewInt(params.DistributionInterval)
}
if params.StakeIncentives != nil {
params.StakeIncentives.DistributionEpochInBlocks = sdk.NewInt(params.DistributionInterval)
}
m.keeper.SetParams(ctx, params)
return nil
}
4 changes: 2 additions & 2 deletions x/incentive/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
m := migrations.NewMigrator(am.keeper)
err := cfg.RegisterMigration(types.ModuleName, 8, m.V9Migration)
err := cfg.RegisterMigration(types.ModuleName, 9, m.V10Migration)
if err != nil {
panic(err)
}
Expand All @@ -137,7 +137,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
}

// ConsensusVersion is a sequence number for state-breaking change of the module. It should be incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty versions, the initial version should be set to 1
func (AppModule) ConsensusVersion() uint64 { return 9 }
func (AppModule) ConsensusVersion() uint64 { return 10 }

// BeginBlock contains the logic that is automatically triggered at the beginning of each block
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
Expand Down

0 comments on commit 8e1f1b7

Please sign in to comment.