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

[feat][protocol]: gate withdrawals if negative TNC subaccount encountered after liquidation and deleveraging steps #936

Merged
merged 10 commits into from Jan 10, 2024

Conversation

lucas-dydx
Copy link
Contributor

@lucas-dydx lucas-dydx commented Jan 5, 2024

Changelist

Gate withdrawals if a negative TNC subaccount is encountered after the liquidation and deleveraging steps in PrepareCheckState.

Note that all potentially liquidatable subaccounts specified by the daemon will be checked for simplicity.

Test Plan

Wrote E2E tests verifying that when there's negative TNC subaccounts found in state, that withdrawals are blocked.

Author/Reviewer Checklist

  • If this PR has changes that result in a different app state given the same prior state and transaction list, manually add the state-breaking label.
  • If the PR has breaking postgres changes to the indexer add the indexer-postgres-breaking label.
  • If this PR isn't state-breaking but has changes that modify behavior in PrepareProposal or ProcessProposal, manually add the label proposal-breaking.
  • If this PR is one of many that implement a specific feature, manually label them all feature:[feature-name].
  • If you wish to for mergify-bot to automatically create a PR to backport your change to a release branch, manually add the label backport/[branch-name].
  • Manually add any of the following labels: refactor, chore, bug.

Copy link

coderabbitai bot commented Jan 5, 2024

Walkthrough

The recent updates involve two main changes. Firstly, the error return values have been eliminated from several functions, simplifying the interface and possibly the error handling process. Secondly, the system has introduced a zero-fill deleveraging mechanism. This feature adds new checks and controls to manage withdrawals, ensuring that deleveraging operations can be executed without leaving any negative balances, which is crucial for maintaining the platform's financial integrity.

Changes

File(s) Change Summary
protocol/mocks/MemClob.go, protocol/mocks/MemClobKeeper.go Removed error returns from functions and restructured variable declarations.
protocol/x/clob/abci.go, protocol/x/clob/keeper/deleveraging.go, .../memclob/memclob.go, .../types/internal_operation.go, .../types/memclob.go, .../types/operations_to_propose.go Added zero-fill deleveraging operations with new checks and methods to control withdrawals and update logic flow.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@lucas-dydx lucas-dydx force-pushed the lucas-dydx/protocol-pcs-insert-zero-fill-delev branch from 0e1da1f to 7759ace Compare January 5, 2024 23:20
}

if !foundNegativeTncSubaccount {
return nil
Copy link
Contributor Author

@lucas-dydx lucas-dydx Jan 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Planning to add more metrics here.

  • Add counters for total calls to this method.
  • Add counters for halted withdrawals (can add alerts on this).
  • Add latency metrics to this method.

@lucas-dydx lucas-dydx changed the title WIP [feat][protocol]: gate withdrawals if negative TNC subaccount encountered after liquidation and deleveraging steps [feat][protocol]: gate withdrawals if negative TNC subaccount encountered after liquidation and deleveraging steps Jan 8, 2024
// Note the first TX is MsgProposeOperations, the second is all other TXs.
execResult := response.TxResults[1]
require.True(t, execResult.IsErr())
require.Equal(t, satypes.ErrFailedToUpdateSubaccounts.ABCICode(), execResult.Code)
Copy link
Contributor Author

@lucas-dydx lucas-dydx Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Planning to add the following additional tests:

  • Transfers and withdrawals become unblocked after WITHDRAWAL_AND_TRANSFERS_BLOCKED_AFTER_NEGATIVE_TNC_SUBACCOUNT_SEEN_BLOCKS blocks
  • Both transfers and withdrawals fail
  • Transfers and withdrawals are not blocked if subaccounts specified in negative TNC subaccounts have non-negative TNC after liquidations and deleveraging steps

@lucas-dydx lucas-dydx marked this pull request as ready for review January 8, 2024 22:57
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 13

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 7e793b6 and 23373f9.
Files selected for processing (9)
  • protocol/mocks/MemClob.go (17 hunks)
  • protocol/mocks/MemClobKeeper.go (13 hunks)
  • protocol/x/clob/abci.go (1 hunks)
  • protocol/x/clob/e2e/withdrawal_gating_test.go (1 hunks)
  • protocol/x/clob/keeper/deleveraging.go (1 hunks)
  • protocol/x/clob/memclob/memclob.go (1 hunks)
  • protocol/x/clob/types/internal_operation.go (1 hunks)
  • protocol/x/clob/types/memclob.go (1 hunks)
  • protocol/x/clob/types/operations_to_propose.go (1 hunks)
Additional comments: 22
protocol/x/clob/types/memclob.go (1)
  • 140-144: The addition of the InsertZeroFillDeleveragingIntoOperationsQueue method to the MemClob interface is consistent with the interface's design and the method signature follows Go's conventions.
protocol/x/clob/types/internal_operation.go (1)
  • 107-118: > Note: This review was outside the patches, and no patch overlapping with it was found. Original lines [26-26]

The removal of the panic condition in NewMatchPerpetualDeleveragingInternalOperation for zero maker fills seems to align with the introduction of zero-fill deleveraging operations. Ensure this change is intentional and does not introduce any unintended side effects.

Verification successful

The review of the operations_to_propose.go file confirms that the NewMatchPerpetualDeleveragingInternalOperation function is used correctly in the context of zero-fill deleveraging operations, as intended by the PR. The logic surrounding its usage is consistent with the system's design to differentiate between zero-fill and regular deleveraging operations. The removal of the panic condition for zero maker fills is intentional and does not introduce any unintended side effects based on the current usage within the codebase.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify that the removal of the panic condition is handled correctly in all usages of the function.
ast-grep --lang go --pattern $'NewMatchPerpetualDeleveragingInternalOperation($_, $_, $$$, $_)'

Length of output: 96



Script:

#!/bin/bash
# Attempt to find usages of the function with a modified pattern that accounts for any number of parameters.
ast-grep --lang go --pattern $'NewMatchPerpetualDeleveragingInternalOperation($$$)'

Length of output: 998



Script:

#!/bin/bash
# Review the implementation of the NewMatchPerpetualDeleveragingInternalOperation function and the surrounding logic.
cat ./protocol/x/clob/types/operations_to_propose.go

Length of output: 16408

protocol/x/clob/abci.go (1)
  • 235-240: The addition of logic to gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any negative TNC subaccounts are detected is a significant change for the system's financial integrity. Ensure this logic is correctly implemented and thoroughly tested.
protocol/mocks/MemClobKeeper.go (9)
  • 38-38: The changes in the AddOrderToOrderbookCollatCheck function seem to move the declaration of r1 outside of the conditional block. This change could potentially alter the behavior of the mock, depending on how the Called method is implemented. It's important to ensure that the mock's behavior remains consistent with the actual MemClobKeeper interface it's mocking.

  • 52-71: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [61-77]

In the AddPreexistingStatefulOrder function, the return variables r0, r1, r2, and r3 are declared outside of the conditional blocks. This change appears to be a refactor to simplify the code. Ensure that the refactor does not change the intended behavior of the mock, especially in cases where the Called method might return different types or fewer values than expected.

  • 98-105: The CanDeleverageSubaccount function has been refactored similarly to the previous functions, with return variables r0, r1, and r2 declared outside of the conditional blocks. Verify that the changes do not affect the mock's behavior, particularly in error handling and the return of boolean values.

  • 156-156: The GetLongTermOrderPlacement function's changes follow the same pattern as the previous functions. Ensure that the changes do not introduce any unintended side effects, especially since boolean return values can be critical in control flow within tests.

  • 177-184: The GetOrderFillAmount function's refactor also needs to be verified for consistency with the expected behavior. The mock should accurately reflect the behavior of the actual implementation it represents.

  • 221-221: The IsLiquidatable function's refactor includes moving the error return variable outside of the conditional block. Verify that this does not affect error handling in tests that use this mock.

  • 265-265: In the OffsetSubaccountPerpetualPosition function, the return variables are declared outside of the conditional blocks. This is a significant change since it involves a slice and a pointer to big.Int. Ensure that the mock continues to return the correct types and values as expected in various test scenarios.

  • 279-305: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [288-311]

The ProcessSingleMatch function has multiple return variables, and their declarations have been moved outside of the conditional blocks. This function seems to be more complex than the others, so it's crucial to verify that the changes do not introduce any regressions or behavior changes in the mock.

  • 323-342: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [332-348]

The ReplayPlaceOrder function's refactor is similar to the others, with return variables declared outside of the conditional blocks. Verify that the mock's behavior is consistent with the actual implementation, especially in terms of error handling and the return of complex types like *clobtypes.OffchainUpdates.

protocol/mocks/MemClob.go (1)
  • 285-288: The new function InsertZeroFillDeleveragingIntoOperationsQueue has been added. Ensure that this function is correctly implemented and that it matches the interface it's mocking.
protocol/x/clob/types/operations_to_propose.go (2)
  • 239-254: The new function AddZeroFillDeleveragingToOperationsQueue has been added without any panic conditions, unlike other functions in this file which have various checks that cause a panic if conditions are not met. It's important to ensure that this is intentional and that no checks are needed here for consistency and safety.
Verification successful

The output from the rg command indicates that the AddZeroFillDeleveragingToOperationsQueue function is the only function with an Add prefix in the OperationsToPropose type within the operations_to_propose.go file. This suggests that there are no other similar functions in this file that we can compare with regarding the presence or absence of panic conditions or checks.

Given this information, we cannot determine if the lack of panic conditions in the AddZeroFillDeleveragingToOperationsQueue function is consistent with similar functions in the same file, as there are no similar functions to compare with. The absence of other Add functions means that the review comment pointing out the lack of panic conditions cannot be confirmed as an inconsistency within the context of this specific file.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify if there are any other instances where similar functions do not perform checks.
rg "func \(o \*OperationsToPropose\) Add" protocol/x/clob/types/operations_to_propose.go

Length of output: 162

* 236-258: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [1-238]

The existing functions in the file have several panic conditions to ensure data integrity. It's crucial to maintain consistency across the file for error handling. The new function should likely follow the same pattern unless there's a specific reason not to.

Verification successful

The use of panic for error handling is consistent throughout the operations_to_propose.go file, as indicated by the multiple instances found in the output. This pattern is applied in various functions to ensure data integrity and handle exceptional cases that should not occur during normal operation.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify if the panic pattern is consistent across similar functions.
rg "panic" protocol/x/clob/types/operations_to_propose.go

Length of output: 1266

protocol/x/clob/memclob/memclob.go (7)
  • 218-230: The new method InsertZeroFillDeleveragingIntoOperationsQueue has been added to the MemClobPriceTimePriority struct. This method is responsible for inserting a zero-fill deleveraging operation into the operations queue, which is used to indicate that a subaccount has a negative TNC and withdrawals should be disabled. The method signature and logic appear to be correct and align with the PR objectives.

  • 231-231: The comment for the method mustUpdateMemclobStateWithMatches has been updated to clarify its functionality. It's important that comments accurately reflect the purpose and behavior of the code they describe.

  • 231-231: The method mustPerformTakerOrderMatching is complex and critical for the trading protocol's operation. It appears to handle the matching of taker orders against maker orders correctly, including various checks and updates to the state. However, due to its complexity, it is recommended to ensure thorough testing, particularly for edge cases and error conditions, to ensure the robustness of the matching logic.

  • 231-231: The method GetPricePremium performs a financial calculation that is critical to the protocol. It is important to ensure that the logic for calculating the price premium is correct and that all edge cases are handled properly. Given the financial implications, it is recommended to have this method reviewed by a domain expert in financial calculations to confirm its accuracy and robustness.

  • 231-231: The method GetMidPrice calculates the mid-price of an order book. It is important to ensure that the calculation correctly handles scenarios where the best bid or ask may not be present and that the method returns accurate and expected results. Given the importance of this metric in trading systems, it is recommended to verify the correctness of the calculation through unit tests.

  • 231-231: Methods like getImpactPriceSubticks and GetPricePremiumFromSide perform price calculations that are essential to the protocol's operation. It is crucial to ensure that these calculations are correct, handle edge cases, and avoid potential division by zero errors. It is recommended to verify the correctness of these methods through comprehensive unit tests and possibly peer review by domain experts.

  • 215-234: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [1-231]

The file memclob.go is extensive and complex, containing critical logic for the trading protocol's operation. Due to the complexity and the financial implications of the code, it is imperative to ensure thorough testing, including unit tests, integration tests, and end-to-end tests, to validate the correctness of the logic. Additionally, it is recommended to involve domain experts in the review process to confirm the accuracy of financial calculations and the robustness of the trading mechanisms.

Comment on lines 191 to 239
// GateWithdrawalsIfNegativeTncSubaccountSeen gates withdrawals if a negative TNC subaccount exists.
// It does this by inserting a zero-fill deleveraging operation into the operations queue iff any of
// the provided negative TNC subaccounts are still negative TNC.
func (k Keeper) GateWithdrawalsIfNegativeTncSubaccountSeen(
ctx sdk.Context,
negativeTncSubaccountIds []satypes.SubaccountId,
) (err error) {
foundNegativeTncSubaccount := false
var negativeTncSubaccountId satypes.SubaccountId
for _, subaccountId := range negativeTncSubaccountIds {
bigNetCollateral,
_,
_,
err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirements(
ctx,
satypes.Update{SubaccountId: subaccountId},
)
if err != nil {
return err
}

// If the subaccount has negative TNC, mark that a negative TNC subaccount was found.
if bigNetCollateral.Sign() == -1 {
foundNegativeTncSubaccount = true
negativeTncSubaccountId = subaccountId
break
}
}

if !foundNegativeTncSubaccount {
return nil
}

// A negative TNC subaccount was found, therefore insert a zero-fill deleveraging operation into
// the operations queue to indicate withdrawals should be gated.
subaccount := k.subaccountsKeeper.GetSubaccount(ctx, negativeTncSubaccountId)
perpetualPositions := subaccount.GetPerpetualPositions()
if len(perpetualPositions) == 0 {
return errorsmod.Wrapf(
types.ErrNoPerpetualPositionsToLiquidate,
"GateWithdrawalsIfNegativeTncSubaccountSeen: subaccount has no open positions: (%s)",
lib.MaybeGetJsonString(subaccount),
)
}
perpetualId := subaccount.PerpetualPositions[0].PerpetualId
k.MemClob.InsertZeroFillDeleveragingIntoOperationsQueue(ctx, negativeTncSubaccountId, perpetualId)

return nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new function GateWithdrawalsIfNegativeTncSubaccountSeen correctly implements the logic to gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if a negative TNC subaccount is found. However, there are a few points to consider:

  1. Error Handling: The function returns immediately if an error is encountered while fetching the net collateral and margin requirements. This is good practice as it prevents further execution with potentially invalid state.

  2. Loop Break: The loop breaks as soon as a negative TNC subaccount is found, which is efficient.

  3. Metrics and Logging: There are no metrics or logging statements within this function. Considering the previous comments on adding metrics, it would be beneficial to include metrics and logging here to monitor the frequency and context in which withdrawals are gated.

  4. Error Messages: The error message in line 229 is clear and provides enough information for debugging.

  5. Function Naming: The function name is descriptive and clearly indicates its purpose.

Overall, the function appears to be logically sound and aligns with the PR objectives. However, adding metrics and logging would enhance observability.

+ // TODO: Consider adding metrics and logging to monitor the gating of withdrawals.

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// GateWithdrawalsIfNegativeTncSubaccountSeen gates withdrawals if a negative TNC subaccount exists.
// It does this by inserting a zero-fill deleveraging operation into the operations queue iff any of
// the provided negative TNC subaccounts are still negative TNC.
func (k Keeper) GateWithdrawalsIfNegativeTncSubaccountSeen(
ctx sdk.Context,
negativeTncSubaccountIds []satypes.SubaccountId,
) (err error) {
foundNegativeTncSubaccount := false
var negativeTncSubaccountId satypes.SubaccountId
for _, subaccountId := range negativeTncSubaccountIds {
bigNetCollateral,
_,
_,
err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirements(
ctx,
satypes.Update{SubaccountId: subaccountId},
)
if err != nil {
return err
}
// If the subaccount has negative TNC, mark that a negative TNC subaccount was found.
if bigNetCollateral.Sign() == -1 {
foundNegativeTncSubaccount = true
negativeTncSubaccountId = subaccountId
break
}
}
if !foundNegativeTncSubaccount {
return nil
}
// A negative TNC subaccount was found, therefore insert a zero-fill deleveraging operation into
// the operations queue to indicate withdrawals should be gated.
subaccount := k.subaccountsKeeper.GetSubaccount(ctx, negativeTncSubaccountId)
perpetualPositions := subaccount.GetPerpetualPositions()
if len(perpetualPositions) == 0 {
return errorsmod.Wrapf(
types.ErrNoPerpetualPositionsToLiquidate,
"GateWithdrawalsIfNegativeTncSubaccountSeen: subaccount has no open positions: (%s)",
lib.MaybeGetJsonString(subaccount),
)
}
perpetualId := subaccount.PerpetualPositions[0].PerpetualId
k.MemClob.InsertZeroFillDeleveragingIntoOperationsQueue(ctx, negativeTncSubaccountId, perpetualId)
return nil
}
// GateWithdrawalsIfNegativeTncSubaccountSeen gates withdrawals if a negative TNC subaccount exists.
// It does this by inserting a zero-fill deleveraging operation into the operations queue iff any of
// the provided negative TNC subaccounts are still negative TNC.
// TODO: Consider adding metrics and logging to monitor the gating of withdrawals.
func (k Keeper) GateWithdrawalsIfNegativeTncSubaccountSeen(
ctx sdk.Context,
negativeTncSubaccountIds []satypes.SubaccountId,
) (err error) {
foundNegativeTncSubaccount := false
var negativeTncSubaccountId satypes.SubaccountId
for _, subaccountId := range negativeTncSubaccountIds {
bigNetCollateral,
_,
_,
err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirements(
ctx,
satypes.Update{SubaccountId: subaccountId},
)
if err != nil {
return err
}
// If the subaccount has negative TNC, mark that a negative TNC subaccount was found.
if bigNetCollateral.Sign() == -1 {
foundNegativeTncSubaccount = true
negativeTncSubaccountId = subaccountId
break
}
}
if !foundNegativeTncSubaccount {
return nil
}
// A negative TNC subaccount was found, therefore insert a zero-fill deleveraging operation into
// the operations queue to indicate withdrawals should be gated.
subaccount := k.subaccountsKeeper.GetSubaccount(ctx, negativeTncSubaccountId)
perpetualPositions := subaccount.GetPerpetualPositions()
if len(perpetualPositions) == 0 {
return errorsmod.Wrapf(
types.ErrNoPerpetualPositionsToLiquidate,
"GateWithdrawalsIfNegativeTncSubaccountSeen: subaccount has no open positions: (%s)",
lib.MaybeGetJsonString(subaccount),
)
}
perpetualId := subaccount.PerpetualPositions[0].PerpetualId
k.MemClob.InsertZeroFillDeleveragingIntoOperationsQueue(ctx, negativeTncSubaccountId, perpetualId)
return nil
}

@@ -37,6 +33,7 @@ func (_m *MemClob) CancelOrder(ctx types.Context, msgCancelOrder *clobtypes.MsgC
}
}

var r1 error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error variable r1 is declared but not used in the CancelOrder function. This is likely a leftover from the removal of error return values. The mock should be consistent with the interface it's mocking.

- var r1 error

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 error

@@ -82,6 +75,7 @@
}
}

