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

Prevent Collateral updates with pending orders #1711

Merged
merged 19 commits into from
Jul 18, 2023

Conversation

leomassazza
Copy link
Contributor

@leomassazza leomassazza commented Jul 7, 2023

Check if there's a pending order for the account for updateCollateral and commitOrder.
After some discussions the definition is that only a single pending order can exists per account, hence this PR also moves the asyncOrders mapping on PerpsMarket to a loadable AsyncOrder instance mostly used in PerpsAccount.

@leomassazza leomassazza self-assigned this Jul 7, 2023
@codecov
Copy link

codecov bot commented Jul 7, 2023

Codecov Report

Merging #1711 (a685a4f) into main (7e7143f) will not change coverage.
The diff coverage is n/a.

❗ Current head a685a4f differs from pull request most recent head f8449f1. Consider uploading reports for the commit f8449f1 to get more accurate results

@@           Coverage Diff           @@
##             main    #1711   +/-   ##
=======================================
  Coverage   72.77%   72.77%           
=======================================
  Files          57       57           
  Lines         720      720           
  Branches      236      236           
=======================================
  Hits          524      524           
  Misses        167      167           
  Partials       29       29           
Flag Coverage Δ
core-contracts 93.26% <ø> (ø)
core-modules 90.47% <ø> (ø)
core-utils 68.57% <ø> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@leomassazza leomassazza marked this pull request as ready for review July 11, 2023 13:51
@leomassazza leomassazza changed the title Prevent modifyCollateral with pending orders Prevent Collateral updates with pending orders Jul 11, 2023
@@ -54,6 +54,11 @@ contract PerpsAccountModule is IAccountModule {
account.id = accountId;
}

// Check if there are pending orders
if (account.hasPendingOrders) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add a check here that amountDelta < 0? I don't think a user should ever be prevented from depositing collateral, but it makes sense to prevent withdrawals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we need to check both sides in order to prevent some side effects we noticed on perpsv2 (i.e. ability to manipulate appropriate time to execute an order)

Copy link
Contributor

Choose a reason for hiding this comment

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

How could a person manipulate the timing by adding more collateral? I see how they could withdraw to cause the execution to revert, then deposit again when they want to execute.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea troy's point does make sense to me

Copy link
Member

@kaleb-keny kaleb-keny Jul 12, 2023

Choose a reason for hiding this comment

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

How could a person manipulate the timing by adding more collateral? I see how they could withdraw to cause the execution to revert, then deposit again when they want to execute.

@Tburm it just gives the user more tools to play with with bad intents, like imagine with me during crashing market prices, the user submits intention at the brink of what is possible with his margin, that by the time the order is elegible for execution, he doesn't have enough margin to get executed, he gets a free option to add collateral to be allowed to execute the pending order during that execution time window

Copy link
Member

Choose a reason for hiding this comment

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

It is a safer design therefore, to just allow modification of collateral if no pending order is there

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so, basically (we had this discussion on perpsV2, and there are some complex vectors or side effects) we want to prevent any change of collateral while orders are pending.

Copy link
Contributor

Choose a reason for hiding this comment

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

@kaleb-keny That makes sense, thanks for the detail. I assumed they could somehow guarantee better execution, but in your example it would still require some favorable price action.

Copy link
Member

Choose a reason for hiding this comment

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

@Tburm yeah the attacker would need to check for a favorable with respect to the more lively prices offchain (which are expected to impact his position post-execution)

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, thanks for the details. We should just make sure frontends are well aware of this, since users should know if/when they are prevented from depositing to fix underwater positions.

@0xjocke
Copy link
Contributor

0xjocke commented Jul 11, 2023

What's the difference between this and checking if the account have an order by PerpsMarket.loadValid(marketId).asyncOrders[accountId];?

@leomassazza
Copy link
Contributor Author

What's the difference between this and checking if the account have an order by PerpsMarket.loadValid(marketId).asyncOrders[accountId];?

it needs to be done in a loop for each marketId

systems().PerpsMarket
);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

No sure how valuable, but we could add an assertion for an order on the same market too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@davidvuong
Copy link
Contributor

davidvuong commented Jul 12, 2023

You can move orders from market to an account level and track a mapping of accountId -> struct { order, marketId }[] then you can avoid the need for an additional variable you have to remember to turn on/off. Would require shuffling a few things around but it's one less variable that have to be kept tracked and stored in-sync.

If you track marketId in the Order struct then it can even just be mapping(uint128 -> Order[]), without needing a wrapper struct.

Orders aren't tightly coupled to markets and they don't have an impact until settlement occurs. For settlement, as long as the keeper can find the associated marketId this order belongs to then it will operate just fine too.

@leomassazza leomassazza marked this pull request as draft July 13, 2023 13:58
@leomassazza leomassazza marked this pull request as ready for review July 13, 2023 17:00
Copy link
Contributor

@sunnyvempati sunnyvempati left a comment

Choose a reason for hiding this comment

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

minor changes; logic is clear and looks good 👍🏽

/**
* @notice Gets thrown when pending orders exist and attempts to modify collateral.
*/
error PendingOrdersExist();
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe rename to PendingOrderExists since we can't have multiple orders anyway

Comment on lines 62 to 70
AsyncOrder.Data storage order = AsyncOrder.load(commitment.accountId);

if (order.sizeDelta != 0) {
if (order.sizeDelta != 0 && order.marketId == commitment.marketId) {
revert OrderAlreadyCommitted(commitment.marketId, commitment.accountId);
}

if (order.sizeDelta != 0) {
revert IAccountModule.PendingOrdersExist();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe do AsyncOrder.createValid(..) and move all these checks into that function. would clean up this method quite a bit.

Comment on lines 57 to 60
// Check if there are pending orders
if (AsyncOrder.load(accountId).sizeDelta != 0) {
revert PendingOrdersExist();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

could move this into the account storage and do account.checkPendingOrders() or smth. as much as possible trying to move validations into storage libraries. non blocking; only if you think its cleaner

@@ -547,6 +547,7 @@ library PerpsAccount {
struct Data {
mapping(uint128 => uint256) collateralAmounts;
uint128 id;
bool hasPendingOrders;
Copy link
Contributor

Choose a reason for hiding this comment

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

dont think this is used; re-run yarn build 👍🏽

Copy link
Contributor

@sunnyvempati sunnyvempati left a comment

Choose a reason for hiding this comment

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

🚢

@sunnyvempati sunnyvempati merged commit bd7b5ce into main Jul 18, 2023
17 checks passed
@sunnyvempati sunnyvempati deleted the prevent-collateral-update-with-pending-orders branch July 18, 2023 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants