From db54d73d2c589464f0d2d84f290bade4cf3c4f8f Mon Sep 17 00:00:00 2001 From: Roy Li Date: Thu, 28 Mar 2024 17:53:29 -0400 Subject: [PATCH] next --- protocol/x/clob/keeper/equity_tier_limit.go | 5 +- .../x/clob/keeper/process_single_match.go | 2 +- protocol/x/clob/types/expected_keepers.go | 10 ++ protocol/x/subaccounts/keeper/subaccount.go | 165 ++++++++++++++++-- 4 files changed, 160 insertions(+), 22 deletions(-) diff --git a/protocol/x/clob/keeper/equity_tier_limit.go b/protocol/x/clob/keeper/equity_tier_limit.go index be4df49446..0081ab03c7 100644 --- a/protocol/x/clob/keeper/equity_tier_limit.go +++ b/protocol/x/clob/keeper/equity_tier_limit.go @@ -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. @@ -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, @@ -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 diff --git a/protocol/x/clob/keeper/process_single_match.go b/protocol/x/clob/keeper/process_single_match.go index 7410bdd140..6ca66964e9 100644 --- a/protocol/x/clob/keeper/process_single_match.go +++ b/protocol/x/clob/keeper/process_single_match.go @@ -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, diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index 53aed0ce27..e69c4d5585 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -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 { @@ -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, diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index ec79b1c2cb..22b20091d6 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -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 @@ -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 { @@ -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, ) @@ -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, @@ -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, ) @@ -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, ) }