var r1 error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the CancelOrder function, the DeleverageSubaccount function has an unused error variable r1. This should be removed to reflect the changes in the interface.

- var r1 error

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 error

if rf, ok := ret.Get(0).(func(types.Context, clobtypes.OrderId) uint32); ok {
r0 = rf(ctx, orderId)
} else {
r0 = ret.Get(0).(uint32)
}

var r1 bool
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetCancelOrder function has an unused boolean variable r1. If the function's signature has changed and it no longer returns an error, this variable should be removed.

- var r1 bool

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 bool

Comment on lines +120 to +134
var r1 clobtypes.Order
if rf, ok := ret.Get(1).(func(types.Context, clobtypes.ClobPairId) clobtypes.Order); ok {
r1 = rf(ctx, clobPairId)
} else {
r1 = ret.Get(1).(clobtypes.Order)
}

var r2 clobtypes.Order
if rf, ok := ret.Get(2).(func(types.Context, clobtypes.ClobPairId) clobtypes.Order); ok {
r2 = rf(ctx, clobPairId)
} else {
r2 = ret.Get(2).(clobtypes.Order)
}

var r3 bool
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetMidPrice function has multiple return variables (r1, r2, r3) that are declared but not used. If the function's signature has changed, these should be removed.

- var r1 clobtypes.Order
- var r2 clobtypes.Order
- var r3 bool

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 clobtypes.Order
if rf, ok := ret.Get(1).(func(types.Context, clobtypes.ClobPairId) clobtypes.Order); ok {
r1 = rf(ctx, clobPairId)
} else {
r1 = ret.Get(1).(clobtypes.Order)
}
var r2 clobtypes.Order
if rf, ok := ret.Get(2).(func(types.Context, clobtypes.ClobPairId) clobtypes.Order); ok {
r2 = rf(ctx, clobPairId)
} else {
r2 = ret.Get(2).(clobtypes.Order)
}
var r3 bool

