Skip to content

Commit

Permalink
[Performance] Remove the need to get each perpetual and price twice w…
Browse files Browse the repository at this point in the history
…hen checking collateralization (#1681)
  • Loading branch information
BrendanChou authored Jun 13, 2024
1 parent 87a919e commit edcc82b
Show file tree
Hide file tree
Showing 11 changed files with 525 additions and 520 deletions.
39 changes: 0 additions & 39 deletions protocol/mocks/PerpetualsKeeper.go

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

15 changes: 8 additions & 7 deletions protocol/x/clob/keeper/deleveraging.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"math/big"
"time"

perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"

errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/telemetry"

Expand All @@ -19,6 +17,8 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/lib/metrics"
assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types"
"github.com/dydxprotocol/v4-chain/protocol/x/clob/types"
perplib "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/lib"
perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
)

Expand Down Expand Up @@ -592,11 +592,12 @@ func (k Keeper) ProcessDeleveraging(
}

// Stat quantums deleveraged in quote quantums.
if deleveragedQuoteQuantums, err := k.perpetualsKeeper.GetNetCollateral(
ctx,
perpetualId,
new(big.Int).Abs(deltaBaseQuantums),
); err == nil {
if perpetual, marketPrice, err := k.perpetualsKeeper.GetPerpetualAndMarketPrice(ctx, perpetualId); err == nil {
deleveragedQuoteQuantums := perplib.GetNetNotionalInQuoteQuantums(
perpetual,
marketPrice,
new(big.Int).Abs(deltaBaseQuantums),
)
labels := []metrics.Label{
metrics.GetLabelForIntValue(metrics.PerpetualId, int(perpetualId)),
metrics.GetLabelForBoolValue(metrics.CheckTx, ctx.IsCheckTx()),
Expand Down
67 changes: 29 additions & 38 deletions protocol/x/clob/keeper/liquidations.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/lib/log"
"github.com/dydxprotocol/v4-chain/protocol/lib/metrics"
"github.com/dydxprotocol/v4-chain/protocol/x/clob/types"
perplib "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/lib"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
)

Expand Down Expand Up @@ -455,51 +456,36 @@ func (k Keeper) GetBankruptcyPriceInQuoteQuantums(
)
}

perpetual,
marketPrice,
liquidityTier,
err := k.perpetualsKeeper.
GetPerpetualAndMarketPriceAndLiquidityTier(ctx, perpetualId)
if err != nil {
return nil, err
}

// `DNNV = PNNVAD - PNNV`, where `PNNVAD` is the perpetual's net notional
// with a position size of `PS + deltaQuantums`.
// Note that we are intentionally not calculating `DNNV` from `deltaQuantums`
// directly to avoid rounding errors.
pnnvBig, err := k.perpetualsKeeper.GetNetNotional(
ctx,
perpetualId,
pnnvBig, _, pmmrBig := perplib.GetNetCollateralAndMarginRequirements(
perpetual,
marketPrice,
liquidityTier,
psBig,
)
if err != nil {
return nil, err
}

pnnvadBig, err := k.perpetualsKeeper.GetNetNotional(
ctx,
perpetualId,
pnnvadBig, _, pmmradBig := perplib.GetNetCollateralAndMarginRequirements(
perpetual,
marketPrice,
liquidityTier,
new(big.Int).Add(psBig, deltaQuantums),
)
if err != nil {
return nil, err
}

dnnvBig := new(big.Int).Sub(pnnvadBig, pnnvBig)

// `DMMR = PMMRAD - PMMR`, where `PMMRAD` is the perpetual's maintenance margin requirement
// with a position size of `PS + deltaQuantums`.
// Note that we cannot directly calculate `DMMR` from `deltaQuantums` because the maintenance
// margin requirement function could be non-linear.
_, pmmrBig, err := k.perpetualsKeeper.GetMarginRequirements(ctx, perpetualId, psBig)
if err != nil {
return nil, err
}

_, pmmradBig, err := k.perpetualsKeeper.GetMarginRequirements(
ctx,
perpetualId,
new(big.Int).Add(
psBig,
deltaQuantums,
),
)
if err != nil {
return nil, err
}

dnnvBig := new(big.Int).Sub(pnnvadBig, pnnvBig)
dmmrBig := new(big.Int).Sub(pmmradBig, pmmrBig)
// `dmmrBig` should never be positive if `| PS | >= | PS + deltaQuantums |`. If it is, panic.
if dmmrBig.Sign() == 1 {
Expand Down Expand Up @@ -565,15 +551,20 @@ func (k Keeper) GetFillablePrice(
)
}

pnnvBig, err := k.perpetualsKeeper.GetNetCollateral(ctx, perpetualId, psBig)
perpetual,
marketPrice,
liquidityTier,
err := k.perpetualsKeeper.GetPerpetualAndMarketPriceAndLiquidityTier(ctx, perpetualId)
if err != nil {
return nil, err
}

_, pmmrBig, err := k.perpetualsKeeper.GetMarginRequirements(ctx, perpetualId, psBig)
if err != nil {
return nil, err
}
pnnvBig, _, pmmrBig := perplib.GetNetCollateralAndMarginRequirements(
perpetual,
marketPrice,
liquidityTier,
psBig,
)

tncBig,
_,
Expand Down
18 changes: 5 additions & 13 deletions protocol/x/clob/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,13 @@ type PerpetualsKeeper interface {
bigBaseQuantums *big.Int,
err error,
)
GetNetCollateral(
GetPerpetualAndMarketPriceAndLiquidityTier(
ctx sdk.Context,
id uint32,
bigQuantums *big.Int,
) (
bigNetCollateralQuoteQuantums *big.Int,
err error,
)
GetMarginRequirements(
ctx sdk.Context,
id uint32,
bigQuantums *big.Int,
perpetualId uint32,
) (
bigInitialMarginQuoteQuantums *big.Int,
bigMaintenanceMarginQuoteQuantums *big.Int,
perpetual perpetualsmoduletypes.Perpetual,
price pricestypes.MarketPrice,
liquidityTier perpetualsmoduletypes.LiquidityTier,
err error,
)
GetPerpetual(
Expand Down
84 changes: 26 additions & 58 deletions protocol/x/perpetuals/keeper/perpetual.go
Original file line number Diff line number Diff line change
Expand Up @@ -874,64 +874,6 @@ func (k Keeper) GetNetCollateral(
return k.GetNetNotional(ctx, id, bigQuantums)
}

// GetMarginRequirements returns initial and maintenance margin requirements in quote quantums, given the position
// size in base quantums.
//
// Margin requirements are a function of the absolute value of the open notional of the position as well as
// the parameters of the relevant `LiquidityTier` of the perpetual.
// Initial margin requirement is determined by multiplying `InitialMarginPpm` and `notionalValue`.
// `notionalValue` is determined by multiplying the size of the position by the oracle price of the position.
// Maintenance margin requirement is then simply a fraction (`maintenanceFractionPpm`) of initial margin requirement.
//
// Returns an error if a perpetual with `id`, `perpetual.Params.MarketId`, or
// `perpetual.Params.LiquidityTier` does not exist.
//
// Note that this function is getting called very frequently; metrics in this function
// should be sampled to reduce CPU time.
func (k Keeper) GetMarginRequirements(
ctx sdk.Context,
id uint32,
bigQuantums *big.Int,
) (
bigInitialMarginQuoteQuantums *big.Int,
bigMaintenanceMarginQuoteQuantums *big.Int,
err error,
) {
if rand.Float64() < metrics.LatencyMetricSampleRate {
defer metrics.ModuleMeasureSinceWithLabels(
types.ModuleName,
[]string{metrics.GetMarginRequirements, metrics.Latency},
time.Now(),
[]gometrics.Label{
metrics.GetLabelForStringValue(
metrics.SampleRate,
fmt.Sprintf("%f", metrics.LatencyMetricSampleRate),
),
},
)
}

// Get perpetual and market price.
perpetual, marketPrice, err := k.GetPerpetualAndMarketPrice(ctx, id)
if err != nil {
return nil, nil, err
}
// Get perpetual's liquidity tier.
liquidityTier, err := k.GetLiquidityTier(ctx, perpetual.Params.LiquidityTier)
if err != nil {
return nil, nil, err
}

bigInitialMarginQuoteQuantums,
bigMaintenanceMarginQuoteQuantums = perplib.GetMarginRequirementsInQuoteQuantums(
perpetual,
marketPrice,
liquidityTier,
bigQuantums,
)
return bigInitialMarginQuoteQuantums, bigMaintenanceMarginQuoteQuantums, nil
}

// 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 Down Expand Up @@ -1244,6 +1186,32 @@ func (k Keeper) GetPerpetualAndMarketPrice(
return perpetual, marketPrice, nil
}

// GetPerpetualAndMarketPriceAndLiquidityTier retrieves a Perpetual by its id, its corresponding MarketPrice,
// and its corresponding LiquidityTier.
func (k Keeper) GetPerpetualAndMarketPriceAndLiquidityTier(
ctx sdk.Context,
perpetualId uint32,
) (
types.Perpetual,
pricestypes.MarketPrice,
types.LiquidityTier,
error,
) {
perpetual, err := k.GetPerpetual(ctx, perpetualId)
if err != nil {
return perpetual, pricestypes.MarketPrice{}, types.LiquidityTier{}, err
}
marketPrice, err := k.pricesKeeper.GetMarketPrice(ctx, perpetual.Params.MarketId)
if err != nil {
return perpetual, marketPrice, types.LiquidityTier{}, err
}
liquidityTier, err := k.GetLiquidityTier(ctx, perpetual.Params.LiquidityTier)
if err != nil {
return perpetual, marketPrice, liquidityTier, err
}
return perpetual, marketPrice, liquidityTier, nil
}

// Performs the following validation (stateful and stateless) on a `Perpetual`
// structs fields, returning an error if any conditions are false:
// - MarketId is not a valid market.
Expand Down
Loading

0 comments on commit edcc82b

Please sign in to comment.