Skip to content

Commit ef337d0

Browse files
authored
LeverageLp exit fees (#1408)
* distribute fees * add tracking * expected keeper
1 parent 67b8fa0 commit ef337d0

File tree

5 files changed

+59
-4
lines changed

5 files changed

+59
-4
lines changed

app/keepers/keepers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ func NewAppKeeper(
693693
app.CommitmentKeeper,
694694
app.MasterchefKeeper,
695695
app.AccountedPoolKeeper,
696+
app.ParameterKeeper,
696697
)
697698

698699
app.StablestakeKeeper.SetLeverageLpKeeper(app.LeveragelpKeeper)

testutil/keeper/leveragelp.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func LeveragelpKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
4444
nil,
4545
nil,
4646
nil,
47+
nil,
4748
)
4849

4950
ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())

x/leveragelp/keeper/keeper.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type (
3232
commKeeper types.CommitmentKeeper
3333
masterchefKeeper types.MasterchefKeeper
3434
accountedPoolKeeper types.AccountedPoolKeeper
35+
parameterKeeper types.ParameterKeeper
3536

3637
hooks types.LeverageLpHooks
3738
}
@@ -48,6 +49,7 @@ func NewKeeper(
4849
commitmentKeeper types.CommitmentKeeper,
4950
masterchefKeeper types.MasterchefKeeper,
5051
accountedPoolKeeper types.AccountedPoolKeeper,
52+
parameterKeeper types.ParameterKeeper,
5153
) *Keeper {
5254
// ensure that authority is a valid AccAddress
5355
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
@@ -65,6 +67,7 @@ func NewKeeper(
6567
commKeeper: commitmentKeeper,
6668
masterchefKeeper: masterchefKeeper,
6769
accountedPoolKeeper: accountedPoolKeeper,
70+
parameterKeeper: parameterKeeper,
6871
}
6972

7073
return keeper

x/leveragelp/keeper/position_close.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,37 @@ func (k Keeper) CheckHealthStopLossThenRepayAndClose(ctx sdk.Context, position *
174174
var coinsForAmm sdk.Coins
175175
if percentageExitLeverageFee.IsPositive() && len(coinsLeftAfterRepay) > 0 {
176176
coinsForAmm = ammkeeper.PortionCoins(coinsLeftAfterRepay, percentageExitLeverageFee)
177-
weightBreakingFeePortion := k.amm.GetParams(ctx).WeightBreakingFeePortion
178177

179-
coinsToAmmRebalancer := ammkeeper.PortionCoins(coinsForAmm, osmomath.BigDecFromDec(weightBreakingFeePortion))
178+
totalFeeValue := weightBreakingFeeValue.Add(slippageValue).Add(swapFeeValue).Add(takerFeeValue)
179+
// 1. weightBreakingFeePortion
180+
weightBreakingFee := weightBreakingFeeValue.Quo(totalFeeValue)
181+
weightBreakingFeePortion := osmomath.BigDecFromDec(k.amm.GetParams(ctx).WeightBreakingFeePortion).Mul(weightBreakingFee)
182+
183+
coinsToAmmRebalancer := ammkeeper.PortionCoins(coinsForAmm, weightBreakingFeePortion)
180184
coinsToAmmPool := coinsForAmm.Sub(coinsToAmmRebalancer...)
181185

186+
// Track weight breaking fee
187+
for _, coin := range coinsToAmmPool {
188+
k.amm.TrackWeightBreakingSlippage(ctx, position.AmmPoolId, coin)
189+
}
190+
191+
// 2. slippageFeePortion
192+
slippageFee := slippageValue.Quo(totalFeeValue)
193+
coinsForSlippage := ammkeeper.PortionCoins(coinsForAmm, slippageFee)
194+
195+
// Track slippage fee
196+
for _, coin := range coinsForSlippage {
197+
k.amm.TrackWeightBreakingSlippage(ctx, position.AmmPoolId, coin)
198+
k.amm.TrackSlippage(ctx, position.AmmPoolId, coin)
199+
}
200+
182201
// Very important to fetch this again, Updating ammPool
183202
ammPool, _ = k.amm.GetPool(ctx, position.AmmPoolId)
184-
err = k.bankKeeper.SendCoins(ctx, position.GetPositionAddress(), sdk.MustAccAddressFromBech32(ammPool.Address), coinsToAmmPool)
203+
err = k.bankKeeper.SendCoins(ctx, position.GetPositionAddress(), sdk.MustAccAddressFromBech32(ammPool.Address), coinsToAmmPool.Add(coinsForSlippage...))
185204
if err != nil {
186205
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
187206
}
188-
err = k.amm.AddToPoolBalanceAndUpdateLiquidity(ctx, &ammPool, math.ZeroInt(), coinsToAmmPool)
207+
err = k.amm.AddToPoolBalanceAndUpdateLiquidity(ctx, &ammPool, math.ZeroInt(), coinsToAmmPool.Add(coinsForSlippage...))
189208
if err != nil {
190209
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
191210
}
@@ -195,6 +214,29 @@ func (k Keeper) CheckHealthStopLossThenRepayAndClose(ctx sdk.Context, position *
195214
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
196215
}
197216

217+
// 3. swapFeePortion
218+
swapFee := swapFeeValue.Quo(totalFeeValue)
219+
coinsForSwap := ammkeeper.PortionCoins(coinsForAmm, swapFee)
220+
221+
rebalanceTreasury := sdk.MustAccAddressFromBech32(ammPool.GetRebalanceTreasury())
222+
err = k.bankKeeper.SendCoins(ctx, position.GetPositionAddress(), rebalanceTreasury, coinsForSwap)
223+
if err != nil {
224+
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
225+
}
226+
227+
err = k.amm.OnCollectFee(ctx, ammPool, coinsForSwap)
228+
if err != nil {
229+
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
230+
}
231+
232+
// 4. takerFeePortion
233+
takerFee := takerFeeValue.Quo(totalFeeValue)
234+
coinsForTaker := ammkeeper.PortionCoins(coinsForAmm, takerFee)
235+
236+
err = k.bankKeeper.SendCoins(ctx, position.GetPositionAddress(), sdk.MustAccAddressFromBech32(k.parameterKeeper.GetParams(ctx).TakerFeeCollectionAddress), coinsForTaker)
237+
if err != nil {
238+
return osmomath.ZeroBigDec(), math.ZeroInt(), sdk.Coins{}, math.ZeroInt(), sdk.Coins{}, osmomath.ZeroBigDec(), stopLossReached, osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), osmomath.ZeroBigDec(), err
239+
}
198240
}
199241

200242
// anything left over in position balance goes to user

x/leveragelp/types/expected_keepers.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
ammtypes "github.com/elys-network/elys/v7/x/amm/types"
99
assetprofiletypes "github.com/elys-network/elys/v7/x/assetprofile/types"
1010
commitmenttypes "github.com/elys-network/elys/v7/x/commitment/types"
11+
parameterstypes "github.com/elys-network/elys/v7/x/parameter/types"
1112
stablestaketypes "github.com/elys-network/elys/v7/x/stablestake/types"
1213
"github.com/osmosis-labs/osmosis/osmomath"
1314
)
@@ -35,6 +36,9 @@ type AmmKeeper interface {
3536
CalcInAmtGivenOut(ctx sdk.Context, poolId uint64, oracle ammtypes.OracleKeeper, snapshot ammtypes.SnapshotPool, tokensOut sdk.Coins, tokenInDenom string, swapFee osmomath.BigDec) (tokenIn sdk.Coin, slippage osmomath.BigDec, tokenInDec osmomath.BigDec, err error)
3637
JoinPoolNoSwap(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, shareOutAmount sdkmath.Int, tokenInMaxs sdk.Coins) (tokenIn sdk.Coins, sharesOut sdkmath.Int, err error)
3738
ExitPool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, shareInAmount sdkmath.Int, tokenOutMins sdk.Coins, tokenOutDenom string, isLiquidation, applyWeightBreakingFee bool) (exitCoins sdk.Coins, weightBalanceBonus osmomath.BigDec, slippage osmomath.BigDec, swapFee osmomath.BigDec, takerFeesFinal osmomath.BigDec, err error)
39+
OnCollectFee(ctx sdk.Context, pool ammtypes.Pool, coins sdk.Coins) error
40+
TrackWeightBreakingSlippage(ctx sdk.Context, poolId uint64, token sdk.Coin)
41+
TrackSlippage(ctx sdk.Context, poolId uint64, amount sdk.Coin)
3842
}
3943

4044
// BankKeeper defines the expected interface needed to retrieve account balances.
@@ -90,3 +94,7 @@ type MasterchefKeeper interface {
9094
type AccountedPoolKeeper interface {
9195
GetAccountedBalance(sdk.Context, uint64, string) sdkmath.Int
9296
}
97+
98+
type ParameterKeeper interface {
99+
GetParams(ctx sdk.Context) (params parameterstypes.Params)
100+
}

0 commit comments

Comments
 (0)