Platform: Code4rena
Start Date: 01/12/2022
Pot Size: $26,900 USDC
Total HM: 3
Participants: 19
Period: 4 days
Judge: GalloDaSballo
Id: 188
League: ETH
Rank: 5/19
Findings: 1
Award: $1,702.50
π Selected for report: 1
π Solo Findings: 0
1702.4987 USDC - $1,702.50
When the user calls CrossChainRelayerArbitrum.processCalls, ETH is sent as the submission fee. According to the documentation : https://github.com/OffchainLabs/arbitrum/blob/master/docs/L1_L2_Messages.md#retryable-transaction-lifecycle
Credit-Back Address: Address to which all excess gas is credited on L2; i.e., excess ETH for base submission cost (MaxSubmissionCost - ActualSubmissionCostPaid) and excess ETH provided for L2 execution ( (GasPrice x MaxGas) - ActualETHSpentInExecution). ... Submission fee is collected: submission fee is deducted from the senderβs L2 account; MaxSubmissionCost - submission fee is credited to Credit-Back Address.
the excess submission fee is refunded to the address on L2 of the excessFeeRefundAddress provided when calling createRetryableTicket.
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts * @dev all msg.value will deposited to callValueRefundAddress on L2 * @param destAddr destination L2 contract address * @param l2CallValue call value for retryable L2 message * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee * @param excessFeeRefundAddress maxgas x gasprice - execution cost gets credited here on L2 balance * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled * @param maxGas Max gas deducted from user's L2 balance to cover L2 execution * @param gasPriceBid price bid for L2 execution * @param data ABI encoded data of L2 message * @return unique id for retryable transaction (keccak256(requestID, uint(0) ) */ function createRetryableTicket( address destAddr, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 maxGas, uint256 gasPriceBid, bytes calldata data ) external payable virtual override onlyWhitelisted returns (uint256) {
In CrossChainRelayerArbitrum.processCalls, excessFeeRefundAddress == msg.sender.
uint256 _ticketID = inbox.createRetryableTicket{ value: msg.value }( address(executor), 0, _maxSubmissionCost, msg.sender, // @audit : excessFeeRefundAddress msg.sender, // @audit: callValueRefundAddress _gasLimit, _gasPriceBid, _data );
For EOA accounts, the excess submission fees are correctly refunded to their address on L2. However, for smart contracts, since there may not exist a corresponding address on L2, these excess submission fees will be lost.
Also, since the callValueRefundAddress is also msg.sender, according to the documentation, if the Retryable Ticket is cancelled or expired, then the smart contract caller may lose all the submission fees
If the Retryable Ticket is cancelled or expires before it is redeemed, Callvalue is credited to Beneficiary.
https://github.com/pooltogether/ERC5164/blob/5647bd84f2a6d1a37f41394874d567e45a97bf48/src/ethereum-arbitrum/EthereumToArbitrumRelayer.sol#L118-L127 https://github.com/OffchainLabs/arbitrum/blob/master/packages/arb-bridge-eth/contracts/bridge/Inbox.sol#L333-L354
None
Consider allowing the user to specify excessFeeRefundAddress and callValueRefundAddress when calling CrossChainRelayerArbitrum.processCalls
#0 - GalloDaSballo
2022-12-11T20:38:48Z
Making primary for quality of info.
Ultimately boils down to the idea that contracts won't get a refund, will have to think about whether this Med (submitted as such), or Low (self-inflicted)
#1 - c4-judge
2022-12-11T20:38:52Z
GalloDaSballo marked the issue as primary issue
#2 - PierrickGT
2022-12-14T02:40:57Z
Fixed in this PR: https://github.com/code-423n4/2022-12-pooltogether-findings/issues/63
The processCalls
function was intended to be called by an EOA only but it's true that a contract may want to call it while providing the required _gasLimit
, _maxSubmissionCost
and _gasPriceBid
by an EOA.
Passing a refundAddress
variable will allow a contract to refund the EOA that called it.
Regarding the severity, I think 2 (Med Risk) is appropriate since the contract would leak value.
#3 - c4-sponsor
2022-12-14T02:41:03Z
PierrickGT marked the issue as sponsor confirmed
#4 - GalloDaSballo
2022-12-26T18:05:47Z
Agree with finding, am conflicted on severity:
Will think about it further
#5 - GalloDaSballo
2022-12-26T18:07:53Z
More specifically, the fact that the system wants to allow refunds and has a bug that prevents that, which would qualify as Medium. (We care if you send more, we will send it back, but because of bug we cannot)
While the pre-condition, in case of a less sophisticated system, would most likely be Low (we don't care if you send more, don't send more)
#6 - GalloDaSballo
2022-12-26T23:36:17Z
The Warden has shown an incorrect implementation, which can cause excess fees to be lost.
While the loss of excess fees could be considered Low Severity (self-inflicted), the integration mistake is worth flagging and warrants the increased severity.
#7 - c4-judge
2022-12-26T23:42:51Z
GalloDaSballo marked the issue as selected for report