if rf, ok := ret.Get(0).(func(types.Context, clobtypes.ClobPair, perpetualstypes.GetPricePremiumParams) int32); ok {
r0 = rf(ctx, clobPair, params)
} else {
r0 = ret.Get(0).(int32)
}

var r1 error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetPricePremium function has an unused error variable r1. This should be removed to reflect the changes in the interface.

- var r1 error

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 error

@@ -300,6 +272,7 @@
}
}

var r1 error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetSubaccountOrders function has an unused error variable r1. This should be removed to clean up the code.

- var r1 error

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
var r1 error

Comment on lines 282 to 311
return r0, r1
}

// InsertZeroFillDeleveragingIntoOperationsQueue provides a mock function with given fields: ctx, subaccountId, perpetualId
func (_m *MemClob) InsertZeroFillDeleveragingIntoOperationsQueue(ctx types.Context, subaccountId subaccountstypes.SubaccountId, perpetualId uint32) {
_m.Called(ctx, subaccountId, perpetualId)
}

// PlaceOrder provides a mock function with given fields: ctx, order
func (_m *MemClob) PlaceOrder(ctx types.Context, order clobtypes.Order) (subaccountstypes.BaseQuantums, clobtypes.OrderStatus, *clobtypes.OffchainUpdates, error) {
ret := _m.Called(ctx, order)

var r0 subaccountstypes.BaseQuantums
var r1 clobtypes.OrderStatus
var r2 *clobtypes.OffchainUpdates
var r3 error
if rf, ok := ret.Get(0).(func(types.Context, clobtypes.Order) (subaccountstypes.BaseQuantums, clobtypes.OrderStatus, *clobtypes.OffchainUpdates, error)); ok {
return rf(ctx, order)
}
if rf, ok := ret.Get(0).(func(types.Context, clobtypes.Order) subaccountstypes.BaseQuantums); ok {
r0 = rf(ctx, order)
} else {
r0 = ret.Get(0).(subaccountstypes.BaseQuantums)
}

var r1 clobtypes.OrderStatus
if rf, ok := ret.Get(1).(func(types.Context, clobtypes.Order) clobtypes.OrderStatus); ok {
r1 = rf(ctx, order)
} else {
r1 = ret.Get(1).(clobtypes.OrderStatus)
}

var r2 *clobtypes.OffchainUpdates
if rf, ok := ret.Get(2).(func(types.Context, clobtypes.Order) *clobtypes.OffchainUpdates); ok {
r2 = rf(ctx, order)
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [301-317]

The PlaceOrder function has an unused error variable r3. This should be removed if the function's signature has been updated.

- var r3 error

Comment on lines 329 to 348
ret := _m.Called(ctx, liquidationOrder)

var r0 subaccountstypes.BaseQuantums
var r1 clobtypes.OrderStatus
var r2 *clobtypes.OffchainUpdates
var r3 error
if rf, ok := ret.Get(0).(func(types.Context, clobtypes.LiquidationOrder) (subaccountstypes.BaseQuantums, clobtypes.OrderStatus, *clobtypes.OffchainUpdates, error)); ok {
return rf(ctx, liquidationOrder)
}
if rf, ok := ret.Get(0).(func(types.Context, clobtypes.LiquidationOrder) subaccountstypes.BaseQuantums); ok {
r0 = rf(ctx, liquidationOrder)
} else {
r0 = ret.Get(0).(subaccountstypes.BaseQuantums)
}

var r1 clobtypes.OrderStatus
if rf, ok := ret.Get(1).(func(types.Context, clobtypes.LiquidationOrder) clobtypes.OrderStatus); ok {
r1 = rf(ctx, liquidationOrder)
} else {
r1 = ret.Get(1).(clobtypes.OrderStatus)
}

var r2 *clobtypes.OffchainUpdates
if rf, ok := ret.Get(2).(func(types.Context, clobtypes.LiquidationOrder) *clobtypes.OffchainUpdates); ok {
r2 = rf(ctx, liquidationOrder)
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [338-354]

The PlacePerpetualLiquidation function has an unused error variable r3. This should be removed to reflect the changes in the interface.

- var r3 error

Comment on lines 236 to 258
)
}

// AddZeroFillDeleveragingToOperationsQueue adds a zero-fill deleveraging match operation to the
// operations queue.
func (o *OperationsToPropose) AddZeroFillDeleveragingToOperationsQueue(
liquidatedSubaccountId satypes.SubaccountId,
perpetualId uint32,
) {
o.OperationsQueue = append(
o.OperationsQueue,
NewMatchPerpetualDeleveragingInternalOperation(
liquidatedSubaccountId,
perpetualId,
[]MatchPerpetualDeleveraging_Fill{},
false,
),
)
}

// MustAddDeleveragingToOperationsQueue adds a deleveraging match operation to the
// operations queue.
// This function will panic if:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside the patches, and no patch overlapping with it was found. Original lines [9-9]

The TODO comment indicates that the public fields in the OperationsToPropose struct are a hack. This should be addressed to encapsulate the struct's fields properly, ensuring that they are only modified through methods that can maintain the integrity of the data.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 23373f9 and d58920e.
Files selected for processing (1)
  • protocol/x/clob/e2e/withdrawal_gating_test.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • protocol/x/clob/e2e/withdrawal_gating_test.go

Comment on lines 224 to 238
// A negative TNC subaccount was found, therefore insert a zero-fill deleveraging operation into
// the operations queue to indicate withdrawals should be gated.
subaccount := k.subaccountsKeeper.GetSubaccount(ctx, negativeTncSubaccountId)
perpetualPositions := subaccount.GetPerpetualPositions()
if len(perpetualPositions) == 0 {
return errorsmod.Wrapf(
types.ErrNoPerpetualPositionsToLiquidate,
"GateWithdrawalsIfNegativeTncSubaccountSeen: subaccount has no open positions: (%s)",
lib.MaybeGetJsonString(subaccount),
)
}
perpetualId := subaccount.PerpetualPositions[0].PerpetualId
k.MemClob.InsertZeroFillDeleveragingIntoOperationsQueue(ctx, negativeTncSubaccountId, perpetualId)

return nil
Copy link
Contributor

@jayy04 jayy04 Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can just modify memclob.DeleverageSubaccount for this.

We can set deltaQuantums to 0 and special case this within DeleverageSubaccount, so that we don't need these new functions like InsertZeroFillDeleveragingIntoOperationsQueue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly would prefer to avoid this. the current approach is simpler since it avoids modifying existing critical paths to add on a hack (this is prob not long-term withdrawal gating solution)

for example if we modify memclob.DeleverageSubaccount, then wouldn't we have to update the logic to handle cases where zero-fills are returned from OffsetSubaccountPerpetualPosition? maybe it's fine to add these to the op queue, but imo just makes things more complicated for little gain

given this is not the long-term solution, would rather add this new function so it's easy to rip out later once we build long-term solution for withdrawal gating

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah sounds good

Comment on lines +49 to +50
`Can place a liquidation order that is unfilled and cannot be deleveraged due to
non-overlapping bankruptcy prices, withdrawals are gated`: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the current implementation, liquidation order doesn't need to be unfilled and deleverage can still happen for withdrawals to be gated, right? since this is happening in step 8 which is after liquidations/deleveraging steps.

can we add tests for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I'll add tests for all variants of the below possible scenarios that can happen for verifying withdrawals are gated / not gated:

  • liquidation order unfilled, partial deleveraging
  • liquidation order filled, deleveraging fails
  • liquidation order filled, partial deleveraging

&withdrawMsg,
) {
resp := tApp.CheckTx(checkTx)
require.Conditionf(t, resp.IsOK, "Expected CheckTx to succeed. Response: %+v", resp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we can't reject withdrawals / transfers here? is it because we don't actually process the transfer until DeliverTx?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm yeah not sure if it's worth building an ante handler for this 🤔 nbd for now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i dont think it is personally since this is an edge case

ideally frontend's query whether withdrawals are blocked before submitting in vast majority of cases

lib.MaybeGetJsonString(subaccount),
)
}
perpetualId := subaccount.PerpetualPositions[0].PerpetualId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any case a subaccount can have negative TNC and have a no perpetual positions? ie price slips fast enough and we match/liquidate at a less favorable price than the bankruptcy price?

