-
Notifications
You must be signed in to change notification settings - Fork 124
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
[CLOB-1028] allow settlement at oracle price in ProcessDeleveraging #835
Changes from 6 commits
64598c8
81bd4b7
b2e6b2e
f81ad94
25bcb31
64503ff
b469e2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -236,13 +236,36 @@ func (k Keeper) OffsetSubaccountPerpetualPosition( | |
deltaQuantums = new(big.Int).Set(deltaQuantumsRemaining) | ||
} | ||
|
||
// Fetch delta quote quantums. Calculated at bankruptcy price for standard | ||
// deleveraging and at oracle price for final settlement deleveraging. | ||
deltaQuoteQuantums, err := k.getDeleveragingQuoteQuantumsDelta( | ||
ctx, | ||
perpetualId, | ||
liquidatedSubaccountId, | ||
deltaQuantums, | ||
) | ||
if err != nil { | ||
liquidatedSubaccount := k.subaccountsKeeper.GetSubaccount(ctx, liquidatedSubaccountId) | ||
k.Logger(ctx).Error( | ||
"Encountered error when getting quote quantums for deleveraging", | ||
"error", err, | ||
"blockHeight", ctx.BlockHeight(), | ||
"perpetualId", perpetualId, | ||
"deltaQuantums", deltaQuantums, | ||
"liquidatedSubaccount", liquidatedSubaccount, | ||
"offsettingSubaccount", offsettingSubaccount, | ||
) | ||
return false | ||
} | ||
|
||
// Try to process the deleveraging operation for both subaccounts. | ||
if err := k.ProcessDeleveraging( | ||
ctx, | ||
liquidatedSubaccountId, | ||
*offsettingSubaccount.Id, | ||
perpetualId, | ||
deltaQuantums, | ||
deltaQuoteQuantums, | ||
); err == nil { | ||
// Update the remaining liquidatable quantums. | ||
deltaQuantumsRemaining = new(big.Int).Sub( | ||
|
@@ -305,22 +328,48 @@ func (k Keeper) OffsetSubaccountPerpetualPosition( | |
return fills, deltaQuantumsRemaining | ||
} | ||
|
||
// getDeleveragingQuoteQuantums returns the quote quantums delta to apply to a deleveraging operation. | ||
// This returns the bankruptcy price for standard deleveraging operations, and the oracle price for | ||
// final settlement deleveraging operations. The type of deleveraging event is determined by the | ||
// clob pair status of the clob pair associated with the provided perpetual. | ||
func (k Keeper) getDeleveragingQuoteQuantumsDelta( | ||
ctx sdk.Context, | ||
perpetualId uint32, | ||
subaccountId satypes.SubaccountId, | ||
deltaQuantums *big.Int, | ||
) (*big.Int, error) { | ||
clobPair := k.mustGetClobPairForPerpetualId(ctx, perpetualId) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: is it okay if we panic here? This logic is executed in PrepareCheckState. Would we rather recover from this and continue? I think it is fine to panic but just want to double check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah should be fine to panic - if clob pair is missing, then something is really really wrong There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just realized this function isn't doing exactly what I want for usability. The purpose of this function is to allow the deleveraging flow to be reusable such that non-negative TNC subaccounts with positions in a final settlement market can be closed at the oracle price. Currently this function is written such that ALL subaccounts (including negative TNC) for the closed market will be settled at oracle price. This isn't what we want. I think the easiest way to updated this would be to do a collateral check and use the oracle price iff I think what I'll do here is use |
||
isFinalSettlement := clobPair.Status == types.ClobPair_STATUS_FINAL_SETTLEMENT | ||
|
||
if isFinalSettlement { | ||
return k.perpetualsKeeper.GetNetNotional(ctx, perpetualId, deltaQuantums) | ||
} | ||
|
||
return k.GetBankruptcyPriceInQuoteQuantums( | ||
ctx, | ||
subaccountId, | ||
perpetualId, | ||
deltaQuantums, | ||
) | ||
} | ||
|
||
// ProcessDeleveraging processes a deleveraging operation by closing both the liquidated subaccount's | ||
// position and the offsetting subaccount's position at the bankruptcy price of the _liquidated_ position. | ||
// This function takes a `deltaQuantums` argument, which is the delta with respect to the liquidated subaccount's | ||
// position, to allow for partial deleveraging. This function emits a cometbft event if the deleveraging match | ||
// is successfully written to state. | ||
// | ||
// This function returns an error if: | ||
// - `deltaQuantums` is not valid with respect to either of the subaccounts. | ||
// - `deltaBaseQuantums` is not valid with respect to either of the subaccounts. | ||
// - `GetBankruptcyPriceInQuoteQuantums` returns an error. | ||
// - subaccount updates cannot be applied when the bankruptcy prices of both subaccounts don't overlap. | ||
func (k Keeper) ProcessDeleveraging( | ||
ctx sdk.Context, | ||
liquidatedSubaccountId satypes.SubaccountId, | ||
offsettingSubaccountId satypes.SubaccountId, | ||
perpetualId uint32, | ||
deltaQuantums *big.Int, | ||
deltaBaseQuantums *big.Int, | ||
deltaQuoteQuantums *big.Int, | ||
) ( | ||
err error, | ||
) { | ||
|
@@ -338,36 +387,24 @@ func (k Keeper) ProcessDeleveraging( | |
// by checking that `deltaQuantums` is on the opposite side of the liquidated position side, | ||
// the same side as the offsetting subaccount position side, and the magnitude of `deltaQuantums` | ||
// is not larger than both positions. | ||
if liquidatedPositionQuantums.Sign()*deltaQuantums.Sign() != -1 || | ||
liquidatedPositionQuantums.CmpAbs(deltaQuantums) == -1 || | ||
offsettingPositionQuantums.Sign()*deltaQuantums.Sign() != 1 || | ||
offsettingPositionQuantums.CmpAbs(deltaQuantums) == -1 { | ||
if liquidatedPositionQuantums.Sign()*deltaBaseQuantums.Sign() != -1 || | ||
liquidatedPositionQuantums.CmpAbs(deltaBaseQuantums) == -1 || | ||
offsettingPositionQuantums.Sign()*deltaBaseQuantums.Sign() != 1 || | ||
offsettingPositionQuantums.CmpAbs(deltaBaseQuantums) == -1 { | ||
return errorsmod.Wrapf( | ||
types.ErrInvalidPerpetualPositionSizeDelta, | ||
"ProcessDeleveraging: liquidated = (%s), offsetting = (%s), perpetual id = (%d), deltaQuantums = (%+v)", | ||
lib.MaybeGetJsonString(liquidatedSubaccount), | ||
lib.MaybeGetJsonString(offsettingSubaccount), | ||
perpetualId, | ||
deltaQuantums, | ||
deltaBaseQuantums, | ||
) | ||
} | ||
|
||
// Calculate the bankruptcy price of the liquidated position. This is the price at which both positions | ||
// are closed. | ||
bankruptcyPriceQuoteQuantums, err := k.GetBankruptcyPriceInQuoteQuantums( | ||
ctx, | ||
liquidatedSubaccountId, | ||
perpetualId, | ||
deltaQuantums, | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
deleveragedSubaccountQuoteBalanceDelta := bankruptcyPriceQuoteQuantums | ||
offsettingSubaccountQuoteBalanceDelta := new(big.Int).Neg(bankruptcyPriceQuoteQuantums) | ||
deleveragedSubaccountPerpetualQuantumsDelta := deltaQuantums | ||
offsettingSubaccountPerpetualQuantumsDelta := new(big.Int).Neg(deltaQuantums) | ||
deleveragedSubaccountQuoteBalanceDelta := deltaQuoteQuantums | ||
offsettingSubaccountQuoteBalanceDelta := new(big.Int).Neg(deltaQuoteQuantums) | ||
deleveragedSubaccountPerpetualQuantumsDelta := deltaBaseQuantums | ||
offsettingSubaccountPerpetualQuantumsDelta := new(big.Int).Neg(deltaBaseQuantums) | ||
|
||
updates := []satypes.Update{ | ||
// Liquidated subaccount update. | ||
|
@@ -419,12 +456,12 @@ func (k Keeper) ProcessDeleveraging( | |
if deleveragedQuoteQuantums, err := k.perpetualsKeeper.GetNetCollateral( | ||
ctx, | ||
perpetualId, | ||
new(big.Int).Abs(deltaQuantums), | ||
new(big.Int).Abs(deltaBaseQuantums), | ||
); err == nil { | ||
labels := []metrics.Label{ | ||
metrics.GetLabelForIntValue(metrics.PerpetualId, int(perpetualId)), | ||
metrics.GetLabelForBoolValue(metrics.CheckTx, ctx.IsCheckTx()), | ||
metrics.GetLabelForBoolValue(metrics.IsLong, deltaQuantums.Sign() == -1), | ||
metrics.GetLabelForBoolValue(metrics.IsLong, deltaBaseQuantums.Sign() == -1), | ||
} | ||
|
||
metrics.AddSampleWithLabels( | ||
|
@@ -463,9 +500,9 @@ func (k Keeper) ProcessDeleveraging( | |
liquidatedSubaccountId, | ||
offsettingSubaccountId, | ||
perpetualId, | ||
satypes.BaseQuantums(new(big.Int).Abs(deltaQuantums).Uint64()), | ||
satypes.BaseQuantums(bankruptcyPriceQuoteQuantums.Uint64()), | ||
deltaQuantums.Sign() > 0, | ||
satypes.BaseQuantums(new(big.Int).Abs(deltaBaseQuantums).Uint64()), | ||
satypes.BaseQuantums(deltaQuoteQuantums.Uint64()), | ||
deltaBaseQuantums.Sign() > 0, | ||
), | ||
), | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errors returned from bankruptcy price calculation were previously caught within ProcessDeleveraging and recovered from in OffsetSubaccountPerpetualPosition, continuing onto the next iteration without breaking. I am opting to continue this pattern, but will log a debug msg