Skip to content

Commit

Permalink
fix: update open price in perpetual position (#388)
Browse files Browse the repository at this point in the history
* fix: update open price in perpetual position

* test: fix tests
  • Loading branch information
cosmic-vagabond authored Feb 27, 2024
1 parent 5597784 commit 226b894
Show file tree
Hide file tree
Showing 23 changed files with 216 additions and 82 deletions.
1 change: 0 additions & 1 deletion x/accountedpool/types/mocks/amm_keeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions x/accountedpool/types/mocks/perpetual_keeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion x/perpetual/keeper/begin_blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func (k Keeper) BeginBlocker(ctx sdk.Context) {
ctx.Logger().Error(errorsmod.Wrapf(assetprofiletypes.ErrAssetProfileNotFound, "asset %s not found", ptypes.BaseCurrency).Error())
}
baseCurrency := entry.Denom
baseCurrencyDecimal := entry.Decimals

currentHeight := ctx.BlockHeight()
pools := k.GetAllPools(ctx)
Expand Down Expand Up @@ -53,7 +54,7 @@ func (k Keeper) BeginBlocker(ctx sdk.Context) {

mtps, _, _ := k.GetMTPsForPool(ctx, pool.AmmPoolId, nil)
for _, mtp := range mtps {
err := BeginBlockerProcessMTP(ctx, k, mtp, pool, ammPool, baseCurrency)
err := BeginBlockerProcessMTP(ctx, k, mtp, pool, ammPool, baseCurrency, baseCurrencyDecimal)
if err != nil {
ctx.Logger().Error(err.Error())
continue
Expand Down
8 changes: 6 additions & 2 deletions x/perpetual/keeper/begin_blocker_process_mtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/elys-network/elys/x/perpetual/types"
)

func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool types.Pool, ammPool ammtypes.Pool, baseCurrency string) error {
func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool types.Pool, ammPool ammtypes.Pool, baseCurrency string, baseCurrencyDecimal uint64) error {
defer func() {
if r := recover(); r != nil {
if msg, ok := r.(string); ok {
Expand Down Expand Up @@ -76,7 +76,11 @@ func BeginBlockerProcessMTP(ctx sdk.Context, k Keeper, mtp *types.MTP, pool type
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error estimating swap: %s", mtp.CustodyAsset))
}
if types.ReachedTakeProfitPrice(mtp, assetPrice) {

// divide assetPrice by 10^baseCurrencyDecimal to get the actual price in decimal
assetPriceDec := math.LegacyNewDecFromBigInt(assetPrice.BigInt()).Quo(math.LegacyNewDec(10).Power(uint64(baseCurrencyDecimal)))

if types.ReachedTakeProfitPrice(mtp, assetPriceDec) {
// flag position as must force close
mustForceClose = true
} else {
Expand Down
3 changes: 3 additions & 0 deletions x/perpetual/keeper/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen) (*types.MsgOpenRespons
return k.OpenConsolidate(ctx, existingMtp, mtp, msg, baseCurrency)
}

// calc and update open price
k.OpenChecker.UpdateOpenPrice(ctx, mtp, ammPool, baseCurrency)

k.OpenChecker.EmitOpenEvent(ctx, mtp)

if k.hooks != nil {
Expand Down
3 changes: 3 additions & 0 deletions x/perpetual/keeper/open_consolidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (k Keeper) OpenConsolidate(ctx sdk.Context, existingMtp *types.MTP, newMtp
return nil, errorsmod.Wrap(types.ErrInvalidPosition, msg.Position.String())
}

// calc and update open price
k.UpdateOpenPrice(ctx, existingMtp, ammPool, baseCurrency)

ctx.EventManager().EmitEvent(types.GenerateOpenEvent(existingMtp))

if k.hooks != nil {
Expand Down
62 changes: 54 additions & 8 deletions x/perpetual/keeper/open_long_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
ammtypes "github.com/elys-network/elys/x/amm/types"
assetprofiletypes "github.com/elys-network/elys/x/assetprofile/types"
"github.com/elys-network/elys/x/perpetual/keeper"
"github.com/elys-network/elys/x/perpetual/types"
"github.com/elys-network/elys/x/perpetual/types/mocks"
Expand Down Expand Up @@ -408,14 +409,26 @@ func TestOpenLong_BaseCurrency_Collateral(t *testing.T) {
// Setup coin prices
SetupStableCoinPrices(ctx, oracle)

// Set asset profile
app.AssetprofileKeeper.SetEntry(ctx, assetprofiletypes.Entry{
BaseDenom: ptypes.BaseCurrency,
Denom: ptypes.BaseCurrency,
Decimals: 6,
})
app.AssetprofileKeeper.SetEntry(ctx, assetprofiletypes.Entry{
BaseDenom: ptypes.ATOM,
Denom: ptypes.ATOM,
Decimals: 6,
})

// Generate 1 random account with 1000stake balanced
addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000000))

// Create a pool
// Mint 100000USDC
usdcToken := []sdk.Coin{sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000000000))}
usdcToken := []sdk.Coin{sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(200000000000))}
// Mint 100000ATOM
atomToken := []sdk.Coin{sdk.NewCoin(ptypes.ATOM, sdk.NewInt(100000000000))}
atomToken := []sdk.Coin{sdk.NewCoin(ptypes.ATOM, sdk.NewInt(200000000000))}

err := app.BankKeeper.MintCoins(ctx, ammtypes.ModuleName, usdcToken)
require.NoError(t, err)
Expand All @@ -430,11 +443,11 @@ func TestOpenLong_BaseCurrency_Collateral(t *testing.T) {
poolAssets := []ammtypes.PoolAsset{
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.ATOM, sdk.NewInt(100000000000)),
Token: sdk.NewCoin(ptypes.ATOM, sdk.NewInt(10000000000)),
},
{
Weight: sdk.NewInt(50),
Token: sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(10000000000)),
Token: sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000000000)),
},
}

Expand Down Expand Up @@ -473,8 +486,8 @@ func TestOpenLong_BaseCurrency_Collateral(t *testing.T) {

// Balance check before create a perpetual position
balances := app.BankKeeper.GetAllBalances(ctx, poolAddress)
require.Equal(t, balances.AmountOf(ptypes.BaseCurrency), sdk.NewInt(10000000000))
require.Equal(t, balances.AmountOf(ptypes.ATOM), sdk.NewInt(100000000000))
require.Equal(t, balances.AmountOf(ptypes.BaseCurrency), sdk.NewInt(100000000000))
require.Equal(t, balances.AmountOf(ptypes.ATOM), sdk.NewInt(10000000000))

// Create a perpetual position open msg
msg2 := types.NewMsgOpen(
Expand All @@ -493,14 +506,47 @@ func TestOpenLong_BaseCurrency_Collateral(t *testing.T) {
require.Equal(t, len(mtps), 1)

balances = app.BankKeeper.GetAllBalances(ctx, poolAddress)
require.Equal(t, balances.AmountOf(ptypes.BaseCurrency), sdk.NewInt(10100000000))
require.Equal(t, balances.AmountOf(ptypes.ATOM), sdk.NewInt(100000000000))
require.Equal(t, balances.AmountOf(ptypes.BaseCurrency), sdk.NewInt(100100000000))
require.Equal(t, balances.AmountOf(ptypes.ATOM), sdk.NewInt(10000000000))

_, found = mk.OpenLongChecker.GetPool(ctx, pool.PoolId)
require.Equal(t, found, true)

err = mk.InvariantCheck(ctx)
require.Equal(t, err, nil)

mtp := mtps[0]

// Check MTP
require.Equal(t, types.MTP{
Address: addr[0].String(),
CollateralAsset: "uusdc",
TradingAsset: "uatom",
LiabilitiesAsset: "uusdc",
CustodyAsset: "uatom",
Collateral: sdk.NewInt(100000000),
Liabilities: sdk.NewInt(400000000),
BorrowInterestPaidCollateral: sdk.NewInt(0),
BorrowInterestPaidCustody: sdk.NewInt(0),
BorrowInterestUnpaidCollateral: sdk.NewInt(0),
Custody: sdk.NewInt(49751243),
TakeProfitLiabilities: sdk.NewInt(495049497),
TakeProfitCustody: sdk.NewInt(49751243),
Leverage: sdk.NewDec(5),
MtpHealth: sdk.MustNewDecFromStr("1.249999982500000000"),
Position: types.Position_LONG,
Id: uint64(1),
AmmPoolId: uint64(1),
ConsolidateLeverage: sdk.NewDec(4),
SumCollateral: sdk.NewInt(100000000),
TakeProfitPrice: sdk.MustNewDecFromStr(types.TakeProfitPriceDefault),
TakeProfitBorrowRate: sdk.MustNewDecFromStr("1.0"),
FundingFeePaidCollateral: sdk.NewInt(0),
FundingFeePaidCustody: sdk.NewInt(0),
FundingFeeReceivedCollateral: sdk.NewInt(0),
FundingFeeReceivedCustody: sdk.NewInt(0),
OpenPrice: sdk.MustNewDecFromStr("10.00000000000000000"),
}, mtp)
}

func TestOpenLong_ATOM_Collateral(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions x/perpetual/keeper/open_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ func TestOpen_Successful(t *testing.T) {
mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{}, types.Pool{}, nil)
mockChecker.On("CheckPoolHealth", ctx, poolId).Return(nil)
mockChecker.On("OpenShort", ctx, poolId, msg, ptypes.BaseCurrency).Return(mtp, nil)
mockChecker.On("UpdateOpenPrice", ctx, mtp, ammtypes.Pool{}, ptypes.BaseCurrency).Return(nil)
mockChecker.On("EmitOpenEvent", ctx, mtp).Return()

_, err := k.Open(ctx, msg)
Expand Down
34 changes: 34 additions & 0 deletions x/perpetual/keeper/update_open_price.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package keeper

import (
"fmt"

"cosmossdk.io/errors"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
ammtypes "github.com/elys-network/elys/x/amm/types"
"github.com/elys-network/elys/x/perpetual/types"
)

func (k Keeper) UpdateOpenPrice(ctx sdk.Context, mtp *types.MTP, ammPool ammtypes.Pool, baseCurrency string) error {
collateralAmountInBaseCurrency := mtp.Collateral
if mtp.CollateralAsset != baseCurrency {
C, err := k.EstimateSwap(ctx, sdk.NewCoin(mtp.CollateralAsset, mtp.Collateral), baseCurrency, ammPool)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error estimating swap: %s", mtp.CustodyAsset))
}
collateralAmountInBaseCurrency = C
}

// open price = (collateral + liabilities) / custody
mtp.OpenPrice = math.LegacyNewDecFromBigInt(
collateralAmountInBaseCurrency.Add(mtp.Liabilities).Quo(mtp.Custody).BigInt(),
)

err := k.SetMTP(ctx, mtp)
if err != nil {
return err
}

return nil
}
1 change: 1 addition & 0 deletions x/perpetual/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type OpenChecker interface {
CheckPoolHealth(ctx sdk.Context, poolId uint64) error
OpenLong(ctx sdk.Context, poolId uint64, msg *MsgOpen, baseCurrency string) (*MTP, error)
OpenShort(ctx sdk.Context, poolId uint64, msg *MsgOpen, baseCurrency string) (*MTP, error)
UpdateOpenPrice(ctx sdk.Context, mtp *MTP, ammPool ammtypes.Pool, baseCurrency string) error
EmitOpenEvent(ctx sdk.Context, mtp *MTP)
SetMTP(ctx sdk.Context, mtp *MTP) error
CheckSameAssetPosition(ctx sdk.Context, msg *MsgOpen) *MTP
Expand Down
1 change: 0 additions & 1 deletion x/perpetual/types/mocks/account_keeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 226b894

Please sign in to comment.