Yearn Finance Exploit Analysis

Peckshield has released an analysis. This is an exploit that took advantage of a contract that relies on the business logic of an external contract.

In order to understand how the exploit works it’s helpful to first understand how Curve pools work. Curve pools are optimized for the exchange of like kind assets such as stablecoins and bases it’s bonding curve on the assumption that over the long term these assets have a one to one exchange rate.

In order to incentivize having a balance of assets in the pool it implements deposit and withdrawal bonuses/penalties. When there is a disproportionately small amount of a given token in the pool a deposit bonus is given, conversely a penalty is applied when a token has a larger share of the pool. The reverse is applied for withdrawals where a penalty is applied for withdrawing scarce tokens and a bonus is applied for abundant tokens.

The yDAI vault makes deposits and withdrawals into the Curve 3pool as part of it’s core strategy. In the block prior to the first transaction (11792210) the 3pool liquidity balances were:

  • DAI: 207,211,018
  • USDC: 227,758,811
  • USDT: 194,173,881

Upon initiating the transaction the exploit contract, through a series a flash loans and swaps acquired 38,219,752 DAI and133,000,000 USDC which they swapped through 3pool for 167,159,608 USDT bringing the new pool balances to:

  • DAI: 245,430,770
  • USDC: 360,758,811
  • USDT: 27,014,273

At this point the pool is heavily skewed which creates high slippage for DAI and USDC depositors and high rewards for USDT depositors and DAI and USDC withdrawers.

The exploiting contract then deposits 105,469,871 DAI into the yDAI vault. Upon triggering earn on the yDAI vault, the yDAI vault deposited 104,436,479 DAI in to 3pool which now made the skew significantly more extreme. With such an extreme skew the tails of the rewards curve are now utilized which are convex compared to when the pool is more balanced.

At this point the exploiting contract deposits back into the 3pool the USDT for 169,468,555 3pool shares and redeems it’s yDAI shares, which triggers a DAI withdrawal from 3pool where the exploiting contract receives 104,700,650 in DAI which is 769,221 less DAI than it deposited. The exploiting contract then redeems 168,604,719 3pool shares for it’s original deposit of 167,159,608 USDT and profit of 863,836 3pool shares. Considering the shares tend towards $1 in value over time the net profit on this turn for the exploiting contract was ~$94,000.

The contract call then loops through the above process a few more times then repaying the flash loans before hitting the gas limit and sending the final profits of 316,814 3crv and 11,833 USDT to the contract caller. As the limiting factor in the loops is the gas limit the attacker than initiated several more calls to the exploiting contract bringing the final amount of funds received by the exploiting sender to 506,314 3crv, 1,747,728 USDT and 513,356 DAI.

This attack shows the importance of understanding how dependent contracts function. It seems the Yearn team did have such an understanding as they implemented a withdrawal fee of 0.5% in the yDAI vault which would have rendered this attack unprofitable in most scenarios but they recently disabled the fee to encourage migration to new vaults. The vault also had slippage protection in place of 1% but at large enough sums and with enough rotations through a strategy it proved to be to too wide to deter such an attack. Another interesting point is that anyone could call the earn function which triggers a deployment of the vault funds and the attacker took advantage of that. In V2 vaults they utilize a network of keepers which are whitelisted agents that monitor the chain and trigger actions as needed. Finally it seems important to consider window of opportunity attacks, loosing parameters to facilitate temporary onchain events can create attack vectors that don’t exist under normal circumstances.

7 Likes