Skip to content

Commit

Permalink
refactor: tp calc and update (#257)
Browse files Browse the repository at this point in the history
* refactor: tp calc and update

* fix: types

* test: fix

* test: fix

* test: fix
  • Loading branch information
cosmic-vagabond authored Nov 20, 2023
1 parent 547de88 commit b63ab1f
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 15 deletions.
16 changes: 16 additions & 0 deletions x/amm/types/calc_in_amt_given_out.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package types

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
Expand All @@ -19,6 +21,15 @@ 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 @@ -55,6 +66,8 @@ 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 @@ -65,6 +78,9 @@ 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
8 changes: 8 additions & 0 deletions x/margin/keeper/begin_blocker_process_mtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool type
}
}
}()
var err error
// update mtp take profit liabilities
// calculate mtp take profit liablities, delta x_tp_l = delta y_tp_c * current price (take profit liabilities = take profit custody * current price)
mtp.TakeProfitLiabilities, err = k.CalcMTPTakeProfitLiability(ctx, mtp, baseCurrency)
if err != nil {
ctx.Logger().Error(errors.Wrap(err, fmt.Sprintf("error calculating mtp take profit liabilities: %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
30 changes: 30 additions & 0 deletions x/margin/keeper/calc_mtp_take_profit_liabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package keeper

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

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
ammPool, err := k.GetAmmPool(ctx, mtp.AmmPoolId, takeProfitCustodyAsset)
if err != nil {
return sdk.ZeroInt(), err
}

// convert custody amount to base currency
C, err := k.EstimateSwapGivenOut(ctx, takeProfitCustody, baseCurrency, ammPool)
if err != nil {
return sdk.ZeroInt(), err
}
takeProfitLiabilities = takeProfitLiabilities.Add(C)
}

return takeProfitLiabilities, nil
}
32 changes: 24 additions & 8 deletions x/margin/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,16 @@ func (k Keeper) Borrow(ctx sdk.Context, collateralAsset string, custodyAsset str

mtp.Collaterals[collateralIndex].Amount = mtp.Collaterals[collateralIndex].Amount.Add(collateralAmount)
mtp.Liabilities = mtp.Liabilities.Add(sdk.NewIntFromBigInt(liabilitiesDec.TruncateInt().BigInt()))

// we divide liabilities by take profit price to get take profit liabilities in base currency
mtp.TakeProfitLiabilities = mtp.Liabilities.Quo(sdk.NewIntFromBigInt(mtp.TakeProfitPrice.TruncateInt().BigInt()))

mtp.Custodies[custodyIndex].Amount = mtp.Custodies[custodyIndex].Amount.Add(custodyAmount)

// we divide custody amount by take profit price to get take profit custody amount in base currency
mtp.TakeProfitCustodies[custodyIndex].Amount = mtp.Custodies[custodyIndex].Amount.Quo(sdk.NewIntFromBigInt(mtp.TakeProfitPrice.TruncateInt().BigInt()))
// calculate mtp take profit custody, delta y_tp_c = delta x_l / take profit price (take profit custody = liabilities / take profit price)
mtp.TakeProfitCustodies = types.CalcMTPTakeProfitCustodies(mtp)

// calculate mtp take profit liablities, delta x_tp_l = delta y_tp_c * current price (take profit liabilities = take profit custody * current price)
mtp.TakeProfitLiabilities, err = k.CalcMTPTakeProfitLiability(ctx, mtp, baseCurrency)
if err != nil {
return err
}

mtp.Leverages = append(mtp.Leverages, eta.Add(sdk.OneDec()))

Expand Down Expand Up @@ -216,6 +218,18 @@ func (k Keeper) Borrow(ctx sdk.Context, collateralAsset string, custodyAsset str
return err
}

// All take profit liability has to be in base currency
err = pool.UpdateTakeProfitLiabilities(ctx, baseCurrency, mtp.TakeProfitLiabilities, true, mtp.Position)
if err != nil {
return err
}

// All take profit custody has to be in base currency
err = pool.UpdateTakeProfitCustody(ctx, baseCurrency, mtp.TakeProfitCustodies[custodyIndex].Amount, true, mtp.Position)
if err != nil {
return err
}

k.SetPool(ctx, *pool)

return k.SetMTP(ctx, mtp)
Expand All @@ -238,7 +252,9 @@ func (k Keeper) CalculatePoolHealthByPosition(ctx sdk.Context, pool *types.Pool,
}

balance := sdk.NewDecFromInt(asset.AssetBalance.Add(ammBalance))
liabilities := sdk.NewDecFromInt(asset.Liabilities)

// X_L = X_P_L - X_TP_L (pool liabilities = pool synthetic liabilities - pool take profit liabilities)
liabilities := sdk.NewDecFromInt(asset.Liabilities.Sub(asset.TakeProfitLiabilities))

if balance.Add(liabilities).IsZero() {
return sdk.ZeroDec()
Expand Down Expand Up @@ -311,7 +327,7 @@ func (k Keeper) IncrementalBorrowInterestPayment(ctx sdk.Context, collateralAsse
return sdk.ZeroInt(), err
}

// If collateralAset is not in base currency, convert it to original asset format
// If collateralAsset is not in base currency, convert it to original asset format
if collateralAsset != baseCurrency {
// swap custody amount to collateral for updating borrow interest unpaid
amtTokenIn := sdk.NewCoin(baseCurrency, borrowInterestPayment)
Expand Down
4 changes: 2 additions & 2 deletions x/margin/keeper/open_long_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func (k Keeper) ProcessOpenLong(ctx sdk.Context, mtp *types.MTP, leverage sdk.De
// Update consolidated collateral amount
k.OpenLongChecker.CalcMTPConsolidateCollateral(ctx, mtp, baseCurrency)

// Calculate consolidate liabiltiy
types.CalcMTPConsolidateLiability(mtp)
// Calculate consolidate liabiltiy and update consolidate leverage
mtp.ConsolidateLeverage = types.CalcMTPConsolidateLiability(mtp)

// Set MTP
k.OpenLongChecker.SetMTP(ctx, mtp)
Expand Down
4 changes: 2 additions & 2 deletions x/margin/keeper/open_short_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ func (k Keeper) ProcessOpenShort(ctx sdk.Context, mtp *types.MTP, leverage sdk.D
// Update consolidated collateral amount
k.OpenShortChecker.CalcMTPConsolidateCollateral(ctx, mtp, baseCurrency)

// Calculate consolidate liabiltiy
types.CalcMTPConsolidateLiability(mtp)
// Calculate consolidate liabiltiy and update consolidate leverage
mtp.ConsolidateLeverage = types.CalcMTPConsolidateLiability(mtp)

// Set MTP
k.OpenShortChecker.SetMTP(ctx, mtp)
Expand Down
10 changes: 10 additions & 0 deletions x/margin/keeper/repay.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ func (k Keeper) Repay(ctx sdk.Context, mtp *types.MTP, pool *types.Pool, ammPool
return err
}

err = pool.UpdateTakeProfitLiabilities(ctx, baseCurrency, mtp.TakeProfitLiabilities, false, mtp.Position)
if err != nil {
return err
}

err = pool.UpdateTakeProfitCustody(ctx, baseCurrency, mtp.TakeProfitCustodies[collateralIndex].Amount, false, mtp.Position)
if err != nil {
return err
}

err = k.DestroyMTP(ctx, mtp.Address, mtp.Id)
if err != nil {
return err
Expand Down
6 changes: 3 additions & 3 deletions x/margin/types/calc_mtp_consolidate_leverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func CalcMTPConsolidateLiability(mtp *MTP) {
func CalcMTPConsolidateLiability(mtp *MTP) sdk.Dec {
if mtp.SumCollateral.IsZero() {
return
return mtp.ConsolidateLeverage
}

leverage := mtp.Liabilities.Quo(mtp.SumCollateral)
mtp.ConsolidateLeverage = sdk.NewDecFromInt(leverage)
return sdk.NewDecFromInt(leverage)
}
16 changes: 16 additions & 0 deletions x/margin/types/calc_mtp_take_profit_custodies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func CalcMTPTakeProfitCustodies(mtp *MTP) sdk.Coins {
takeProfitCustodies := mtp.TakeProfitCustodies
if IsTakeProfitPriceInifite(mtp) {
return takeProfitCustodies
}
for custodyIndex := range mtp.Custodies {
takeProfitCustodies[custodyIndex].Amount = sdk.NewDecFromInt(mtp.Liabilities).Quo(mtp.TakeProfitPrice).TruncateInt()
}
return takeProfitCustodies
}
5 changes: 5 additions & 0 deletions x/margin/types/is_take_profit_price_inifite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package types

func IsTakeProfitPriceInifite(mtp *MTP) bool {
return mtp.TakeProfitPrice.TruncateInt().String() == TakeProfitPriceDefault
}
36 changes: 36 additions & 0 deletions x/margin/types/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,42 @@ func (p *Pool) UpdateLiabilities(ctx sdk.Context, assetDenom string, amount sdk.
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "invalid asset denom")
}

// Update the asset take profit liabilities
func (p *Pool) UpdateTakeProfitLiabilities(ctx sdk.Context, assetDenom string, amount sdk.Int, isIncrease bool, position Position) error {
poolAssets := p.GetPoolAssets(position)
for i, asset := range *poolAssets {
if asset.AssetDenom == assetDenom {
if isIncrease {
(*poolAssets)[i].TakeProfitLiabilities = asset.TakeProfitLiabilities.Add(amount)
} else {
(*poolAssets)[i].TakeProfitLiabilities = asset.TakeProfitLiabilities.Sub(amount)
}

return nil
}
}

return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "invalid asset denom")
}

// Update the asset take profit custody
func (p *Pool) UpdateTakeProfitCustody(ctx sdk.Context, assetDenom string, amount sdk.Int, isIncrease bool, position Position) error {
poolAssets := p.GetPoolAssets(position)
for i, asset := range *poolAssets {
if asset.AssetDenom == assetDenom {
if isIncrease {
(*poolAssets)[i].TakeProfitCustody = asset.TakeProfitCustody.Add(amount)
} else {
(*poolAssets)[i].TakeProfitCustody = asset.TakeProfitCustody.Sub(amount)
}

return nil
}
}

return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "invalid asset denom")
}

// Update the asset custody
func (p *Pool) UpdateCustody(ctx sdk.Context, assetDenom string, amount sdk.Int, isIncrease bool, position Position) error {
poolAssets := p.GetPoolAssets(position)
Expand Down
110 changes: 110 additions & 0 deletions x/margin/types/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,116 @@ func TestPool_UpdateLiabilitiesInvalid(t *testing.T) {
assert.Equal(t, pool.PoolAssetsLong[0].Liabilities, sdk.NewInt(0))
}

func TestPool_UpdateTakeProfitLiabilitiesValid(t *testing.T) {
ctx := sdk.Context{} // mock or setup a context

// Define the margin pool with assets
pool := types.NewPool(1)
pool.PoolAssetsLong = []types.PoolAsset{
{
Liabilities: sdk.NewInt(0),
TakeProfitLiabilities: sdk.NewInt(0),
Custody: sdk.NewInt(0),
AssetBalance: sdk.NewInt(0),
BlockBorrowInterest: sdk.NewInt(0),
AssetDenom: "testAsset",
},
}

// Test scenario, increase 100 and decrease 150.
denom := "testAsset"
err := pool.UpdateTakeProfitLiabilities(ctx, denom, sdk.NewInt(100), true, types.Position_LONG)
// Expect that there is no error
assert.Nil(t, err)
// Expect that there is 100 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitLiabilities, sdk.NewInt(100))
err = pool.UpdateTakeProfitLiabilities(ctx, denom, sdk.NewInt(150), false, types.Position_LONG)
// Expect that there is no error
assert.Nil(t, err)
// Expect that there is -50 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitLiabilities, sdk.NewInt(-50))
}

func TestPool_UpdateTakeProfitLiabilitiesInvalid(t *testing.T) {
ctx := sdk.Context{} // mock or setup a context

// Define the margin pool with assets
pool := types.NewPool(1)
pool.PoolAssetsLong = []types.PoolAsset{
{
Liabilities: sdk.NewInt(0),
TakeProfitLiabilities: sdk.NewInt(0),
Custody: sdk.NewInt(0),
AssetBalance: sdk.NewInt(0),
BlockBorrowInterest: sdk.NewInt(0),
AssetDenom: "testAsset",
},
}

// Test scenario, increase 100 and decrease 50.
denom := "testAsset2"
err := pool.UpdateTakeProfitLiabilities(ctx, denom, sdk.NewInt(100), true, types.Position_LONG)
// Expect that there is invalid asset denom error.
assert.True(t, errors.Is(err, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "invalid asset denom")))

// Expect that there is still 0 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitLiabilities, sdk.NewInt(0))
}

func TestPool_UpdateTakeProfitCustodyValid(t *testing.T) {
ctx := sdk.Context{} // mock or setup a context

// Define the margin pool with assets
pool := types.NewPool(1)
pool.PoolAssetsLong = []types.PoolAsset{
{
TakeProfitCustody: sdk.NewInt(0),
Custody: sdk.NewInt(0),
AssetBalance: sdk.NewInt(0),
BlockBorrowInterest: sdk.NewInt(0),
AssetDenom: "testAsset",
},
}

// Test scenario, increase 100 and decrease 150.
denom := "testAsset"
err := pool.UpdateTakeProfitCustody(ctx, denom, sdk.NewInt(100), true, types.Position_LONG)
// Expect that there is no error
assert.Nil(t, err)
// Expect that there is 100 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitCustody, sdk.NewInt(100))
err = pool.UpdateTakeProfitCustody(ctx, denom, sdk.NewInt(150), false, types.Position_LONG)
// Expect that there is no error
assert.Nil(t, err)
// Expect that there is -50 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitCustody, sdk.NewInt(-50))
}

func TestPool_UpdateTakeProfitCustodyInvalid(t *testing.T) {
ctx := sdk.Context{} // mock or setup a context

// Define the margin pool with assets
pool := types.NewPool(1)
pool.PoolAssetsLong = []types.PoolAsset{
{
TakeProfitCustody: sdk.NewInt(0),
Custody: sdk.NewInt(0),
AssetBalance: sdk.NewInt(0),
BlockBorrowInterest: sdk.NewInt(0),
AssetDenom: "testAsset",
},
}

// Test scenario, increase 100 and decrease 50.
denom := "testAsset2"
err := pool.UpdateTakeProfitCustody(ctx, denom, sdk.NewInt(100), true, types.Position_LONG)
// Expect that there is invalid asset denom error.
assert.True(t, errors.Is(err, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "invalid asset denom")))

// Expect that there is still 0 liabilities
assert.Equal(t, pool.PoolAssetsLong[0].TakeProfitCustody, sdk.NewInt(0))
}

func TestPool_UpdateCustodyValid(t *testing.T) {
ctx := sdk.Context{} // mock or setup a context

Expand Down

0 comments on commit b63ab1f

Please sign in to comment.