Saddle Finance is an automated market maker (AMM) on Ethereum. In particular, they specialize in stable swaps and aim to reduce the slippage of users. The bulk of the code is based on Curve but has been widely re-implemented.
There are two types of pools: Standard and Meta. The standard pool is an AMM pool where the tokens provided for liquidity are swapped via the pool. In the meta tool, a pegged token and another token represent the liquidity in the standard pool. Meta allow liquidity in one pool to be used in additional pools.
When trying to figure out the fees for a given Liquidity Provider (LP) token, there is a mispricing. The LP token's virtual price grows and grows as more fees are taken. However, the swap function does not account for this virtual price. The base virtual price calculation was simply NOT applied to the contract.
Interestingly enough, forks of Saddle (Nerve and Synapse) were exploited for a similar issue. Patches were made to the forks and Saddle itself but they missed the patch on the swap calculation.
At a high level, we need make a very large swap for the LP token with the missing price calculation. How this is precisely done:
- Obtain USDC funds via a flash loan.
- Swap USDC for sUSD.
- Swap the sUSD into the Saddle pool in order to get the LP token via the Meta pool.
- Swap the LP token for sUSD via the Meta pool. Doing this over and over again allows for us to obtain a lot more sUSD because of the LP token mispricing.
- Swap sUSD for USDC.
In the real world attack, the attacker swaps the sUSD and LP several times to remove all of the liquidity from the Meta pool. The article demonstrates a proof of concept of the exploit as well, which is pretty cool to look at!
Two takeaways for me. First, financial calculation mistakes are easy to make, hard to trace and costly- they are not obvious patterns to follow for auditors. Secondly, where there are bugs, there are likely more bugs! In this case, they patched the bulk of the functionality but missed a single location. Unfortunately, this was all the attacker needed.