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

fix: keep track of pending withdrawals #16

Closed
wants to merge 6 commits into from

Conversation

xenoliss
Copy link
Contributor

@xenoliss xenoliss commented Apr 2, 2024

This PR fixes code-423n4/2024-03-coinbase-findings#110.

Implementation changes:

  1. Adds a _pendingWithdrawals state variable whose initial value is set to 1 (for gas)
  2. In validatePaymasterUserOp():
  • revert if the withdraw amount is above the available balance (available balance = balance - _pendingWithdrawals).
  • increment _pendingWithdrawals
  1. In postOp() reset _pendingWithdrawals to 1 if needed
  2. Revert with UnexpectedPostOpRevertedMode in postOp() instead of asserting.

Tests changes:
Minor refactoring, the biggest changes being in test_revertsInsufficientAvailableBalance() to add fuzzing.

revert InsufficientBalance(withdrawAmount, address(this).balance);
uint256 newPendingWithdrawals = _pendingWithdrawals + withdrawAmount;

if ((newPendingWithdrawals - 1) > address(this).balance) {
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure it's worth the gas / visual complexity of subtracting the 1 wei :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you recommend removing it entirely?

The point of this PR was to track the amounts to avoid our paymaster reputation being decreased in case where the bundler would include userops that revert at execution due to insufficient balance. If I remove this I wonder if someone could not use this off-by-one issue intentionally.

Copy link
Contributor

Choose a reason for hiding this comment

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

hmm I don't see a way to exploit this. In this case we are OVER estimating pending withdraws? So the failure case there is a withdraw that gets rejected in validation but could have succeeded?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh right my bad!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not implemented in this PR, will reconsider it for later.

amount = withdrawAmount;

vm.deal(address(magic), initialBalance);
vm.store(address(magic), bytes32(uint256(0)), bytes32(pendingWithdrawals + 1));
Copy link
Contributor

Choose a reason for hiding this comment

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

might be better to test multiple calls to validate so that we ensure we are setting / updating correctly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The best approach might be to have a test that simulates the bundler (validation + execution) and keep those unit tests focused on ~1 use case.

Copy link
Contributor

Choose a reason for hiding this comment

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

We have integration tests here if you want to write new one https://github.com/coinbase/magic-spend/blob/main/test/Integration.t.sol

I think we could have here test_reverts_whenBalanceTooLow1Withdraw test_reverts_whenBalanceTooLow2Withdraws

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I replaced the current test implementation to perform two successive validations that exhaust (and exceed) the available balance.

@xenoliss
Copy link
Contributor Author

xenoliss commented Apr 4, 2024

Closing as a simpler and effective approach is preferred (see #17)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants