Skip to content

Commit

Permalink
[chore] Move perpetuals/keeper helper functions to perpetuals/lib (
Browse files Browse the repository at this point in the history
  • Loading branch information
BrendanChou authored Jun 13, 2024
1 parent 35b2c9f commit 87a919e
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 124 deletions.
6 changes: 3 additions & 3 deletions protocol/daemons/liquidation/client/sub_task_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
assetstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types"
clobkeeper "github.com/dydxprotocol/v4-chain/protocol/x/clob/keeper"
clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"
perpkeeper "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/keeper"
perplib "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/lib"
perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
sakeeper "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/keeper"
Expand Down Expand Up @@ -344,7 +344,7 @@ func (c *Client) CheckSubaccountCollateralization(
bigQuantums := perpetualPosition.GetBigQuantums()

// Get the net collateral for the position.
bigNetCollateralQuoteQuantums := perpkeeper.GetNetNotionalInQuoteQuantums(perpetual, marketPrice, bigQuantums)
bigNetCollateralQuoteQuantums := perplib.GetNetNotionalInQuoteQuantums(perpetual, marketPrice, bigQuantums)
bigTotalNetCollateral.Add(bigTotalNetCollateral, bigNetCollateralQuoteQuantums)

liquidityTier, ok := liquidityTiers[perpetual.Params.LiquidityTier]
Expand All @@ -357,7 +357,7 @@ func (c *Client) CheckSubaccountCollateralization(
}

// Get the maintenance margin requirement for the position.
_, bigMaintenanceMarginQuoteQuantums := perpkeeper.GetMarginRequirementsInQuoteQuantums(
_, bigMaintenanceMarginQuoteQuantums := perplib.GetMarginRequirementsInQuoteQuantums(
perpetual,
marketPrice,
liquidityTier,
Expand Down
110 changes: 4 additions & 106 deletions protocol/x/perpetuals/keeper/perpetual.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/lib/metrics"
epochstypes "github.com/dydxprotocol/v4-chain/protocol/x/epochs/types"
"github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/funding"
perplib "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/lib"
"github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
gometrics "github.com/hashicorp/go-metrics"
Expand Down Expand Up @@ -817,31 +818,7 @@ func (k Keeper) GetNetNotional(
return new(big.Int), err
}

return GetNetNotionalInQuoteQuantums(perpetual, marketPrice, bigQuantums), nil
}

// GetNetNotionalInQuoteQuantums returns the net notional in quote quantums, which can be
// represented by the following equation:
//
// `quantums / 10^baseAtomicResolution * marketPrice * 10^marketExponent * 10^quoteAtomicResolution`.
// Note that longs are positive, and shorts are negative.
//
// Also note that this is a stateless function.
func GetNetNotionalInQuoteQuantums(
perpetual types.Perpetual,
marketPrice pricestypes.MarketPrice,
bigQuantums *big.Int,
) (
bigNetNotionalQuoteQuantums *big.Int,
) {
bigQuoteQuantums := lib.BaseToQuoteQuantums(
bigQuantums,
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)

return bigQuoteQuantums
return perplib.GetNetNotionalInQuoteQuantums(perpetual, marketPrice, bigQuantums), nil
}

// GetNotionalInBaseQuantums returns the net notional in base quantums, which can be represented
Expand Down Expand Up @@ -946,7 +923,7 @@ func (k Keeper) GetMarginRequirements(
}

bigInitialMarginQuoteQuantums,
bigMaintenanceMarginQuoteQuantums = GetMarginRequirementsInQuoteQuantums(
bigMaintenanceMarginQuoteQuantums = perplib.GetMarginRequirementsInQuoteQuantums(
perpetual,
marketPrice,
liquidityTier,
Expand All @@ -955,56 +932,6 @@ func (k Keeper) GetMarginRequirements(
return bigInitialMarginQuoteQuantums, bigMaintenanceMarginQuoteQuantums, nil
}

// GetMarginRequirementsInQuoteQuantums returns initial and maintenance margin requirements
// in quote quantums, given the position size in base quantums.
//
// Note that this is a stateless function.
func GetMarginRequirementsInQuoteQuantums(
perpetual types.Perpetual,
marketPrice pricestypes.MarketPrice,
liquidityTier types.LiquidityTier,
bigQuantums *big.Int,
) (
bigInitialMarginQuoteQuantums *big.Int,
bigMaintenanceMarginQuoteQuantums *big.Int,
) {
// Always consider the magnitude of the position regardless of whether it is long/short.
bigAbsQuantums := new(big.Int).Set(bigQuantums).Abs(bigQuantums)

// Calculate the notional value of the position in quote quantums.
bigQuoteQuantums := lib.BaseToQuoteQuantums(
bigAbsQuantums,
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)
// Calculate the perpetual's open interest in quote quantums.
openInterestQuoteQuantums := lib.BaseToQuoteQuantums(
perpetual.OpenInterest.BigInt(), // OpenInterest is represented as base quantums.
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)

// Initial margin requirement quote quantums = size in quote quantums * initial margin PPM.
bigBaseInitialMarginQuoteQuantums := liquidityTier.GetInitialMarginQuoteQuantums(
bigQuoteQuantums,
big.NewInt(0), // pass in 0 as open interest to get base IMR.
)
// Maintenance margin requirement quote quantums = IM in quote quantums * maintenance fraction PPM.
bigMaintenanceMarginQuoteQuantums = lib.BigMulPpm(
bigBaseInitialMarginQuoteQuantums,
lib.BigU(liquidityTier.MaintenanceFractionPpm),
true,
)

bigInitialMarginQuoteQuantums = liquidityTier.GetInitialMarginQuoteQuantums(
bigQuoteQuantums,
openInterestQuoteQuantums, // pass in current OI to get scaled IMR.
)
return bigInitialMarginQuoteQuantums, bigMaintenanceMarginQuoteQuantums
}

// GetSettlementPpm returns the net settlement amount ppm (in quote quantums) given
// the perpetual Id and position size (in base quantums).
// When handling rounding, always round positive settlement amount to zero, and
Expand All @@ -1031,43 +958,14 @@ func (k Keeper) GetSettlementPpm(
return big.NewInt(0), big.NewInt(0), err
}

bigNetSettlementPpm, newFundingIndex = GetSettlementPpmWithPerpetual(
bigNetSettlementPpm, newFundingIndex = perplib.GetSettlementPpmWithPerpetual(
perpetual,
quantums,
index,
)
return bigNetSettlementPpm, newFundingIndex, nil
}

// GetSettlementPpm returns the net settlement amount ppm (in quote quantums) given
// the perpetual and position size (in base quantums).
//
// Note that this function is a stateless utility function.
func GetSettlementPpmWithPerpetual(
perpetual types.Perpetual,
quantums *big.Int,
index *big.Int,
) (
bigNetSettlementPpm *big.Int,
newFundingIndex *big.Int,
) {
indexDelta := new(big.Int).Sub(perpetual.FundingIndex.BigInt(), index)

// if indexDelta is zero, then net settlement is zero.
if indexDelta.Sign() == 0 {
return big.NewInt(0), perpetual.FundingIndex.BigInt()
}

bigNetSettlementPpm = new(big.Int).Mul(indexDelta, quantums)

// `bigNetSettlementPpm` carries sign. `indexDelta` is the increase in `fundingIndex`, so if
// the position is long (positive), the net settlement should be short (negative), and vice versa.
// Thus, always negate `bigNetSettlementPpm` here.
bigNetSettlementPpm = bigNetSettlementPpm.Neg(bigNetSettlementPpm)

return bigNetSettlementPpm, perpetual.FundingIndex.BigInt()
}

// GetPremiumSamples reads premium samples from the current `funding-tick` epoch,
// stored in a `PremiumStore` struct.
func (k Keeper) GetPremiumSamples(ctx sdk.Context) (
Expand Down
22 changes: 9 additions & 13 deletions protocol/x/perpetuals/keeper/perpetual_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@ import (
"sort"
"testing"

"github.com/cosmos/gogoproto/proto"
"github.com/dydxprotocol/v4-chain/protocol/app/module"

errorsmod "cosmossdk.io/errors"

"github.com/dydxprotocol/v4-chain/protocol/dtypes"
"github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager"
"github.com/dydxprotocol/v4-chain/protocol/mocks"
"cosmossdk.io/store/prefix"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dydxprotocol/v4-chain/protocol/lib"
"github.com/stretchr/testify/mock"

"github.com/stretchr/testify/require"

"cosmossdk.io/store/prefix"
"github.com/cosmos/gogoproto/proto"
"github.com/dydxprotocol/v4-chain/protocol/app/module"
"github.com/dydxprotocol/v4-chain/protocol/dtypes"
indexerevents "github.com/dydxprotocol/v4-chain/protocol/indexer/events"
"github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager"
"github.com/dydxprotocol/v4-chain/protocol/lib"
"github.com/dydxprotocol/v4-chain/protocol/mocks"
big_testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/big"
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants"
keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper"
Expand All @@ -37,6 +31,8 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/keeper"
"github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func TestModifyPerpetual_Success(t *testing.T) {
Expand Down
106 changes: 106 additions & 0 deletions protocol/x/perpetuals/lib/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package lib

import (
"math/big"

"github.com/dydxprotocol/v4-chain/protocol/lib"
"github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
)

// GetSettlementPpm returns the net settlement amount ppm (in quote quantums) given
// the perpetual and position size (in base quantums).
func GetSettlementPpmWithPerpetual(
perpetual types.Perpetual,
quantums *big.Int,
index *big.Int,
) (
bigNetSettlementPpm *big.Int,
newFundingIndex *big.Int,
) {
indexDelta := new(big.Int).Sub(perpetual.FundingIndex.BigInt(), index)

// if indexDelta is zero, then net settlement is zero.
if indexDelta.Sign() == 0 {
return big.NewInt(0), perpetual.FundingIndex.BigInt()
}

bigNetSettlementPpm = new(big.Int).Mul(indexDelta, quantums)

// `bigNetSettlementPpm` carries sign. `indexDelta` is the increase in `fundingIndex`, so if
// the position is long (positive), the net settlement should be short (negative), and vice versa.
// Thus, always negate `bigNetSettlementPpm` here.
bigNetSettlementPpm = bigNetSettlementPpm.Neg(bigNetSettlementPpm)

return bigNetSettlementPpm, perpetual.FundingIndex.BigInt()
}

// GetNetNotionalInQuoteQuantums returns the net notional in quote quantums, which can be
// represented by the following equation:
//
// `quantums / 10^baseAtomicResolution * marketPrice * 10^marketExponent * 10^quoteAtomicResolution`.
// Note that longs are positive, and shorts are negative.
func GetNetNotionalInQuoteQuantums(
perpetual types.Perpetual,
marketPrice pricestypes.MarketPrice,
bigQuantums *big.Int,
) (
bigNetNotionalQuoteQuantums *big.Int,
) {
bigQuoteQuantums := lib.BaseToQuoteQuantums(
bigQuantums,
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)

return bigQuoteQuantums
}

// GetMarginRequirementsInQuoteQuantums returns initial and maintenance margin requirements
// in quote quantums, given the position size in base quantums.
func GetMarginRequirementsInQuoteQuantums(
perpetual types.Perpetual,
marketPrice pricestypes.MarketPrice,
liquidityTier types.LiquidityTier,
bigQuantums *big.Int,
) (
bigInitialMarginQuoteQuantums *big.Int,
bigMaintenanceMarginQuoteQuantums *big.Int,
) {
// Always consider the magnitude of the position regardless of whether it is long/short.
bigAbsQuantums := new(big.Int).Abs(bigQuantums)

// Calculate the notional value of the position in quote quantums.
bigQuoteQuantums := lib.BaseToQuoteQuantums(
bigAbsQuantums,
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)
// Calculate the perpetual's open interest in quote quantums.
openInterestQuoteQuantums := lib.BaseToQuoteQuantums(
perpetual.OpenInterest.BigInt(), // OpenInterest is represented as base quantums.
perpetual.Params.AtomicResolution,
marketPrice.Price,
marketPrice.Exponent,
)

// Initial margin requirement quote quantums = size in quote quantums * initial margin PPM.
bigBaseInitialMarginQuoteQuantums := liquidityTier.GetInitialMarginQuoteQuantums(
bigQuoteQuantums,
big.NewInt(0), // pass in 0 as open interest to get base IMR.
)
// Maintenance margin requirement quote quantums = IM in quote quantums * maintenance fraction PPM.
bigMaintenanceMarginQuoteQuantums = lib.BigMulPpm(
bigBaseInitialMarginQuoteQuantums,
lib.BigU(liquidityTier.MaintenanceFractionPpm),
true,
)

bigInitialMarginQuoteQuantums = liquidityTier.GetInitialMarginQuoteQuantums(
bigQuoteQuantums,
openInterestQuoteQuantums, // pass in current OI to get scaled IMR.
)
return bigInitialMarginQuoteQuantums, bigMaintenanceMarginQuoteQuantums
}
Loading

0 comments on commit 87a919e

Please sign in to comment.