Skip to content

Commit

Permalink
next tick deleveraging
Browse files Browse the repository at this point in the history
  • Loading branch information
jayy04 committed May 28, 2024
1 parent e2b8cb8 commit cb41ada
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 57 deletions.
1 change: 1 addition & 0 deletions .github/workflows/protocol-build-and-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on: # yamllint disable-line rule:truthy
- main
- 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x
- 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x
- 'jy/heap'

jobs:
build-and-push-dev:
Expand Down
34 changes: 20 additions & 14 deletions protocol/x/clob/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ func EndBlocker(
// Prune any rate limiting information that is no longer relevant.
keeper.PruneRateLimits(ctx)

keeper.NextTickDeleverage(ctx)

// Emit relevant metrics at the end of every block.
metrics.SetGauge(
metrics.InsuranceFundBalance,
Expand Down Expand Up @@ -219,30 +221,34 @@ func PrepareCheckState(

// 6. Get all potentially liquidatable subaccount IDs and attempt to liquidate them.
liquidatableSubaccountIds := keeper.DaemonLiquidationInfo.GetLiquidatableSubaccountIds()
subaccountsToDeleverage, err := keeper.LiquidateSubaccountsAgainstOrderbook(ctx, liquidatableSubaccountIds)
_, err := keeper.LiquidateSubaccountsAgainstOrderbook(ctx, liquidatableSubaccountIds)
if err != nil {
panic(err)
}

// Add subaccounts with open positions in final settlement markets to the slice of subaccounts/perps
// to be deleveraged.
subaccountsToDeleverage = append(
subaccountsToDeleverage,
keeper.GetSubaccountsWithPositionsInFinalSettlementMarkets(ctx)...,
)

// 7. Deleverage subaccounts.
// TODO(CLOB-1052) - decouple steps 6 and 7 by using DaemonLiquidationInfo.NegativeTncSubaccounts
// as the input for this function.
if err := keeper.DeleverageSubaccounts(ctx, subaccountsToDeleverage); err != nil {
panic(err)
}
// subaccountsToDeleverage = append(
// subaccountsToDeleverage,
// keeper.GetSubaccountsWithPositionsInFinalSettlementMarkets(ctx)...,
// )

// // 7. Deleverage subaccounts.
// // TODO(CLOB-1052) - decouple steps 6 and 7 by using DaemonLiquidationInfo.NegativeTncSubaccounts
// // as the input for this function.
// if err := keeper.DeleverageSubaccounts(ctx, subaccountsToDeleverage); err != nil {
// panic(err)
// }

// 8. Gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any
// of the negative TNC subaccounts still have negative TNC after liquidations and deleveraging steps.
negativeTncSubaccountIds := keeper.DaemonLiquidationInfo.GetNegativeTncSubaccountIds()
if err := keeper.GateWithdrawalsIfNegativeTncSubaccountSeen(ctx, negativeTncSubaccountIds); err != nil {
panic(err)
if len(negativeTncSubaccountIds) > 0 {
log.ErrorLog(ctx, "Found negative TNC subaccounts with next tick deleveraging")
}
// if err := keeper.GateWithdrawalsIfNegativeTncSubaccountSeen(ctx, negativeTncSubaccountIds); err != nil {
// panic(err)
// }

// Send all off-chain Indexer events
keeper.SendOffchainMessages(offchainUpdates, nil, metrics.SendPrepareCheckStateOffchainUpdates)
Expand Down
120 changes: 120 additions & 0 deletions protocol/x/clob/keeper/deleveraging.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ import (
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
)

func (k Keeper) NextTickDeleverage(
ctx sdk.Context,
) {
negativeTncSubaccounts := k.subaccountsKeeper.GetAllNegativeTncSubaccounts(ctx)

for _, subaccountId := range negativeTncSubaccounts {
k.DeleverageEntireSubaccount(ctx, subaccountId)
}
}

func (k Keeper) DeleverageEntireSubaccount(
ctx sdk.Context,
subaccountId satypes.SubaccountId,
) {
subaccount := k.subaccountsKeeper.GetSubaccount(ctx, subaccountId)
for _, position := range subaccount.PerpetualPositions {
k.OffsetSubaccountPerpetualPositionV2(ctx, subaccountId, position.PerpetualId)
}
}

// MaybeDeleverageSubaccount is the main entry point to deleverage a subaccount. It attempts to find positions
// on the opposite side of deltaQuantums and use them to offset the liquidated subaccount's position at
// the bankruptcy price of the liquidated position.
Expand Down Expand Up @@ -289,6 +309,106 @@ func (k Keeper) IsValidInsuranceFundDelta(ctx sdk.Context, insuranceFundDelta *b
return new(big.Int).Add(currentInsuranceFundBalance, insuranceFundDelta).Sign() >= 0
}

func (k Keeper) OffsetSubaccountPerpetualPositionV2(
ctx sdk.Context,
liquidatedSubaccountId satypes.SubaccountId,
perpetualId uint32,
) {
liquidatedSubaccount := k.subaccountsKeeper.GetSubaccount(ctx, liquidatedSubaccountId)
position, exists := liquidatedSubaccount.GetPerpetualPositionForId(perpetualId)
if !exists {
log.ErrorLog(
ctx,
"Failed to find position for perpetual in liquidated subaccount",
"perpetualId", perpetualId,
"liquidatedSubaccount", liquidatedSubaccount,
)
return
}
deltaQuantumsRemaining := new(big.Int).Neg(position.GetBigQuantums())

// Find subaccounts with open positions on the opposite side of the liquidated subaccount.
var offsettingSide satypes.PositionSide
if deltaQuantumsRemaining.Sign() == -1 {
offsettingSide = satypes.Short
} else {
offsettingSide = satypes.Long
}
subaccountsWithOpenPositions := k.subaccountsKeeper.GetSubaccountsWithOpenPositionsOnSide(
ctx,
perpetualId,
offsettingSide,
)

for index := 0; index < len(subaccountsWithOpenPositions) && deltaQuantumsRemaining.Sign() != 0; index++ {
subaccountId := subaccountsWithOpenPositions[index]

offsettingSubaccount := k.subaccountsKeeper.GetSubaccount(ctx, subaccountId)
offsettingPosition, _ := offsettingSubaccount.GetPerpetualPositionForId(perpetualId)
bigOffsettingPositionQuantums := offsettingPosition.GetBigQuantums()

// Skip subaccounts that do not have a position in the opposite direction as the liquidated subaccount.
if deltaQuantumsRemaining.Sign() != bigOffsettingPositionQuantums.Sign() {
continue
}

// TODO(DEC-1495): Determine max amount to offset per offsetting subaccount.
var deltaBaseQuantums *big.Int
if deltaQuantumsRemaining.CmpAbs(bigOffsettingPositionQuantums) > 0 {
deltaBaseQuantums = new(big.Int).Set(bigOffsettingPositionQuantums)
} else {
deltaBaseQuantums = 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,
deltaBaseQuantums,
false,
)
if err != nil {
panic("failed to get deleveraging quote quantums delta")
}

// Try to process the deleveraging operation for both subaccounts.
if err := k.ProcessDeleveraging(
ctx,
liquidatedSubaccountId,
*offsettingSubaccount.Id,
perpetualId,
deltaBaseQuantums,
deltaQuoteQuantums,
); err == nil {
// Update the remaining liquidatable quantums.
deltaQuantumsRemaining.Sub(deltaQuantumsRemaining, deltaBaseQuantums)
} else if errors.Is(err, types.ErrInvalidPerpetualPositionSizeDelta) {
panic(
fmt.Sprintf(
"Invalid perpetual position size delta when processing deleveraging. error: %v",
err,
),
)
} else {
// If an error is returned, it's likely because the subaccounts' bankruptcy prices do not overlap.
// TODO(CLOB-75): Support deleveraging subaccounts with non overlapping bankruptcy prices.
liquidatedSubaccount := k.subaccountsKeeper.GetSubaccount(ctx, liquidatedSubaccountId)
offsettingSubaccount := k.subaccountsKeeper.GetSubaccount(ctx, *offsettingSubaccount.Id)
log.ErrorLog(ctx, "Encountered error when processing deleveraging",
err,
"blockHeight", ctx.BlockHeight(),
"checkTx", ctx.IsCheckTx(),
"perpetualId", perpetualId,
"deltaBaseQuantums", deltaBaseQuantums,
"liquidatedSubaccount", liquidatedSubaccount,
"offsettingSubaccount", offsettingSubaccount,
)
}
}
}

// OffsetSubaccountPerpetualPosition iterates over all subaccounts and use those with positions
// on the opposite side to offset the liquidated subaccount's position by `deltaQuantumsTotal`.
//
Expand Down
8 changes: 8 additions & 0 deletions protocol/x/clob/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ type SubaccountsKeeper interface {
ctx sdk.Context,
perpetualId uint32,
) (sdk.AccAddress, error)
GetAllNegativeTncSubaccounts(
ctx sdk.Context,
) []satypes.SubaccountId
GetSubaccountsWithOpenPositionsOnSide(
ctx sdk.Context,
perpetualId uint32,
side satypes.PositionSide,
) []satypes.SubaccountId
}

type AssetsKeeper interface {
Expand Down
Loading

0 comments on commit cb41ada

Please sign in to comment.