Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Performance] Remove the need to get each perpetual and price twice when checking collateralization #1681

Merged
merged 1 commit into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading