Skip to content

Commit

Permalink
[Masterchef]: Tests (#892)
Browse files Browse the repository at this point in the history
* add external incentive test

* ext

---------

Co-authored-by: Abhinav Kumar <57705190+avkr003@users.noreply.github.com>
  • Loading branch information
amityadav0 and avkr003 authored Oct 31, 2024
1 parent fc39f28 commit eca0a53
Show file tree
Hide file tree
Showing 2 changed files with 355 additions and 0 deletions.
149 changes: 149 additions & 0 deletions x/masterchef/keeper/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
simapp "github.com/elys-network/elys/app"
ammtypes "github.com/elys-network/elys/x/amm/types"
ctypes "github.com/elys-network/elys/x/commitment/types"
"github.com/elys-network/elys/x/masterchef/types"
ptypes "github.com/elys-network/elys/x/parameter/types"
perptypes "github.com/elys-network/elys/x/perpetual/types"

Expand Down Expand Up @@ -345,3 +346,151 @@ func TestCollectPerpRevenue(t *testing.T) {
// It should be 1950=3000*0.65 usdc
require.Equal(t, fees, sdk.DecCoins{sdk.NewDecCoin(ptypes.BaseCurrency, sdk.NewInt(1800))})
}

func TestExternalRewardsDistribution(t *testing.T) {
app := simapp.InitElysTestApp(true)
ctx := app.BaseApp.NewContext(true, tmproto.Header{})

mk, bk, amm, oracle := app.MasterchefKeeper, app.BankKeeper, app.AmmKeeper, app.OracleKeeper

// Setup coin prices
SetupStableCoinPrices(ctx, oracle)

// Generate 1 random account with 1000stake balanced
addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000))

// Create 2 pools

// #######################
// ####### POOL 1 ########
// Mint 100000USDC
usdcToken := sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000)))

err := bk.MintCoins(ctx, ammtypes.ModuleName, usdcToken)
require.NoError(t, err)
err = bk.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[0], usdcToken)
require.NoError(t, err)

poolAssets := []ammtypes.PoolAsset{
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.Elys, sdk.NewInt(100000)),
},
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000)),
},
}

argSwapFee := sdk.MustNewDecFromStr("0.1")
argExitFee := sdk.MustNewDecFromStr("0.1")

poolParams := &ammtypes.PoolParams{
SwapFee: argSwapFee,
ExitFee: argExitFee,
}

msg := ammtypes.NewMsgCreatePool(
addr[0].String(),
poolParams,
poolAssets,
)

// Create a Elys+USDC pool
poolId, err := amm.CreatePool(ctx, msg)
require.NoError(t, err)
require.Equal(t, poolId, uint64(1))

// ####### POOL 2 ########
// ATOM+USDC pool
// Mint uusdc
usdcToken = sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(200000)))

err = app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcToken)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[1], usdcToken)
require.NoError(t, err)

// Mint uatom
atomToken := sdk.NewCoins(sdk.NewCoin(ptypes.ATOM, sdk.NewInt(200000)))
err = bk.MintCoins(ctx, ammtypes.ModuleName, atomToken)
require.NoError(t, err)
err = bk.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[1], atomToken)
require.NoError(t, err)

poolAssets2 := []ammtypes.PoolAsset{
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.ATOM, sdk.NewInt(150000)),
},
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000)),
},
}

msg = ammtypes.NewMsgCreatePool(
addr[1].String(),
poolParams,
poolAssets2,
)

// Create a ATOM+USDC pool
poolId, err = amm.CreatePool(ctx, msg)
require.NoError(t, err)
require.Equal(t, poolId, uint64(2))

pools := amm.GetAllPool(ctx)

// check length of pools
require.Equal(t, len(pools), 2)

externalIncentive := types.ExternalIncentive{
Id: 0,
RewardDenom: "reward1",
PoolId: 1,
FromBlock: ctx.BlockHeight() - 1,
ToBlock: ctx.BlockHeight() + 101,
AmountPerBlock: sdk.OneInt(),
Apr: sdk.ZeroDec(),
}

mk.SetExternalIncentive(ctx, externalIncentive)

_, found := mk.GetPoolRewardInfo(ctx, externalIncentive.PoolId, externalIncentive.RewardDenom)
require.False(t, found)

mk.ProcessExternalRewardsDistribution(ctx)

pool, found := mk.GetPoolInfo(ctx, externalIncentive.PoolId)
require.True(t, found)
require.Equal(t, pool.ExternalRewardDenoms, []string{"reward1"})

rewardInfo, found := mk.GetPoolRewardInfo(ctx, externalIncentive.PoolId, externalIncentive.RewardDenom)
require.True(t, found)
require.Equal(t, rewardInfo.RewardDenom, externalIncentive.RewardDenom)
require.Equal(t, rewardInfo.PoolAccRewardPerShare, sdk.MustNewDecFromStr("0.000099900099900099"))

