Skip to content

Commit

Permalink
Incentive module Eden rewards calculation algorithm update. (#198)
Browse files Browse the repository at this point in the history
* chore: manage eden boost burning from elys unstake and eden uncommitted

* chore: add abci test

* refactor: margin functions (#194)

* refactor: margin functions

* fix: test cases

* fix: mocks

* test: fix test cases

* fix: issue with staking hook handling and burning amount calculation

* chore: track Elys staked, Eden committed and EdenB committed separately in Eden rewards calculation

* fix: update comments for elys staked

---------

Co-authored-by: Cosmic Vagabond <121588426+cosmic-vagabond@users.noreply.github.com>
  • Loading branch information
kenta-elys and cosmic-vagabond authored Sep 21, 2023
1 parent 511b0eb commit dabd7e8
Show file tree
Hide file tree
Showing 25 changed files with 1,067 additions and 57 deletions.
1 change: 1 addition & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ genesis:
withdraw_addr_enabled: true
reward_portion_for_lps: "0.65"
pool_infos: []
elys_stake_tracking_rate: "10"
fee_pool:
community_pool:
- amount: "0"
Expand Down
9 changes: 9 additions & 0 deletions docs/static/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38979,6 +38979,9 @@ paths:
title: |-
Pool information
poolId, reward wallet, mulitplier
elys_stake_tracking_rate:
type: string
format: int64
description: >-
QueryParamsResponse is response type for the Query/Params RPC
method.
Expand Down Expand Up @@ -78818,6 +78821,9 @@ definitions:
title: |-
Pool information
poolId, reward wallet, mulitplier
elys_stake_tracking_rate:
type: string
format: int64
description: Params defines the parameters for the module.
elys.incentive.PoolInfo:
type: object
Expand Down Expand Up @@ -78938,6 +78944,9 @@ definitions:
title: |-
Pool information
poolId, reward wallet, mulitplier
elys_stake_tracking_rate:
type: string
format: int64
description: QueryParamsResponse is response type for the Query/Params RPC method.
elys.liquidityprovider.Params:
type: object
Expand Down
17 changes: 17 additions & 0 deletions proto/elys/incentive/elys_staked.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
syntax = "proto3";
package elys.incentive;

option go_package = "github.com/elys-network/elys/x/incentive/types";
option (gogoproto.equal_all) = true;

import "gogoproto/gogo.proto";

// Elys staked
message ElysStaked {
string address = 1;
string amount = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}

2 changes: 2 additions & 0 deletions proto/elys/incentive/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ message Params {
// Pool information
// poolId, reward wallet, mulitplier
repeated PoolInfo pool_infos = 6 [(gogoproto.nullable) = false];

int64 elys_stake_tracking_rate = 7;
}
1 change: 0 additions & 1 deletion proto/elys/incentive/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ service Query {
option (google.api.http).get = "/elys-network/elys/incentive/community_pool";

}

}
// QueryParamsRequest is request type for the Query/Params RPC method.
message QueryParamsRequest {}
Expand Down
15 changes: 15 additions & 0 deletions x/commitment/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,25 @@ func (mh MultiCommitmentHooks) CommitmentChanged(ctx sdk.Context, creator string
}
}

// Committed is called when staker committed his token
func (mh MultiCommitmentHooks) EdenUncommitted(ctx sdk.Context, creator string, amount sdk.Coin) {
for i := range mh {
mh[i].EdenUncommitted(ctx, creator, amount)
}
}

// Committed executes the indicated for committed hook
func (k Keeper) AfterCommitmentChange(ctx sdk.Context, creator string, amount sdk.Coin) {
if k.hooks == nil {
return
}
k.hooks.CommitmentChanged(ctx, creator, amount)
}

// Committed executes the indicated for committed hook
func (k Keeper) EdenUncommitted(ctx sdk.Context, creator string, amount sdk.Coin) {
if k.hooks == nil {
return
}
k.hooks.EdenUncommitted(ctx, creator, amount)
}
6 changes: 6 additions & 0 deletions x/commitment/keeper/msg_server_uncommit_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
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"
ptypes "github.com/elys-network/elys/x/parameter/types"
)

func (k msgServer) UncommitTokens(goCtx context.Context, msg *types.MsgUncommitTokens) (*types.MsgUncommitTokensResponse, error) {
Expand Down Expand Up @@ -58,6 +59,11 @@ func (k msgServer) UncommitTokens(goCtx context.Context, msg *types.MsgUncommitT
// Emit Hook commitment changed
k.AfterCommitmentChange(ctx, msg.Creator, sdk.NewCoin(msg.Denom, msg.Amount))

// Emit Hook if Eden is uncommitted
if msg.Denom == ptypes.Eden {
k.EdenUncommitted(ctx, msg.Creator, sdk.NewCoin(msg.Denom, msg.Amount))
}

// Emit blockchain event
ctx.EventManager().EmitEvent(
sdk.NewEvent(
Expand Down
3 changes: 3 additions & 0 deletions x/commitment/types/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ import sdk "github.com/cosmos/cosmos-sdk/types"
type CommitmentHooks interface {
// Token commitment changed
CommitmentChanged(ctx sdk.Context, creator string, amount sdk.Coin)

// Eden uncommitted
EdenUncommitted(ctx sdk.Context, creator string, amount sdk.Coin)
}
63 changes: 63 additions & 0 deletions x/incentive/keeper/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2022 Evmos Foundation
// This file is part of the Evmos Network packages.
//
// Evmos is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Evmos packages are distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Evmos packages. If not, see https://github.com/evmos/evmos/blob/main/LICENSE

package keeper

import (
"time"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"

ctypes "github.com/elys-network/elys/x/commitment/types"
"github.com/elys-network/elys/x/incentive/types"
)

// EndBlocker of incentive module
func (k Keeper) EndBlocker(ctx sdk.Context) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)
params := k.GetParams(ctx)
// Update Elys staked amount every n blocks
if params.ElysStakeTrackingRate == 0 || ctx.BlockHeight()%params.ElysStakeTrackingRate != 0 {
return
}

// Track the amount of Elys staked
k.cmk.IterateCommitments(
ctx, func(commitments ctypes.Commitments) bool {
// Commitment owner
creator := commitments.Creator
_, err := sdk.AccAddressFromBech32(creator)
if err != nil {
// This could be validator address
return false
}

// Calculate delegated amount per delegator
delegatedAmt := k.CalculateDelegatedAmount(ctx, creator)

elysStaked := types.ElysStaked{
Address: creator,
Amount: delegatedAmt,
}

// Set Elys staked amount
k.SetElysStaked(ctx, elysStaked)

return false
},
)
}
50 changes: 50 additions & 0 deletions x/incentive/keeper/abci_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package keeper_test

import (
"testing"

tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
simapp "github.com/elys-network/elys/app"
ctypes "github.com/elys-network/elys/x/commitment/types"
ptypes "github.com/elys-network/elys/x/parameter/types"
"github.com/stretchr/testify/require"
)

func TestABCI_EndBlocker(t *testing.T) {
app, genAccount, _ := simapp.InitElysTestAppWithGenAccount()
ctx := app.BaseApp.NewContext(initChain, tmproto.Header{})

ik := app.IncentiveKeeper

var committed []sdk.Coins
var uncommitted []sdk.Coins

// Prepare uncommitted tokens
uedenToken := sdk.NewCoins(sdk.NewCoin(ptypes.Eden, sdk.NewInt(2000)))
uedenBToken := sdk.NewCoins(sdk.NewCoin(ptypes.EdenB, sdk.NewInt(2000)))
uncommitted = append(uncommitted, uedenToken)
uncommitted = append(uncommitted, uedenBToken)

// Eden
err := app.BankKeeper.MintCoins(ctx, ctypes.ModuleName, uedenToken)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ctypes.ModuleName, genAccount, uedenToken)
require.NoError(t, err)

// EdenB
err = app.BankKeeper.MintCoins(ctx, ctypes.ModuleName, uedenBToken)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ctypes.ModuleName, genAccount, uedenBToken)
require.NoError(t, err)

// Add testing commitment
simapp.AddTestCommitment(app, ctx, genAccount, committed, uncommitted)
// Update Elys staked amount
ik.EndBlocker(ctx)

// Get elys staked
elysStaked, found := ik.GetElysStaked(ctx, genAccount.String())
require.Equal(t, found, true)
require.Equal(t, elysStaked.Amount, sdk.DefaultPowerReduction)
}
63 changes: 63 additions & 0 deletions x/incentive/keeper/elys_staked.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package keeper

import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/incentive/types"
)

// SetElysStaked set a specific elysStaked in the store from its index
func (k Keeper) SetElysStaked(ctx sdk.Context, elysStaked types.ElysStaked) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ElysStakedKeyPrefix))
b := k.cdc.MustMarshal(&elysStaked)
store.Set(types.ElysStakedKey(
elysStaked.Address,
), b)
}

// GetElysStaked returns a elysStaked from its index
func (k Keeper) GetElysStaked(
ctx sdk.Context,
address string,

) (val types.ElysStaked, found bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ElysStakedKeyPrefix))

b := store.Get(types.ElysStakedKey(
address,
))
if b == nil {
return val, false
}

k.cdc.MustUnmarshal(b, &val)
return val, true
}

// RemoveElysStaked removes a elysStaked from the store
func (k Keeper) RemoveElysStaked(
ctx sdk.Context,
address string,

) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ElysStakedKeyPrefix))
store.Delete(types.ElysStakedKey(
address,
))
}

// GetAllElysStaked returns all elysStaked
func (k Keeper) GetAllElysStaked(ctx sdk.Context) (list []types.ElysStaked) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ElysStakedKeyPrefix))
iterator := sdk.KVStorePrefixIterator(store, []byte{})

defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
var val types.ElysStaked
k.cdc.MustUnmarshal(iterator.Value(), &val)
list = append(list, val)
}

return
}
10 changes: 10 additions & 0 deletions x/incentive/keeper/hooks_commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import (
func (k Keeper) CommitmentChanged(ctx sdk.Context, creator string, amount sdk.Coin) {
}

// Process eden uncommitted hook
func (k Keeper) EdenUncommitted(ctx sdk.Context, creator string, amount sdk.Coin) {
k.BurnEdenBFromEdenUncommitted(ctx, creator, amount.Amount)
}

// ___________________________________________________________________________________________________

// Hooks wrapper struct for incentive keeper
Expand All @@ -27,3 +32,8 @@ func (k Keeper) CommitmentHooks() CommitmentHooks {
func (h CommitmentHooks) CommitmentChanged(ctx sdk.Context, creator string, amount sdk.Coin) {
h.k.CommitmentChanged(ctx, creator, amount)
}

// EdenUncommitted implements EdenUncommitted
func (h CommitmentHooks) EdenUncommitted(ctx sdk.Context, creator string, amount sdk.Coin) {
h.k.EdenUncommitted(ctx, creator, amount)
}
2 changes: 1 addition & 1 deletion x/incentive/keeper/hooks_staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (k Keeper) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress,

// Updating commitments on delegation changes
func (k Keeper) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error {
return nil
return k.BurnEdenBFromElysUnstaking(ctx, delAddr)
}

func (k Keeper) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error {
Expand Down
16 changes: 15 additions & 1 deletion x/incentive/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,21 @@ func (k Keeper) UpdateUncommittedTokens(ctx sdk.Context, epochIdentifier string,

// Calculate new uncommitted Eden tokens from Eden & Eden boost committed, Dex rewards distribution
// Distribute gas fees to stakers
newUncommittedEdenTokens, dexRewards, dexRewardsByStakers := k.CalculateRewardsForStakers(ctx, delegatedAmt, commitments, edenAmountPerEpochStakers, dexRevenueStakersAmt)

// Calculate new uncommitted Eden tokens from Elys staked
newUncommittedEdenTokens, dexRewards, dexRewardsByStakers := k.CalculateRewardsForStakersByElysStaked(ctx, delegatedAmt, edenAmountPerEpochStakers, dexRevenueStakersAmt)
totalEdenGiven = totalEdenGiven.Add(newUncommittedEdenTokens)
totalRewardsGiven = totalRewardsGiven.Add(dexRewards)

// Calculate new uncommitted Eden tokens from Eden committed
edenCommitted := commitments.GetCommittedAmountForDenom(ptypes.Eden)
newUncommittedEdenTokens, dexRewards = k.CalculateRewardsForStakersByCommitted(ctx, edenCommitted, edenAmountPerEpochStakers, dexRevenueStakersAmt)
totalEdenGiven = totalEdenGiven.Add(newUncommittedEdenTokens)
totalRewardsGiven = totalRewardsGiven.Add(dexRewards)

// Calculate new uncommitted Eden tokens from Eden Boost committed
edenBoostCommitted := commitments.GetCommittedAmountForDenom(ptypes.EdenB)
newUncommittedEdenTokens, dexRewards = k.CalculateRewardsForStakersByCommitted(ctx, edenBoostCommitted, edenAmountPerEpochStakers, dexRevenueStakersAmt)
totalEdenGiven = totalEdenGiven.Add(newUncommittedEdenTokens)
totalRewardsGiven = totalRewardsGiven.Add(dexRewards)

Expand Down
Loading

0 comments on commit dabd7e8

Please sign in to comment.