PoolTogether contest - Chom'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: 7/19

Findings: 1

Award: $1,309.61

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Chom, enckrish, joestakey

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-63

Awards

1309.6144 USDC - $1,309.61

External Links

Lines of code

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

Vulnerability details

Impact

If a contract calls CrossChainRelayerArbitrum.processCalls, the entire msg.value is never refunded on the destination chain. ETH refunded on the destination chain will be blackholed.

Proof of Concept

createRetryableTicket(address destAddr, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 maxGas, uint256 gasPriceBid, bytes data) → uint256
    uint256 _ticketID = inbox.createRetryableTicket{ value: msg.value }(
      address(executor),
      0,
      _maxSubmissionCost,
      msg.sender,
      msg.sender,
      _gasLimit,
      _gasPriceBid,
      _data
    );

CrossChainRelayerArbitrum.processCalls calls the standard Arbitrum Inbox's createRetryableTicket function with msg.value sent from the caller and msg.sender as the excessFeeRefundAddress and callValueRefundAddress. Assume this function is called by a contract at address 0xabcd on the ETH chain, but there isn't exists a contract at address 0xabcd on the Optimism chain. So, the refunded ETH will be blackholed (Nobody can redeem that ETH).

Add a refundAddress parameter to the CrossChainRelayerArbitrum.processCalls function and pass it as the excessFeeRefundAddress and callValueRefundAddress on createRetryableTicket.

    uint256 _ticketID = inbox.createRetryableTicket{ value: msg.value }(
      address(executor),
      0,
      _maxSubmissionCost,
      refundAddress,
      refundAddress,
      _gasLimit,
      _gasPriceBid,
      _data
    );

#0 - c4-judge

2022-12-11T20:39:31Z

GalloDaSballo marked the issue as duplicate of #63

#1 - c4-judge

2022-12-26T23:40:43Z

#2 - GalloDaSballo

2022-12-26T23:53:55Z

Incorrectly Downgraded, this is a dup of #63 as it mentions the risk of not controlling the account on L2

#3 - Simon-Busch

2022-12-28T10:37:02Z

Changed back severity as requested by @GalloDaSballo

#4 - c4-judge

2022-12-28T22:01:41Z

GalloDaSballo marked the issue as not a duplicate

#5 - c4-judge

2022-12-28T22:01:47Z

GalloDaSballo marked the issue as not a duplicate

#6 - c4-judge

2022-12-28T22:01:57Z

GalloDaSballo marked the issue as duplicate of #63

#7 - c4-judge

2023-01-06T11:55:11Z

GalloDaSballo marked the issue as satisfactory

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