// Test multiple external incentives
externalIncentive2 := types.ExternalIncentive{
Id: 0,
RewardDenom: "reward2",
PoolId: 1,
FromBlock: ctx.BlockHeight() - 1,
ToBlock: ctx.BlockHeight() + 101,
AmountPerBlock: sdk.OneInt(),
Apr: sdk.ZeroDec(),
}
mk.SetExternalIncentive(ctx, externalIncentive2)

mk.ProcessExternalRewardsDistribution(ctx)

pool, found = mk.GetPoolInfo(ctx, externalIncentive.PoolId)
require.True(t, found)
require.Equal(t, pool.ExternalRewardDenoms, []string{"reward1", "reward2"})

rewardInfo, found = mk.GetPoolRewardInfo(ctx, externalIncentive2.PoolId, externalIncentive2.RewardDenom)
require.True(t, found)
require.Equal(t, rewardInfo.RewardDenom, externalIncentive2.RewardDenom)
require.Equal(t, rewardInfo.PoolAccRewardPerShare, sdk.MustNewDecFromStr("0.000099900099900099"))
}
206 changes: 206 additions & 0 deletions x/masterchef/keeper/external_incentive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ package keeper_test
import (
"testing"

"cosmossdk.io/math"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
simapp "github.com/elys-network/elys/app"
ammtypes "github.com/elys-network/elys/x/amm/types"
masterchefkeeper "github.com/elys-network/elys/x/masterchef/keeper"
"github.com/elys-network/elys/x/masterchef/types"
ptypes "github.com/elys-network/elys/x/parameter/types"
tokenomicskeeper "github.com/elys-network/elys/x/tokenomics/keeper"
tokenomicstypes "github.com/elys-network/elys/x/tokenomics/types"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -58,3 +66,201 @@ func TestExternalIncentive(t *testing.T) {
externalIncentivesStored = app.MasterchefKeeper.GetAllExternalIncentives(ctx)
require.Len(t, externalIncentivesStored, 2)
}

// Test USDC reward as external and via dex collection
func TestUSDCExternalIncentive(t *testing.T) {
app, _, _ := simapp.InitElysTestAppWithGenAccount()
ctx := app.BaseApp.NewContext(true, tmproto.Header{})

mk, amm, oracle := app.MasterchefKeeper, app.AmmKeeper, app.OracleKeeper

// Setup coin prices
SetupStableCoinPrices(ctx, oracle)

authority := authtypes.NewModuleAddress(govtypes.ModuleName).String()

srv := tokenomicskeeper.NewMsgServerImpl(app.TokenomicsKeeper)

expected := &tokenomicstypes.MsgCreateTimeBasedInflation{
Authority: authority,
StartBlockHeight: uint64(1),
EndBlockHeight: uint64(6307200),
Inflation: &tokenomicstypes.InflationEntry{
LmRewards: 9999999,
IcsStakingRewards: 9999999,
CommunityFund: 9999999,
StrategicReserve: 9999999,
TeamTokensVested: 9999999,
},
}

wctx := sdk.WrapSDKContext(ctx)
_, err := srv.CreateTimeBasedInflation(wctx, expected)
require.NoError(t, err)

expected = &tokenomicstypes.MsgCreateTimeBasedInflation{
Authority: authority,
StartBlockHeight: uint64(6307201),
EndBlockHeight: uint64(12614401),
Inflation: &tokenomicstypes.InflationEntry{
LmRewards: 9999999,
IcsStakingRewards: 9999999,
CommunityFund: 9999999,
StrategicReserve: 9999999,
TeamTokensVested: 9999999,
},
}
_, err = srv.CreateTimeBasedInflation(wctx, expected)
require.NoError(t, err)

// Generate 1 random account with 1000stake balanced
addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(10000000000))

// Create a pool
// Mint 100000USDC
usdcToken := sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000000000)))

err = app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcToken.MulInt(sdk.NewInt(2)))
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[0], usdcToken)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[1], usdcToken)
require.NoError(t, err)

usdcToken = sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000000000)))
err = app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcToken.MulInt(sdk.NewInt(2)))
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[0], usdcToken)
require.NoError(t, err)

poolAssets := []ammtypes.PoolAsset{
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.Elys, sdk.NewInt(10000000)),
},
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000000)),
},
}

argSwapFee := sdk.MustNewDecFromStr("0.0")
argExitFee := sdk.MustNewDecFromStr("0.0")

poolParams := &ammtypes.PoolParams{
SwapFee: argSwapFee,
ExitFee: argExitFee,
}

msg := ammtypes.NewMsgCreatePool(
addr[0].String(),
poolParams,
poolAssets,
)

// Create a Elys+USDC pool
poolId, err := amm.CreatePool(ctx, msg)
require.NoError(t, err)
require.Equal(t, poolId, uint64(1))

pools := amm.GetAllPool(ctx)

// check length of pools
require.Equal(t, len(pools), 1)

_, _, err = amm.ExitPool(ctx, addr[0], pools[0].PoolId, math.NewIntWithDecimal(1, 21), sdk.NewCoins(), "", false)
require.NoError(t, err)

// new user join pool with same shares
share := ammtypes.InitPoolSharesSupply.Mul(math.NewIntWithDecimal(1, 5))
t.Log(mk.GetPoolTotalCommit(ctx, pools[0].PoolId))
require.Equal(t, mk.GetPoolTotalCommit(ctx, pools[0].PoolId).String(), "10002000000000000000000000")
require.Equal(t, mk.GetPoolBalance(ctx, pools[0].PoolId, addr[0]).String(), "10000000000000000000000000")
_, _, err = amm.JoinPoolNoSwap(ctx, addr[1], pools[0].PoolId, share, sdk.NewCoins(sdk.NewCoin(ptypes.Elys, sdk.NewInt(10000000)), sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000000))))
require.NoError(t, err)
require.Equal(t, mk.GetPoolTotalCommit(ctx, pools[0].PoolId).String(), "20002000000000000000000000")
require.Equal(t, mk.GetPoolBalance(ctx, pools[0].PoolId, addr[1]), share)

atomToken := sdk.NewCoins(sdk.NewCoin("uatom", math.NewIntWithDecimal(100000000, 6)))
err = app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, atomToken)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[0], atomToken)
require.NoError(t, err)

masterchefSrv := masterchefkeeper.NewMsgServerImpl(app.MasterchefKeeper)
_, err = masterchefSrv.AddExternalRewardDenom(sdk.WrapSDKContext(ctx), &types.MsgAddExternalRewardDenom{
Authority: app.GovKeeper.GetAuthority(),
RewardDenom: ptypes.BaseCurrency,
MinAmount: sdk.OneInt(),
Supported: true,
})
require.NoError(t, err)
_, err = masterchefSrv.AddExternalIncentive(sdk.WrapSDKContext(ctx), &types.MsgAddExternalIncentive{
Sender: addr[0].String(),
RewardDenom: ptypes.BaseCurrency,
PoolId: pools[0].PoolId,
AmountPerBlock: math.NewIntWithDecimal(100, 6),
FromBlock: 0,
ToBlock: 1000,
})
require.NoError(t, err)

// Fill in pool revenue wallet
revenueAddress1 := ammtypes.NewPoolRevenueAddress(1)
usdcRevToken1 := sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000)))
err = app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcRevToken1)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, revenueAddress1, usdcRevToken1)
require.NoError(t, err)

// check rewards after 100 block
for i := 1; i <= 100; i++ {
mk.EndBlocker(ctx)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
}

require.Equal(t, ctx.BlockHeight(), int64(100))
poolRewardInfo, _ := app.MasterchefKeeper.GetPoolRewardInfo(ctx, pools[0].PoolId, ptypes.BaseCurrency)
require.Equal(t, poolRewardInfo.LastUpdatedBlock, uint64(99))

res, err := mk.UserPendingReward(ctx, &types.QueryUserPendingRewardRequest{
User: addr[0].String(),
})
require.NoError(t, err)
require.Equal(t, res.TotalRewards[0].Amount.String(), "4949545046")
res, err = mk.UserPendingReward(ctx, &types.QueryUserPendingRewardRequest{
User: addr[1].String(),
})
require.NoError(t, err)
require.Equal(t, res.TotalRewards[0].Amount.String(), "4949545046")

prevUSDCBal := app.BankKeeper.GetBalance(ctx, addr[1], ptypes.BaseCurrency)

// check rewards claimed
_, err = masterchefSrv.ClaimRewards(sdk.WrapSDKContext(ctx), &types.MsgClaimRewards{
Sender: addr[0].String(),
PoolIds: []uint64{pools[0].PoolId},
})
require.NoError(t, err)
_, err = masterchefSrv.ClaimRewards(sdk.WrapSDKContext(ctx), &types.MsgClaimRewards{
Sender: addr[1].String(),
PoolIds: []uint64{pools[0].PoolId},
})
require.NoError(t, err)

curUSDCBal := app.BankKeeper.GetBalance(ctx, addr[1], ptypes.BaseCurrency)
amount, _ := sdk.NewIntFromString("4949545046")
require.Equal(t, curUSDCBal.Amount.String(), prevUSDCBal.Amount.Add(amount).String())

// no pending rewards
res, err = mk.UserPendingReward(ctx, &types.QueryUserPendingRewardRequest{
User: addr[0].String(),
})
require.NoError(t, err)
require.Len(t, res.TotalRewards, 0)
res, err = mk.UserPendingReward(ctx, &types.QueryUserPendingRewardRequest{
User: addr[1].String(),
})
require.NoError(t, err)
require.Len(t, res.TotalRewards, 0)
}

0 comments on commit eca0a53

Please sign in to comment.