Juicebox Buyback Delegate - T1MOH's results

Thousands of projects use Juicebox to fund, operate, and scale their ideas & communities transparently on Ethereum.

General Information

Platform: Code4rena

Start Date: 18/05/2023

Pot Size: $24,500 USDC

Total HM: 3

Participants: 72

Period: 4 days

Judge: LSDan

Id: 237

League: ETH

Juicebox

Findings Distribution

Researcher Performance

Rank: 16/72

Findings: 1

Award: $321.72

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: minhquanym

Also found by: 0xStalin, BLACK-PANDA-REACH, Madalad, T1MOH, Udsen, adriro, max10afternoon, rbserver, sces60107

Labels

bug
2 (Med Risk)
judge review requested
satisfactory
duplicate-162

Awards

321.7244 USDC - $321.72

External Links

Lines of code

https://github.com/code-423n4/2023-05-juicebox/blob/main/juice-buyback/contracts/JBXBuybackDelegate.sol#L216-L233

Vulnerability details

Impact

didPay() function is payable and receives ETH. Then during uniswapV3Callback deposits ETH into WETH and sends it into UniswapV3Pool for projectToken. But excess ETH is not returned to caller of JBXBuybackDelegate and can be used by other users.

Proof of Concept

didPay() is payable:

    function didPay(JBDidPayData calldata _data) external payable override {

Excess is not returned:

    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override {
        // Check if this is really a callback
        if (msg.sender != address(pool)) revert JuiceBuyback_Unauthorized();

        // Unpack the data
        (uint256 _minimumAmountReceived) = abi.decode(data, (uint256));

        // Assign 0 and 1 accordingly
        uint256 _amountReceived = uint256(-(_projectTokenIsZero ? amount0Delta : amount1Delta));
        uint256 _amountToSend = uint256(_projectTokenIsZero ? amount1Delta : amount0Delta);

        // Revert if slippage is too high
        if (_amountReceived < _minimumAmountReceived) revert JuiceBuyback_MaximumSlippage();

        // Wrap and transfer the weth to the pool
        weth.deposit{value: _amountToSend}();
        weth.transfer(address(pool), _amountToSend);
    }

Tools Used

Manual Review

Add argument excess receiver to data argument passed to pool.swap(). And send excess:

    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override {
        // Unpack the data
        (uint256 _minimumAmountReceived, address excessReceiver) = abi.decode(data, (uint256, address));
        ...

        // Wrap and transfer the weth to the pool
        weth.deposit{value: _amountToSend}();
        weth.transfer(address(pool), _amountToSend);

        // SOLUTION
        payable(excessReceiver).call{value: address(this).balance}("");
    }

It may require to refactor logic of terminal contract interacting with JBXBuybackDelegate

Assessed type

ETH-Transfer

#0 - c4-pre-sort

2023-05-24T16:11:11Z

dmvt marked the issue as primary issue

#1 - drgorillamd

2023-05-30T15:01:02Z

this might be valid but really not sure -> the quote comes from frontend by actually staticcalling the quoter (ie as Uni v3 SDK is doing), then the price used is max or min tick (accordingly) -> iic, this means it's unbounded and all the eth are used anyway (and users are protected by passing the quote which takes it into account, "X eth returns Y token" with y being what's left), ie no "partial fill"

  • if I'm wrong, in what kind of exceptional circumstances this would happen? Wouldn't one need to be on the edge of the pool liquidity profile (on the cheap side of the project token), while still having a weight worse than that?

#2 - c4-sponsor

2023-06-01T07:11:31Z

drgorillamd requested judge review

#3 - c4-judge

2023-06-02T14:42:52Z

dmvt marked issue #162 as primary and marked this issue as a duplicate of 162

#4 - dmvt

2023-06-02T14:45:11Z

There are several scenarios where this can occur, one of which is talked about in #162.

#5 - c4-judge

2023-06-02T14:45:23Z

dmvt 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