In this case do we want to default to some value if this doesn't exist? I don't think the perpetual id is used for zero fill deleveraging operations, so having a default would be good to protect against the error when we access a nonexisting array element.

Copy link
Contributor Author

@lucas-dydx lucas-dydx Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any case a subaccount can have negative TNC and have a no perpetual positions? ie price slips fast enough and we match/liquidate at a less favorable price than the bankruptcy price?

shouldn't be possible since subaccounts shouldn't be able to close out all of their positions and still have negative tnc

if this was possible, it would require a subaccount state transition to occur at a worse price than subaccount's bankruptcy price (price that subaccount tnc goes to zero), and that should be invalid

i agree it's still good to think through this though in case invariant gets violated. want me to create an m7 ticket to handle this? also maybe worth discussing with rest of CLOB team to ensure it never happens

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think quick fix we should just add a defeault value of 0, and make a ticket to think through edge cases later

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

synced on slack and we're not doing this for simplicity. created ticket here: https://linear.app/dydx/issue/CLOB-1061/use-default-perpetual-id-for-withdrawal-gating

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d58920e and c20eedf.
Files selected for processing (5)
  • protocol/lib/metrics/metric_keys.go (1 hunks)
  • protocol/x/clob/e2e/withdrawal_gating_test.go (1 hunks)
  • protocol/x/clob/keeper/deleveraging.go (1 hunks)
  • protocol/x/clob/keeper/process_operations.go (1 hunks)
  • protocol/x/clob/memclob/memclob.go (2 hunks)
Additional comments: 6
protocol/lib/metrics/metric_keys.go (1)
  • 42-51: The metric key names have been updated and a new metric GateWithdrawalsIfNegativeTncSubaccountSeen has been added. Ensure that these changes are reflected in any dashboards or alerts that use these metrics. Also, verify that the new metric is being used correctly in the code where withdrawal gating logic is implemented.
protocol/x/clob/e2e/withdrawal_gating_test.go (1)
  • 28-347: The test cases provided seem to cover various scenarios including the gating and ungating of withdrawals and transfers based on the state of TNC subaccounts. It's important to ensure that all the scenarios mentioned in the previous comments are indeed covered by these tests. Additionally, verify that the new logic does not introduce any regressions by running the full test suite.
protocol/x/clob/keeper/deleveraging.go (1)
  • 191-256: The new function GateWithdrawalsIfNegativeTncSubaccountSeen has been added to handle gating withdrawals when negative TNC subaccounts are detected. The function iterates over the provided subaccount IDs, checks for negative TNC, and if found, inserts a zero-fill deleveraging operation. This is in line with the PR objectives to enhance the protocol's financial stability.

However, there are a few points to consider:

  • Ensure that the function is called in the correct context where the gating of withdrawals is necessary.
  • Verify that the insertion of a zero-fill deleveraging operation is the appropriate action for all cases where a negative TNC subaccount is found.
  • Confirm that the function's error handling is consistent with the rest of the codebase, particularly with the use of errorsmod.Wrapf for error wrapping.
protocol/x/clob/keeper/process_operations.go (1)
  • 695-695: The addition of a new metric label DeliverTx with a value of true to the PersistMatchDeleveragingToState function is noted. This change is likely intended to provide more granular telemetry data. Ensure that this new metric is consistent with the telemetry strategy and that it is being used effectively in monitoring and alerting systems.
protocol/x/clob/memclob/memclob.go (2)
  • 10-10: The addition of the cmtlog import should be verified to ensure that it is used within the file and that it does not introduce any unused dependencies.
Verification successful

The output from the shell script confirms that the cmtlog import is indeed used within the memclob.go file. Specifically, it is used to create a new lazy sprintf with the order hash.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify that the cmtlog import is used in the file memclob.go
rg --type go 'cmtlog\.' protocol/x/clob/memclob/memclob.go

Length of output: 115

* 219-231: The new function `InsertZeroFillDeleveragingIntoOperationsQueue` is designed to insert a zero-fill deleveraging operation into the operations queue, which is used to indicate that a subaccount has negative TNC and withdrawals should be disabled. This change seems to align with the PR objectives of enhancing the deleveraging process and withdrawal gating mechanisms. Ensure that the logic of adding the operation to the queue is correct and that the function is called appropriately within the codebase.

@lucas-dydx lucas-dydx merged commit 04b7323 into main Jan 10, 2024
16 of 17 checks passed
@lucas-dydx lucas-dydx deleted the lucas-dydx/protocol-pcs-insert-zero-fill-delev branch January 10, 2024 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants