Write-up for PairAssetManager
Overview
This challenge questions your understanding of Uniswap v2. By solving this puzzle, you will learn about the operational logic of Uniswap v2's factory and constant product market maker (CPMM).
Solving the puzzle
The puzzle's goal is to drain both curtaUSD and curtaStUSD from keeper, which is responsible for pricing the pair. The puzzle contains the following vulnerabilities you can exploit to drain the tokens:
- In
onlyUniswapV2Pair, verification withcodeHashcan be bypassed by deployingUniswapV2Pairdirectly. - In
uniswapV2Call, ifamountInis greater thanmaxAmountIn, it may not revert. - In
uniswapV2Call, the token address passed asdatamay not be the same as the token of the called pair. - [Optional] If a token different from the initial token specified by
_createUserin_depositis deposited, the share of the initial tokens pair will be increased.
In addition to the minimum requirement, vulnerability #4 enables stealing 1 ether - MINIMUM_LIQUIDITY additional curtaUSD and curtaStUSD from owner.
We can exploit these vulnerabilities as follows:
- Create a fake token and directly deploy
UniswapV2Pair(i.e. without the factory). mintandsyncthe fake tokens with the fake pair and scale them so thatPairAssetManager._getAmountInof one token results in a large value.- Call
initializeto change the tokens tocurtaUSDandcurtaStUSD. In the usual case where the pair is deployed through Uniswap's factory,initializecan only be called once to create the pair, but since we deployed it directly, we can callinitializemultiple times. - Call
swapon theUniswapV2Pairwe deployed, and specifytoasPairAssetManageranddataas the token addresses to steal + the number of tokenskeeperhas. We can drain the tokens with the large value returned by_getAmountInfromkeeper. burnall the fake tokens held by the fake pair and callsyncto set the reserve to zero.- Call
initializeto replace the token with the fake token again, andmintandsyncthe other token so that itsPairAssetManager._getAmountInincreases. - Repeat steps 4 and 5, and drain all tokens via
skim.
Solve script
Check out our solve test below for more details.