code-423n4 / 2021-09-wildcredit-findings

0 stars 0 forks source link

IndexPool.INIT_POOL_SUPPLY is too large, which may cause a significant amount of fund loos to the first liquidity provider #95

Closed code423n4 closed 3 years ago

code423n4 commented 3 years ago

Handle

WatchPug

Vulnerability details

https://github.com/sushiswap/trident/blob/6bd4c053b6213ffc612987eb565aa3813d5f0d13/contracts/pool/IndexPool.sol#L33

uint256 internal constant BASE = 10**18;
...
uint256 internal constant INIT_POOL_SUPPLY = BASE * 100;

https://github.com/sushiswap/trident/blob/6bd4c053b6213ffc612987eb565aa3813d5f0d13/contracts/pool/IndexPool.sol#L93-L105

/// @dev Mints LP tokens - should be called via the router after transferring `bento` tokens.
/// The router must ensure that sufficient LP tokens are minted by using the return value.
function mint(bytes calldata data) public override lock returns (uint256 liquidity) {
    (address recipient, uint256 toMint) = abi.decode(data, (address, uint256));

    uint120 ratio = uint120(_div(toMint, totalSupply));

    for (uint256 i = 0; i < tokens.length; i++) {
        address tokenIn = tokens[i];
        uint120 reserve = records[tokenIn].reserve;
        // @dev If token balance is '0', initialize with `ratio`.
        uint120 amountIn = reserve != 0 ? uint120(_mul(ratio, reserve)) : ratio;
        require(amountIn >= MIN_BALANCE, "MIN_BALANCE");
        // @dev Check Trident router has sent `amountIn` for skim into pool.
        unchecked {
            // @dev This is safe from overflow - only logged amounts handled.
            require(_balance(tokenIn) >= amountIn + reserve, "NOT_RECEIVED");
            records[tokenIn].reserve += amountIn;
        }
        emit Mint(msg.sender, tokenIn, amountIn, recipient);
    }
    _mint(recipient, toMint);
    liquidity = toMint;
}

Proof of Concept

Given:

  1. Alice try to mint 100e18 of liquidity;
  2. Alice transfers 1e18 WBTC and 1e18 pBTC;
  3. Alice gets 100e18 of liquidity, worth 1 BTC.

Impact

A significant portion (50% in the case above) of the user's funds cannot be retrieved.

Recommendation

Always mint IndexPool.INIT_POOL_SUPPLY of liquidity to the first liquidity provider and takes just the MIN_BALANCE of each token.

This makes the first liquidity provider always gets a 50% share of the pool while paying MIN_BALANCE of each token.

itsmetechjay commented 3 years ago

Withdrawn by warden. Per WatchPug: "I mistakenly submitted some issues of sushi to wild credit while having two tabs open at the same time."