/
position_close.go
87 lines (72 loc) · 2.74 KB
/
position_close.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package keeper
import (
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/leveragelp/types"
)
func (k Keeper) ForceCloseLong(ctx sdk.Context, position types.Position, pool types.Pool, lpAmount math.Int) (math.Int, error) {
if lpAmount.GT(position.LeveragedLpAmount) || lpAmount.IsNegative() {
return sdk.ZeroInt(), types.ErrInvalidCloseSize
}
// Exit liquidity with collateral token
exitCoins, err := k.amm.ExitPool(ctx, position.GetPositionAddress(), position.AmmPoolId, lpAmount, sdk.Coins{}, position.Collateral.Denom)
if err != nil {
return sdk.ZeroInt(), err
}
// Repay with interest
debt := k.stableKeeper.UpdateInterestStackedByAddress(ctx, position.GetPositionAddress())
// Ensure position.LeveragedLpAmount is not zero to avoid division by zero
if position.LeveragedLpAmount.IsZero() {
return sdk.ZeroInt(), types.ErrAmountTooLow
}
repayAmount := debt.Borrowed.Add(debt.InterestStacked).Sub(debt.InterestPaid).Mul(lpAmount).Quo(position.LeveragedLpAmount)
if err != nil {
return sdk.ZeroInt(), err
}
err = k.stableKeeper.Repay(ctx, position.GetPositionAddress(), sdk.NewCoin(position.Collateral.Denom, repayAmount))
if err != nil {
return sdk.ZeroInt(), err
}
userAmount := exitCoins[0].Amount.Sub(repayAmount)
positionOwner := sdk.MustAccAddressFromBech32(position.Address)
err = k.bankKeeper.SendCoins(ctx, positionOwner, position.GetPositionAddress(), sdk.Coins{sdk.NewCoin(position.Collateral.Denom, userAmount)})
if err != nil {
return sdk.ZeroInt(), err
}
position.LeveragedLpAmount = position.LeveragedLpAmount.Sub(lpAmount)
if position.LeveragedLpAmount.IsZero() {
err = k.DestroyPosition(ctx, position.Address, position.Id)
if err != nil {
return sdk.ZeroInt(), err
}
} else {
k.SetPosition(ctx, &position)
}
pool.LeveragedLpAmount = pool.LeveragedLpAmount.Sub(lpAmount)
k.UpdatePoolHealth(ctx, &pool)
// Hooks after leveragelp position closed
if k.hooks != nil {
k.hooks.AfterLeveragelpPositionClosed(ctx, pool)
}
return repayAmount, nil
}
func (k Keeper) CloseLong(ctx sdk.Context, msg *types.MsgClose) (*types.Position, math.Int, error) {
// Retrieve Position
position, err := k.GetPosition(ctx, msg.Creator, msg.Id)
if err != nil {
return nil, sdk.ZeroInt(), err
}
// Retrieve Pool
pool, found := k.GetPool(ctx, position.AmmPoolId)
if !found {
return nil, sdk.ZeroInt(), errorsmod.Wrap(types.ErrInvalidBorrowingAsset, "invalid pool id")
}
// If lpAmount is lower than zero, close full amount
lpAmount := msg.LpAmount
if lpAmount.IsNil() || lpAmount.LTE(sdk.ZeroInt()) {
lpAmount = position.LeveragedLpAmount
}
repayAmount, err := k.ForceCloseLong(ctx, position, pool, lpAmount)
return &position, repayAmount, err
}