Heartbreaks & Curve LP Oracles

Tripping over the Curve

Such a nice view!!!

# snippet from remove_liquidity
CurveToken(lp_token).burnFrom(msg.sender, _amount)
for i in range(N_COINS):
    value: uint256 = amounts[i] * _amount / total_supply
    if i == 0:
        raw_call(msg.sender, b"", value=value)
    else:
    assert ERC20(self.coins[1]).transfer(msg.sender, value)

 

def _balances(_value: uint256 = 0) -> uint256[N_COINS]:
    return [
        self.balance - self.admin_balances[0] - _value,
        ERC20(self.coins[1]).balanceOf(self) - self.admin_balances[1]
    ]def get_virtual_price() -> uint256:
    """
    @notice The current virtual price of the pool LP token
    @dev Useful for calculating profits
    @return LP token virtual price normalized to 1e18
    """
    D: uint256 = self.get_D(self._balances(), self._A())
    # D is in the units similar to DAI (e.g. converted to precision 1e18)
    # When balanced, D = n * x_u - total virtual value of the portfolio
    token_supply: uint256 = ERC20(self.lp_token).totalSupply()
    return D * PRECISION / token_supply

 

  1. Add a massive amount of liquidity.
  2. Remove it. The raw ETH transfer triggers the fallback function.
  3. During the execution of the fallback function, the virtual price is completely off as much more capital available compared to the LP token supply.

Blinded by the beauty of the pump

  • ETH pools: Only upwards manipulation is possible.
  • Pools holding ERC-677 that perform token callbacks after transfers: Equivalent to ETH pools
  • Pools holding ERC-777: Equivalent to ETH pools but it was possible to devaluate LP tokens when adding liquidity during the ERC-777 sender’s callback function.
  • MakerDAO: ~5M at risk
  • Enzyme: < 1M at risk
  • Abracadabra: ~100M at risk
  • TribeDAO (Rari): ~20M at risk
  • Opyn: ~6M at risk
  1. Write a generic report describing the vulnerability.
  2. Contact our friends at Curve to help identify further protocols. Send them the report.
  3. Send out a generic report to all affected protocols. For some we decided to use private channels. For some we used Immunefi as a trusted platform to report.
  4. Contact our friends at Paradigm to ask for their “U up?” as support to get in touch with the relevant people.

Or to describe it in the words of Mitchell Kuzzel, CEO of Immunefi:

“It’s hard to appreciate just how difficult ChainSecurity’s task was; having proven the vulnerability of the Oracle, it was clear that serious funds were at risk. ChainSecurity decided to go the distance and make disclosures across all affected protocols simultaneously, to maximize the chance of protecting them all (the best practice in such cases).
For our part, that meant several critical bug reports and a flurry of activity to start pushing mitigations immediately, a process which we at Immunefi supported as much as we could.
Each of these protocols owes them a major debt of gratitude for saving them all from a serious vulnerability, and under the most demanding of circumstances.”

Fast forward to the present