PoolTogether contest - cccz's results

A no-loss prize-savings protocol.

General Information

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

PoolTogether

Findings Distribution

Researcher Performance

Rank: 5/19

Findings: 1

Award: $1,702.50

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Chom, enckrish, joestakey

Labels

bug
2 (Med Risk)
primary issue
selected for report
sponsor confirmed
M-02

Awards

1702.4987 USDC - $1,702.50

External Links

Lines of code

https://github.com/pooltogether/ERC5164/blob/5647bd84f2a6d1a37f41394874d567e45a97bf48/src/ethereum-arbitrum/EthereumToArbitrumRelayer.sol#L118-L127

Vulnerability details

Impact

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.

Proof of Concept

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

Tools Used

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:

  • Low -> User sends more than necessary
  • Med -> Behaviour, is inconsistent to expected / intended functionality

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter