Closed c4-bot-3 closed 2 months ago
saxenism (sponsor) disputed
This is an invalid report, since paymaster won't lose the refund, the user will. Also, it is by design and mentioned in our doc
The Warden specifies that a gas refund's failure is not handled and is instead ignored. I believe this behavior conforms with the intended design, as we would not want errors in gas refunds towards a paymaster to result in a transaction's failure. As such, I consider this exhibit invalid and better suited as part of an Analysis report as criticism.
alex-ppg marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2024-03-zksync/blob/4f0ba34f34a864c354c7e8c47643ed8f4a250e13/code/system-contracts/bootloader/bootloader.yul#L1583-L1595
Vulnerability details
zkSync supports account abstraction natively.
bootloader.yul
, which is entrypoint to EraVM, will execute multiple transactions, taking some parts of the EVM on its shoulders, like refunding gas unspent on transaction to user.When a refund for transaction is processed, function
refundCurrentL2Transaction
is called, which in turn usesZKSYNC_NEAR_CALL_callPostOp()
- account abstraction definedpostOp
(reference implementation of ERC-4337 postOp).However, low level call result of
postOp
is popped, and it's the result of calling paymaster to retrieve the refund. If it fails for whatever reason, it won't be terated as a failure, and the paymaster will loose refund.Impact
Paymaster gas refund loss
Proof of Concept
The issue starts with
processL2Tx
:After transaction is executed in
l2TxExecution()
function,gasToRefund
is taken fromgasLeft - gasSpentOnExecute
. This value is then passed torefundCurrentL2Transaction()
function.So, to summarize, the function above checks if there is paymaster defined for transaction. If yes, then it calls
ZKSYNC_NEAR_CALL_callPostOp()
- account abstraction definedpostOp
. Low level call returnssuccess
, which signifies if the call succeded of failed. This important information, because it means if the refund from paymaster to user succeded or not.This result is, however, popped -
pop(ZKSYNC_NEAR_CALL_callPostOp[...]
- meaning that the check is skipped. In case thatpostOp
fails, it's still considered successful, however the paymaster for this transaction won't get refunded for unspent gas.Tools Used
Manual Review
Recommended Mitigation Steps
Consider either reverting transaction that fails on
postOp
, or introduce contract that would allow paymasters to retrieve failed refunds later.Assessed type
Invalid Validation