Skip to content

Commit

Permalink
[Perpetual/Masterchef]: Add perpetual fee collection function in Mast…
Browse files Browse the repository at this point in the history
…erchef (#827)

* collect

* collect perp revenue

* add

* add test
  • Loading branch information
amityadav0 authored Oct 1, 2024
1 parent 8506a2b commit 0954068
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 20 deletions.
25 changes: 13 additions & 12 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,18 @@ func NewElysApp(
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

app.PerpetualKeeper = *perpetualmodulekeeper.NewKeeper(
appCodec,
keys[perpetualmoduletypes.StoreKey],
keys[perpetualmoduletypes.MemStoreKey],
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
&app.AmmKeeper,
app.BankKeeper,
app.OracleKeeper,
app.AssetprofileKeeper,
&app.ParameterKeeper,
)

app.MasterchefKeeper = *masterchefmodulekeeper.NewKeeper(
appCodec,
keys[masterchefmoduletypes.StoreKey],
Expand All @@ -842,6 +854,7 @@ func NewElysApp(
app.TokenomicsKeeper,
app.AccountKeeper,
app.BankKeeper,
app.PerpetualKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
masterchefModule := masterchefmodule.NewAppModule(appCodec, app.MasterchefKeeper, app.AccountKeeper, app.BankKeeper)
Expand Down Expand Up @@ -988,18 +1001,6 @@ func NewElysApp(
}
govKeeper.SetLegacyRouter(govRouter)

app.PerpetualKeeper = *perpetualmodulekeeper.NewKeeper(
appCodec,
keys[perpetualmoduletypes.StoreKey],
keys[perpetualmoduletypes.MemStoreKey],
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
&app.AmmKeeper,
app.BankKeeper,
app.OracleKeeper,
app.AssetprofileKeeper,
&app.ParameterKeeper,
)

app.ClockKeeper = *clockmodulekeeper.NewKeeper(
keys[clockmoduletypes.StoreKey],
appCodec,
Expand Down
1 change: 1 addition & 0 deletions testutil/keeper/masterchef.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func MasterchefKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
nil,
nil,
nil,
nil,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

Expand Down
58 changes: 51 additions & 7 deletions x/masterchef/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func (k Keeper) UpdateLPRewards(ctx sdk.Context) error {

// Collect Gas fees + swap fees
gasFeesForLpsDec := k.CollectGasFees(ctx, baseCurrency)
gasFeesForLpsDec = gasFeesForLpsDec.Add(k.CollectPerpRevenue(ctx, baseCurrency)...)
_, _, rewardsPerPool := k.CollectDEXRevenue(ctx)

// USDC amount in sdk.Dec type
Expand Down Expand Up @@ -292,12 +293,11 @@ func (k Keeper) UpdateLPRewards(ctx sdk.Context) error {

// Move gas fees collected to dex revenue wallet
// Convert it into USDC
func (k Keeper) ConvertGasFeesToUsdc(ctx sdk.Context, baseCurrency string) sdk.Coins {
func (k Keeper) ConvertGasFeesToUsdc(ctx sdk.Context, baseCurrency string, address sdk.AccAddress) sdk.Coins {
// fetch and clear the collected fees for distribution, since this is
// called in BeginBlock, collected fees will be from the previous block
// (and distributed to the previous proposer)
feeCollector := k.authKeeper.GetModuleAccount(ctx, authtypes.FeeCollectorName)
feesCollected := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress())
feesCollected := k.bankKeeper.GetAllBalances(ctx, address)

// Total Swapped coin
totalSwappedCoins := sdk.Coins{}
Expand Down Expand Up @@ -331,7 +331,7 @@ func (k Keeper) ConvertGasFeesToUsdc(ctx sdk.Context, baseCurrency string) sdk.C
// Settles balances between the tx sender and the pool to match the swap that was executed earlier.
// Also emits a swap event and updates related liquidity metrics.
cacheCtx, write := ctx.CacheContext()
_, err = k.amm.UpdatePoolForSwap(cacheCtx, pool, feeCollector.GetAddress(), feeCollector.GetAddress(), tokenIn, tokenOutCoin, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
_, err = k.amm.UpdatePoolForSwap(cacheCtx, pool, address, address, tokenIn, tokenOutCoin, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
if err != nil {
continue
}
Expand All @@ -349,9 +349,9 @@ func (k Keeper) ConvertGasFeesToUsdc(ctx sdk.Context, baseCurrency string) sdk.C

func (k Keeper) CollectGasFees(ctx sdk.Context, baseCurrency string) sdk.DecCoins {
params := k.GetParams(ctx)

feeCollector := k.authKeeper.GetModuleAccount(ctx, authtypes.FeeCollectorName)
// Calculate each portion of Gas fees collected - stakers, LPs
fees := k.ConvertGasFeesToUsdc(ctx, baseCurrency)
fees := k.ConvertGasFeesToUsdc(ctx, baseCurrency, feeCollector.GetAddress())
gasFeeCollectedDec := sdk.NewDecCoinsFromCoins(fees...)

gasFeesForLpsDec := gasFeeCollectedDec.MulDecTruncate(params.RewardPortionForLps)
Expand Down Expand Up @@ -387,12 +387,56 @@ func (k Keeper) CollectGasFees(ctx sdk.Context, baseCurrency string) sdk.DecCoin
return gasFeesForLpsDec
}

// Collect all Perpetual module revenues to Perpetual revenue wallet,
// transfer collected fees from perpetual moduleto the distribution module account
// Coins are not in usdc, so convert them to usdc
func (k Keeper) CollectPerpRevenue(ctx sdk.Context, baseCurrency string) sdk.DecCoins {
fundAddr := k.perpetualKeeper.GetIncrementalBorrowInterestPaymentFundAddress(ctx)
params := k.GetParams(ctx)
// Transfer revenue to a single wallet of Perpetual revenue wallet.
fees := k.ConvertGasFeesToUsdc(ctx, baseCurrency, fundAddr)
// Calculate each portion of Gas fees collected - stakers, LPs
perpFeeCollectedDec := sdk.NewDecCoinsFromCoins(fees...)

perpFeesForLpsDec := perpFeeCollectedDec.MulDecTruncate(params.RewardPortionForLps)
perpFeesForStakersDec := perpFeeCollectedDec.MulDecTruncate(params.RewardPortionForStakers)
perpFeesForProtocolDec := perpFeeCollectedDec.Sub(perpFeesForLpsDec).Sub(perpFeesForStakersDec)

k.AddFeeInfo(ctx, perpFeesForLpsDec.AmountOf(baseCurrency), perpFeesForStakersDec.AmountOf(baseCurrency), perpFeesForProtocolDec.AmountOf(baseCurrency), true)

lpsGasFeeCoins, _ := perpFeesForLpsDec.TruncateDecimal()
protocolGasFeeCoins, _ := perpFeesForProtocolDec.TruncateDecimal()

// Send coins from fund address to masterchef
if lpsGasFeeCoins.IsAllPositive() {
err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, fundAddr, types.ModuleName, lpsGasFeeCoins)
if err != nil {
panic(err)
}
}

// Send coins to protocol revenue address
if protocolGasFeeCoins.IsAllPositive() {
protocolRevenueAddress, err := sdk.AccAddressFromBech32(params.ProtocolRevenueAddress)
if err != nil {
// Handle the error by skipping the fee distribution
ctx.Logger().Error("Invalid protocol revenue address", "error", err)
return perpFeesForLpsDec
}
err = k.bankKeeper.SendCoins(ctx, fundAddr, protocolRevenueAddress, protocolGasFeeCoins)
if err != nil {
panic(err)
}
}
return perpFeesForLpsDec
}

// Collect all DEX revenues to DEX revenue wallet,
// while tracking the 60% of it for LPs reward distribution
// transfer collected fees from different wallets(liquidity pool, perpetual module etc) to the distribution module account
// Assume this is already in USDC.
func (k Keeper) CollectDEXRevenue(ctx sdk.Context) (sdk.Coins, sdk.DecCoins, map[uint64]sdk.Dec) {
// Total colllected revenue amount
// Total collected revenue amount
amountTotalCollected := sdk.Coins{}
amountLPsCollected := sdk.DecCoins{}
rewardsPerPool := make(map[uint64]sdk.Dec)
Expand Down
28 changes: 28 additions & 0 deletions x/masterchef/keeper/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
ammtypes "github.com/elys-network/elys/x/amm/types"
ctypes "github.com/elys-network/elys/x/commitment/types"
ptypes "github.com/elys-network/elys/x/parameter/types"
perptypes "github.com/elys-network/elys/x/perpetual/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 @@ -317,3 +319,29 @@ func TestCollectDEXRevenue(t *testing.T) {
// It should be 1950=3000*0.65 usdc
require.Equal(t, rewardForLpsAmt, sdk.DecCoins{sdk.NewDecCoin(ptypes.BaseCurrency, sdk.NewInt(1800))})
}

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

mk, perp := app.MasterchefKeeper, app.PerpetualKeeper

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

perpParams := perptypes.DefaultParams()
perpParams.IncrementalBorrowInterestPaymentFundAddress = addr[0].String()
perp.SetParams(ctx, &perpParams)

// Fill in perpetual revenue wallet
usdcRevToken2 := sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(3000)))
err := app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcRevToken2)
require.NoError(t, err)
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, ammtypes.ModuleName, addr[0], usdcRevToken2)
require.NoError(t, err)

fees := mk.CollectPerpRevenue(ctx, ptypes.BaseCurrency)

// It should be 1950=3000*0.65 usdc
require.Equal(t, fees, sdk.DecCoins{sdk.NewDecCoin(ptypes.BaseCurrency, sdk.NewInt(1800))})
}
3 changes: 3 additions & 0 deletions x/masterchef/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type (
tokenomicsKeeper types.TokenomicsKeeper
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
perpetualKeeper types.PeperpetualKeeper

authority string // gov module addresss
}
Expand All @@ -49,6 +50,7 @@ func NewKeeper(
tokenomicsKeeper types.TokenomicsKeeper,
ak types.AccountKeeper,
bk types.BankKeeper,
perpetualKeeper types.PeperpetualKeeper,
authority string,
) *Keeper {
return &Keeper{
Expand All @@ -66,6 +68,7 @@ func NewKeeper(
tokenomicsKeeper: tokenomicsKeeper,
authKeeper: ak,
bankKeeper: bk,
perpetualKeeper: perpetualKeeper,
authority: authority,
}
}
Expand Down
8 changes: 8 additions & 0 deletions x/masterchef/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
ctypes "github.com/elys-network/elys/x/commitment/types"
oracletypes "github.com/elys-network/elys/x/oracle/types"
parametertypes "github.com/elys-network/elys/x/parameter/types"
perpetualtypes "github.com/elys-network/elys/x/perpetual/types"

stabletypes "github.com/elys-network/elys/x/stablestake/types"
tokenomictypes "github.com/elys-network/elys/x/tokenomics/types"
)
Expand Down Expand Up @@ -62,6 +64,7 @@ type BankKeeper interface {
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error

BlockedAddr(addr sdk.AccAddress) bool
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
Expand Down Expand Up @@ -140,3 +143,8 @@ type TokenomicsKeeper interface {
type ParameterKeeper interface {
GetParams(ctx sdk.Context) (params parametertypes.Params)
}

type PeperpetualKeeper interface {
GetParams(ctx sdk.Context) (params perpetualtypes.Params)
GetIncrementalBorrowInterestPaymentFundAddress(ctx sdk.Context) sdk.AccAddress
}
1 change: 0 additions & 1 deletion x/perpetual/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,6 @@ func (k Keeper) TakeFundPayment(ctx sdk.Context, returnAmount math.Int, returnAs
return sdk.ZeroInt(), err
}
err = k.bankKeeper.SendCoins(ctx, ammPoolAddr, fundAddr, takeCoins)
//err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, ammPool.Address, fundAddr, takeCoins)
if err != nil {
return sdk.ZeroInt(), err
}
Expand Down

0 comments on commit 0954068

Please sign in to comment.