Skip to content

Commit

Permalink
Merge branch 'main' into consolidated_position_stoploss_price
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmic-vagabond authored Nov 20, 2023
2 parents 687a44c + 2816591 commit e7b37c9
Show file tree
Hide file tree
Showing 23 changed files with 454 additions and 300 deletions.
4 changes: 4 additions & 0 deletions proto/elys/margin/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,8 @@ message Params {
bool whitelisting_enabled = 18;
string invariant_check_epoch = 19;
string broker_address = 20;
string take_profit_borrow_interest_rate_min = 21 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
4 changes: 4 additions & 0 deletions proto/elys/margin/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ message MTP {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string take_profit_borrow_rate = 18 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message WhiteList {
Expand Down
16 changes: 0 additions & 16 deletions x/amm/types/calc_in_amt_given_out.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package types

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
Expand All @@ -21,15 +19,6 @@ func (p Pool) CalcInAmtGivenOut(
return sdk.Coin{}, err
}

// print tokensOut
fmt.Println("tokensOut: ", tokensOut)
// print tokenOut
fmt.Println("tokenOut: ", tokenOut)
// print poolAssetOut
fmt.Println("poolAssetOut: ", poolAssetOut)
// print poolAssetIn
fmt.Println("poolAssetIn: ", poolAssetIn)

outWeight := sdk.NewDecFromInt(poolAssetOut.Weight)
inWeight := sdk.NewDecFromInt(poolAssetIn.Weight)
if p.PoolParams.UseOracle {
Expand Down Expand Up @@ -66,8 +55,6 @@ func (p Pool) CalcInAmtGivenOut(
inWeight,
).Neg()

fmt.Println("tokenAmountIn: ", tokenAmountIn)

// We deduct a swap fee on the input asset. The swap happens by following the invariant curve on the input * (1 - swap fee)
// and then the swap fee is added to the pool.
// Thus in order to give X amount out, we solve the invariant for the invariant input. However invariant input = (1 - swapfee) * trade input.
Expand All @@ -78,9 +65,6 @@ func (p Pool) CalcInAmtGivenOut(
// Otherwise, the pool would under-charge by this rounding error.
tokenInAmt := tokenAmountInBeforeFee.Ceil().TruncateInt()

// print tokenInAmt
fmt.Println("tokenInAmt: ", tokenInAmt)

if !tokenInAmt.IsPositive() {
return sdk.Coin{}, sdkerrors.Wrapf(ErrInvalidMathApprox, "token amount must be positive")
}
Expand Down
1 change: 1 addition & 0 deletions x/margin/client/cli/query_mtp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func networkWithMTPObjects(t *testing.T, n int) (*network.Network, []*types.MTP)
ConsolidateLeverage: sdk.ZeroDec(),
SumCollateral: sdk.ZeroInt(),
TakeProfitPrice: sdk.MustNewDecFromStr(types.TakeProfitPriceDefault),
TakeProfitBorrowRate: sdk.OneDec(),
}

mtps = append(mtps, &mtp)
Expand Down
59 changes: 31 additions & 28 deletions x/margin/keeper/begin_blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,42 @@ func (k Keeper) BeginBlocker(ctx sdk.Context) {
epochLength := k.GetEpochLength(ctx)
epochPosition := k.GetEpochPosition(ctx, epochLength)

if epochPosition == 0 { // if epoch has passed
entry, found := k.apKeeper.GetEntry(ctx, ptypes.BaseCurrency)
if !found {
ctx.Logger().Error(sdkerrors.Wrapf(assetprofiletypes.ErrAssetProfileNotFound, "asset %s not found", ptypes.BaseCurrency).Error())
}
baseCurrency := entry.Denom
// if epoch has not passed
if epochPosition != 0 {
return
}

// if epoch has passed
entry, found := k.apKeeper.GetEntry(ctx, ptypes.BaseCurrency)
if !found {
ctx.Logger().Error(sdkerrors.Wrapf(assetprofiletypes.ErrAssetProfileNotFound, "asset %s not found", ptypes.BaseCurrency).Error())
}
baseCurrency := entry.Denom

currentHeight := ctx.BlockHeight()
pools := k.GetAllPools(ctx)
for _, pool := range pools {
ammPool, err := k.GetAmmPool(ctx, pool.AmmPoolId, "")
currentHeight := ctx.BlockHeight()
pools := k.GetAllPools(ctx)
for _, pool := range pools {
ammPool, err := k.GetAmmPool(ctx, pool.AmmPoolId, "")
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error getting amm pool: %d", pool.AmmPoolId)).Error())
continue // ?
}
if k.IsPoolEnabled(ctx, pool.AmmPoolId) {
rate, err := k.BorrowInterestRateComputation(ctx, pool, ammPool)
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error getting amm pool: %d", pool.AmmPoolId)).Error())
ctx.Logger().Error(err.Error())
continue // ?
}
if k.IsPoolEnabled(ctx, pool.AmmPoolId) {
rate, err := k.BorrowInterestRateComputation(ctx, pool, ammPool)
if err != nil {
ctx.Logger().Error(err.Error())
continue // ?
}
pool.BorrowInterestRate = rate
pool.LastHeightBorrowInterestRateComputed = currentHeight
_ = k.UpdatePoolHealth(ctx, &pool)
// TODO: function missing
// k.TrackSQBeginBlock(ctx, pool)
mtps, _, _ := k.GetMTPsForPool(ctx, pool.AmmPoolId, nil)
for _, mtp := range mtps {
BeginBlockerProcessMTP(ctx, k, mtp, pool, ammPool, baseCurrency)
}
pool.BorrowInterestRate = rate
pool.LastHeightBorrowInterestRateComputed = currentHeight
_ = k.UpdatePoolHealth(ctx, &pool)
// TODO: function missing
// k.TrackSQBeginBlock(ctx, pool)
mtps, _, _ := k.GetMTPsForPool(ctx, pool.AmmPoolId, nil)
for _, mtp := range mtps {
BeginBlockerProcessMTP(ctx, k, mtp, pool, ammPool, baseCurrency)
}
k.SetPool(ctx, pool)
}
k.SetPool(ctx, pool)
}

}
29 changes: 28 additions & 1 deletion x/margin/keeper/begin_blocker_process_mtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool type
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error calculating mtp take profit liabilities: %s", mtp.String())).Error())
return
}
// calculate and update take profit borrow rate
mtp.TakeProfitBorrowRate, err = k.CalcMTPTakeProfitBorrowRate(ctx, mtp)
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error calculating mtp take profit borrow rate: %s", mtp.String())).Error())
return
}
h, err := k.UpdateMTPHealth(ctx, *mtp, ammPool, baseCurrency)
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error updating mtp health: %s", mtp.String())).Error())
Expand Down Expand Up @@ -56,6 +62,27 @@ func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool type

_ = k.SetMTP(ctx, mtp)

for _, custody := range mtp.Custodies {
assetPrice, err := k.EstimateSwapGivenOut(ctx, sdk.NewCoin(custody.Denom, sdk.NewInt(1)), baseCurrency, ammPool)
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error estimating swap given out: %s", custody.Denom)).Error())
return
}
if mtp.TakeProfitPrice.GT(sdk.NewDecFromInt(assetPrice)) {
break
}
ctx.Logger().Error(fmt.Sprintf("error executing force close on position %s because take profit price %s is less than asset price %s", mtp.String(), mtp.TakeProfitPrice.String(), sdk.NewDecFromInt(assetPrice).String()))
return
}

// check MTP health against threshold
safetyFactor := k.GetSafetyFactor(ctx)

if mtp.MtpHealth.GT(safetyFactor) {
ctx.Logger().Error(errors.Wrap(types.ErrMTPHealthy, "error executing force close because mtp is healthy").Error())
return
}

var repayAmount sdk.Int
switch mtp.Position {
case types.Position_LONG:
Expand All @@ -69,7 +96,7 @@ func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool type
if err == nil {
// Emit event if position was closed
k.EmitForceClose(ctx, mtp, repayAmount, "")
} else if err != types.ErrMTPHealthy {
} else {
ctx.Logger().Error(errors.Wrap(err, "error executing force close").Error())
}

Expand Down
3 changes: 3 additions & 0 deletions x/margin/keeper/calc_mtp_interest_liabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,8 @@ func (k Keeper) CalcMTPBorrowInterestLiabilities(ctx sdk.Context, mtp *types.MTP
borrowInterestNewInt = sdk.NewInt(1)
}

// apply take profit borrow rate to borrow interest
borrowInterestNewInt = sdk.NewDecFromInt(borrowInterestNewInt).Mul(mtp.TakeProfitBorrowRate).TruncateInt()

return borrowInterestNewInt
}
36 changes: 36 additions & 0 deletions x/margin/keeper/calc_mtp_take_profit_borrow_rate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/margin/types"
)

func (k Keeper) CalcMTPTakeProfitBorrowRate(ctx sdk.Context, mtp *types.MTP) (sdk.Dec, error) {
// Check if there are any takeProfitCustodies to avoid division by zero
if len(mtp.TakeProfitCustodies) == 0 {
return sdk.ZeroDec(), nil
}

var totalTakeProfitBorrowRate sdk.Dec = sdk.ZeroDec()
for takeProfitCustodyIndex, takeProfitCustody := range mtp.TakeProfitCustodies {
// Calculate the borrow rate for this takeProfitCustody
takeProfitBorrowRateInt := takeProfitCustody.Amount.Quo(mtp.Custodies[takeProfitCustodyIndex].Amount)

// Convert takeProfitBorrowRateInt from sdk.Int to sdk.Dec
takeProfitBorrowRateDec := sdk.NewDecFromInt(takeProfitBorrowRateInt)

// Add this take profit borrow rate to the total
totalTakeProfitBorrowRate = totalTakeProfitBorrowRate.Add(takeProfitBorrowRateDec)
}

// Calculate the average take profit borrow rate
averageTakeProfitBorrowRate := totalTakeProfitBorrowRate.Quo(sdk.NewDec(int64(len(mtp.TakeProfitCustodies))))

// Get Margin Params
params := k.GetParams(ctx)

// Use TakeProfitBorrowInterestRateMin param as minimum take profit borrow rate
averageTakeProfitBorrowRate = sdk.MaxDec(averageTakeProfitBorrowRate, params.TakeProfitBorrowInterestRateMin)

return averageTakeProfitBorrowRate, nil
}
3 changes: 0 additions & 3 deletions x/margin/keeper/calc_mtp_take_profit_liabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import (

func (k Keeper) CalcMTPTakeProfitLiability(ctx sdk.Context, mtp *types.MTP, baseCurrency string) (sdk.Int, error) {
takeProfitLiabilities := sdk.ZeroInt()
if types.IsTakeProfitPriceInifite(mtp) {
return takeProfitLiabilities, nil
}
for _, takeProfitCustody := range mtp.TakeProfitCustodies {
takeProfitCustodyAsset := takeProfitCustody.Denom
// Retrieve AmmPool
Expand Down
67 changes: 22 additions & 45 deletions x/margin/keeper/force_close_long.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,36 @@ import (
)

func (k Keeper) ForceCloseLong(ctx sdk.Context, mtp *types.MTP, pool *types.Pool, takeFundPayment bool) (sdk.Int, error) {
repayAmount := sdk.ZeroInt()
for _, custody := range mtp.Custodies {
custodyAsset := custody.Denom
// Retrieve AmmPool
ammPool, err := k.GetAmmPool(ctx, mtp.AmmPoolId, custodyAsset)
if err != nil {
return math.ZeroInt(), err
}

// check MTP health against threshold
safetyFactor := k.GetSafetyFactor(ctx)

epochLength := k.GetEpochLength(ctx)
epochPosition := k.GetEpochPosition(ctx, epochLength)

if epochPosition > 0 {
repayAmount := sdk.ZeroInt()
for _, custody := range mtp.Custodies {
custodyAsset := custody.Denom
// Retrieve AmmPool
ammPool, err := k.GetAmmPool(ctx, mtp.AmmPoolId, custodyAsset)
if err != nil {
return math.ZeroInt(), err
}

for _, collateral := range mtp.Collaterals {
collateralAsset := collateral.Denom
// Handle Borrow Interest if within epoch position
if err := k.HandleBorrowInterest(ctx, mtp, pool, ammPool, collateralAsset, custodyAsset); err != nil {
return math.ZeroInt(), err
}
}

if mtp.MtpHealth.GT(safetyFactor) {
return math.ZeroInt(), types.ErrMTPHealthy
}
err = k.TakeOutCustody(ctx, *mtp, pool, custodyAsset)
if err != nil {
return math.ZeroInt(), err
}

err = k.TakeOutCustody(ctx, *mtp, pool, custodyAsset)
for _, collateral := range mtp.Collaterals {
collateralAsset := collateral.Denom
// Estimate swap and repay
repayAmt, err := k.EstimateAndRepay(ctx, *mtp, *pool, ammPool, collateralAsset, custodyAsset)
if err != nil {
return math.ZeroInt(), err
}

for _, collateral := range mtp.Collaterals {
collateralAsset := collateral.Denom
// Estimate swap and repay
repayAmt, err := k.EstimateAndRepay(ctx, *mtp, *pool, ammPool, collateralAsset, custodyAsset)
if err != nil {
return math.ZeroInt(), err
}

repayAmount = repayAmount.Add(repayAmt)
}

// Hooks after margin position closed
if k.hooks != nil {
k.hooks.AfterMarginPositionClosed(ctx, ammPool, *pool)
}
repayAmount = repayAmount.Add(repayAmt)
}

return repayAmount, nil
// Hooks after margin position closed
if k.hooks != nil {
k.hooks.AfterMarginPositionClosed(ctx, ammPool, *pool)
}
}

return math.ZeroInt(), nil
return repayAmount, nil
}
Loading

0 comments on commit e7b37c9

Please sign in to comment.