Platform: Code4rena
Start Date: 23/02/2024
Pot Size: $92,000 USDC
Total HM: 0
Participants: 47
Period: 10 days
Judge: 0xTheC0der
Id: 336
League: ETH
Rank: 10/47
Findings: 1
Award: $5,987.35
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: CodeWasp
Also found by: 0xdice91, 0xlemon, Aamir, Al-Qa-qa, AlexCzm, BAHOZ, Bauchibred, Breeje, DadeKuma, Fassi_Security, PetarTolev, Shield, SpicyMeatball, Trust, ZanyBonzy, cheatc0d3, gesha17, haxatron, imare, jesjupyter, kutugu, lsaudit, marchev, merlinboii, nnez, osmanozdemir1, peanuts, radev_sw, twicek, visualbits
5987.3522 USDC - $5,987.35
https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/V3FactoryOwner.sol#L181
The user who attempts to buy protocol fees in V3FactoryOwner.sol
may lose his funds in a bad deal if claimFees
transaction is executed later in time.
Users can pay a fixed amount of tokens to purchase protocol fees accumulated in the pool.
function claimFees( IUniswapV3PoolOwnerActions _pool, address _recipient, uint128 _amount0Requested, uint128 _amount1Requested ) external returns (uint128, uint128) { PAYOUT_TOKEN.safeTransferFrom(msg.sender, address(REWARD_RECEIVER), payoutAmount); REWARD_RECEIVER.notifyRewardAmount(payoutAmount); (uint128 _amount0, uint128 _amount1) = _pool.collectProtocol(_recipient, _amount0Requested, _amount1Requested); // Protect the caller from receiving less than requested. See `collectProtocol` for context. if (_amount0 < _amount0Requested || _amount1 < _amount1Requested) { revert V3FactoryOwner__InsufficientFeesCollected(); } emit FeesClaimed(address(_pool), msg.sender, _recipient, _amount0, _amount1); return (_amount0, _amount1); }
For this deal to be profitable PAYOUT_AMOUNT
should be less than received fees value. Let's take example from the comment below
https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/V3FactoryOwner.sol#L157-L166
USDC/USDT pool has accumulated fees which value is 26K USD, Alice calls claimFees(usdc_usdt, alice, 13000 ether, 13000 ether)
in order to receive 13K USDT and 13K USDC tokens in exchange for PAYOUT_AMOUNT
of 10 WETH that is 10 * 2500 = $25K
, the profit is 26K - 25K = $1000
.
Now imagine that her transaction was executed with a significant time delay due to network conditions or a low gas amount, and WETH/USD price increased to 2700, this would result in a loss of funds as Alice receives 26K in USDC and USDT tokens in exchange for 10 * 2700 = $27K
.
Manual review
Add the deadline check in claimFees
Timing
#0 - MarioPoneder
2024-03-06T19:11:49Z
Deadline consideration seems to be valid cause only minimum token amounts are enforced but not their actual price value which might change over time.
On the contrary, the user has the ability to revoke the approval.
#1 - c4-judge
2024-03-06T19:12:49Z
MarioPoneder marked the issue as primary issue
#2 - c4-sponsor
2024-03-11T14:26:13Z
apbendi (sponsor) disputed
#3 - apbendi
2024-03-11T14:27:22Z
The scenario described is both highly unlikely (the transaction would not remain in the pool long enough for price changes to matter, someone else would arb it) and completely within the searchers control to mitigate (they can wrap their claims in any contract logic they prefer). This is simply a property of MEV, we do not consider it an issue.
#4 - c4-judge
2024-03-14T01:53:33Z
MarioPoneder marked the issue as satisfactory
#5 - c4-judge
2024-03-14T01:55:37Z
MarioPoneder marked issue #331 as primary and marked this issue as a duplicate of 331
#6 - MarioPoneder
2024-03-14T03:16:16Z
Deadline checks as well as slippage checks can be considered state-of-the art and a protocol bears a responsibility to introduce such measures in order to protect its users. Furthermore, the pending transaction doesn't necessarily need to fail even when frontrun by someone else and could still lead to losses (better explained in #331).
However, also the user / MEV searcher bears a responsibility to care about their transactions as they can be cancelled easily. Having a pending transaction in the mempool for e.g. a day (see also PoC of #331) must be considered a careless user error.
See also: https://docs.code4rena.com/awarding/judging-criteria/supreme-court-decisions-fall-2023#verdict-severity-standardization-conditional-on-user-mistake
#7 - c4-judge
2024-03-14T03:16:28Z
MarioPoneder removed the grade
#8 - c4-judge
2024-03-14T03:16:42Z
MarioPoneder changed the severity to QA (Quality Assurance)
#9 - c4-judge
2024-03-14T13:28:59Z
MarioPoneder marked the issue as grade-b
#10 - c4-judge
2024-03-17T13:43:11Z
This previously downgraded issue has been upgraded by MarioPoneder
#11 - c4-judge
2024-03-17T13:43:41Z
MarioPoneder marked the issue as satisfactory
#12 - c4-judge
2024-03-26T22:42:21Z
MarioPoneder marked the issue as grade-a