Skip to content

Commit

Permalink
next
Browse files Browse the repository at this point in the history
  • Loading branch information
roy-dydx committed Mar 28, 2024
1 parent 6ec7df2 commit db54d73
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 22 deletions.
5 changes: 3 additions & 2 deletions protocol/x/clob/keeper/equity_tier_limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/lib"
"github.com/dydxprotocol/v4-chain/protocol/x/clob/types"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
"github.com/holiman/uint256"
)

// GetEquityTierLimitConfiguration gets the equity tier limit configuration from state.
Expand Down Expand Up @@ -63,7 +64,7 @@ func (k Keeper) getEquityTierLimitForSubaccount(
ctx sdk.Context, subaccountId satypes.SubaccountId,
equityTierLimits []types.EquityTierLimit,
) (equityTier types.EquityTierLimit, bigNetCollateral *big.Int, err error) {
netCollateral, _, _, err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirements(
netCollateral, _, _, err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirementsUint256(
ctx,
satypes.Update{
SubaccountId: subaccountId,
Expand All @@ -75,7 +76,7 @@ func (k Keeper) getEquityTierLimitForSubaccount(

var equityTierLimit types.EquityTierLimit
for _, limit := range equityTierLimits {
if netCollateral.Cmp(limit.UsdTncRequired.BigInt()) < 0 {
if netCollateral.Cmp(uint256.MustFromBig(limit.UsdTncRequired.BigInt())) < 0 {
break
}
equityTierLimit = limit
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/clob/keeper/process_single_match.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func (k Keeper) persistMatchedOrders(
}

// Apply the update.
success, successPerUpdate, err := k.subaccountsKeeper.UpdateSubaccounts(
success, successPerUpdate, err := k.subaccountsKeeper.CanUpdateSubaccountsUint256(
ctx,
updates,
satypes.Match,
Expand Down
10 changes: 10 additions & 0 deletions protocol/x/clob/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
perpetualsmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
"github.com/holiman/uint256"
)

type SubaccountsKeeper interface {
Expand Down Expand Up @@ -41,6 +42,15 @@ type SubaccountsKeeper interface {
bigMaintenanceMargin *big.Int,
err error,
)
GetNetCollateralAndMarginRequirementsUint256(
ctx sdk.Context,
update satypes.Update,
) (
bigNetCollateral *uint256.Int,
bigInitialMargin *uint256.Int,
bigMaintenanceMargin *uint256.Int,
err error,
)
GetSubaccount(
ctx sdk.Context,
id satypes.SubaccountId,
Expand Down
165 changes: 146 additions & 19 deletions protocol/x/subaccounts/keeper/subaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,133 @@ func (k Keeper) UpdateSubaccounts(
return success, successPerUpdate, err
}

func (k Keeper) UpdateSubaccountsUint256(
ctx sdk.Context,
updates []types.Update,
updateType types.UpdateType,
) (
success bool,
successPerUpdate []types.UpdateResult,
err error,
) {
defer metrics.ModuleMeasureSinceWithLabels(
types.ModuleName,
[]string{metrics.UpdateSubaccounts, metrics.Latency},
time.Now(),
[]gometrics.Label{
metrics.GetLabelForStringValue(metrics.UpdateType, updateType.String()),
},
)

settledUpdates, subaccountIdToFundingPayments, err := k.getSettledUpdates(ctx, updates, true)
if err != nil {
return false, nil, err
}

allPerps := k.perpetualsKeeper.GetAllPerpetuals(ctx)
success, successPerUpdate, err = k.internalCanUpdateSubaccountsUint256(
ctx,
settledUpdates,
updateType,
allPerps,
)

if !success || err != nil {
return success, successPerUpdate, err
}

// Get a mapping from perpetual Id to current perpetual funding index.
perpIdToFundingIndex := make(map[uint32]dtypes.SerializableInt)
for _, perp := range allPerps {
perpIdToFundingIndex[perp.Params.Id] = perp.FundingIndex
}

// Get OpenInterestDelta from the updates, and persist the OI change if any.
perpOpenInterestDelta := GetDeltaOpenInterestFromUpdatesUint256(settledUpdates, updateType)
if perpOpenInterestDelta != nil {
if err := k.perpetualsKeeper.ModifyOpenInterestUint256(
ctx,
perpOpenInterestDelta.PerpetualId,
perpOpenInterestDelta.BaseQuantums,
); err != nil {
return false, nil, errorsmod.Wrapf(
types.ErrCannotModifyPerpOpenInterestForOIMF,
"perpId = %v, delta = %v, settledUpdates = %+v, err = %v",
perpOpenInterestDelta.PerpetualId,
perpOpenInterestDelta.BaseQuantums,
settledUpdates,
err,
)
}
}

// Apply the updates to perpetual positions.
UpdatePerpetualPositions(
settledUpdates,
perpIdToFundingIndex,
)

// Apply the updates to asset positions.
UpdateAssetPositions(settledUpdates)

// Transfer collateral between collateral pools for any isolated perpetual positions that changed
// state due to an update.
for _, settledUpdateWithUpdatedSubaccount := range settledUpdates {
if err := k.computeAndExecuteCollateralTransfer(
ctx,
// The subaccount in `settledUpdateWithUpdatedSubaccount` already has the perpetual updates
// and asset updates applied to it.
settledUpdateWithUpdatedSubaccount,
allPerps,
); err != nil {
return false, nil, err
}
}

// Apply all updates, including a subaccount update event in the Indexer block message
// per update and emit a cometbft event for each settled funding payment.
for _, u := range settledUpdates {
k.SetSubaccount(ctx, u.SettledSubaccount)
// Below access is safe because for all updated subaccounts' IDs, this map
// is populated as getSettledSubaccount() is called in getSettledUpdates().
fundingPayments := subaccountIdToFundingPayments[*u.SettledSubaccount.Id]
k.GetIndexerEventManager().AddTxnEvent(
ctx,
indexerevents.SubtypeSubaccountUpdate,
indexerevents.SubaccountUpdateEventVersion,
indexer_manager.GetBytes(
indexerevents.NewSubaccountUpdateEvent(
u.SettledSubaccount.Id,
getUpdatedPerpetualPositions(
u,
fundingPayments,
),
getUpdatedAssetPositions(u),
fundingPayments,
),
),
)

// Emit an event indicating a funding payment was paid / received for each settled funding
// payment. Note that `fundingPaid` is positive if the subaccount paid funding,
// and negative if the subaccount received funding.
// Note the perpetual IDs are sorted first to ensure event emission determinism.
sortedPerpIds := lib.GetSortedKeys[lib.Sortable[uint32]](fundingPayments)
for _, perpetualId := range sortedPerpIds {
fundingPaid := fundingPayments[perpetualId]
ctx.EventManager().EmitEvent(
types.NewCreateSettledFundingEvent(
*u.SettledSubaccount.Id,
perpetualId,
fundingPaid.BigInt(),
),
)
}
}

return success, successPerUpdate, err
}

// CanUpdateSubaccounts will validate all `updates` to the relevant subaccounts.
// The `updates` do not have to contain unique `SubaccountIds`.
// Each update is considered in isolation. Thus if two updates are provided
Expand Down Expand Up @@ -898,9 +1025,9 @@ func (k Keeper) internalCanUpdateSubaccountsUint256(
// do not result in OI changes.
perpOpenInterestDelta := GetDeltaOpenInterestFromUpdatesUint256(settledUpdates, updateType)

bigCurNetCollateral := make(map[string]*big.Int)
bigCurInitialMargin := make(map[string]*big.Int)
bigCurMaintenanceMargin := make(map[string]*big.Int)
curNetCollateral := make(map[string]*uint256.Int)
curInitialMargin := make(map[string]*uint256.Int)
curMaintenanceMargin := make(map[string]*uint256.Int)

// Iterate over all updates.
for i, u := range settledUpdates {
Expand Down Expand Up @@ -943,10 +1070,10 @@ func (k Keeper) internalCanUpdateSubaccountsUint256(
}
}
// Get the new collateralization and margin requirements with the update applied.
bigNewNetCollateral,
bigNewInitialMargin,
bigNewMaintenanceMargin,
err := k.internalGetNetCollateralAndMarginRequirements(
newNetCollateral,
newInitialMargin,
newMaintenanceMargin,
err := k.internalGetNetCollateralAndMarginRequirementsUint256(
branchedContext,
u,
)
Expand All @@ -960,7 +1087,7 @@ func (k Keeper) internalCanUpdateSubaccountsUint256(

// The subaccount is not well-collateralized after the update.
// We must now check if the state transition is valid.
if bigNewInitialMargin.Cmp(bigNewNetCollateral) > 0 {
if newInitialMargin.Cmp(newNetCollateral) > 0 {
// Get the current collateralization and margin requirements without the update applied.
emptyUpdate := SettledUpdate{
SettledSubaccount: u.SettledSubaccount,
Expand All @@ -973,11 +1100,11 @@ func (k Keeper) internalCanUpdateSubaccountsUint256(
saKey := string(bytes)

// Cache the current collateralization and margin requirements for the subaccount.
if _, ok := bigCurNetCollateral[saKey]; !ok {
bigCurNetCollateral[saKey],
bigCurInitialMargin[saKey],
bigCurMaintenanceMargin[saKey],
err = k.internalGetNetCollateralAndMarginRequirements(
if _, ok := curNetCollateral[saKey]; !ok {
curNetCollateral[saKey],
curInitialMargin[saKey],
curMaintenanceMargin[saKey],
err = k.internalGetNetCollateralAndMarginRequirementsUint256(
ctx,
emptyUpdate,
)
Expand All @@ -987,12 +1114,12 @@ func (k Keeper) internalCanUpdateSubaccountsUint256(
}

// Determine whether the state transition is valid.
result = IsValidStateTransitionForUndercollateralizedSubaccount(
bigCurNetCollateral[saKey],
bigCurInitialMargin[saKey],
bigCurMaintenanceMargin[saKey],
bigNewNetCollateral,
bigNewMaintenanceMargin,
result = IsValidStateTransitionForUndercollateralizedSubaccountUint256(
curNetCollateral[saKey],
curInitialMargin[saKey],
curMaintenanceMargin[saKey],
newNetCollateral,
newMaintenanceMargin,
)
}

Expand Down

0 comments on commit db54d73

Please sign in to comment.