编译器
0.8.21+commit.d9974bed
文件 1 的 8:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 8:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 3 的 8:Owned.sol
pragma solidity >=0.8.0;
abstract contract Owned {
event OwnershipTransferred(address indexed user, address indexed newOwner);
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
constructor(address _owner) {
owner = _owner;
emit OwnershipTransferred(address(0), _owner);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
文件 4 的 8:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 5 的 8:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 6 的 8:iVaultT1.sol
pragma solidity 0.8.21;
interface IFluidVaultT1 {
function VAULT_ID() external view returns (uint256);
function readFromStorage(bytes32 slot_) external view returns (uint256 result_);
struct ConstantViews {
address liquidity;
address factory;
address adminImplementation;
address secondaryImplementation;
address supplyToken;
address borrowToken;
uint8 supplyDecimals;
uint8 borrowDecimals;
uint vaultId;
bytes32 liquiditySupplyExchangePriceSlot;
bytes32 liquidityBorrowExchangePriceSlot;
bytes32 liquidityUserSupplySlot;
bytes32 liquidityUserBorrowSlot;
}
function constantsView() external view returns (ConstantViews memory constantsView_);
function fetchLatestPosition(
int256 positionTick_,
uint256 positionTickId_,
uint256 positionRawDebt_,
uint256 tickData_
)
external
view
returns (
int256,
uint256,
uint256,
uint256,
uint256
);
function updateExchangePrices(
uint256 vaultVariables2_
)
external
view
returns (
uint256 liqSupplyExPrice_,
uint256 liqBorrowExPrice_,
uint256 vaultSupplyExPrice_,
uint256 vaultBorrowExPrice_
);
function updateExchangePricesOnStorage()
external
returns (
uint256 liqSupplyExPrice_,
uint256 liqBorrowExPrice_,
uint256 vaultSupplyExPrice_,
uint256 vaultBorrowExPrice_
);
function LIQUIDITY() external view returns (address);
function operate(
uint256 nftId_,
int256 newCol_,
int256 newDebt_,
address to_
)
external
payable
returns (
uint256,
int256,
int256
);
function liquidate(
uint256 debtAmt_,
uint256 colPerUnitDebt_,
address to_,
bool absorb_
) external payable returns (uint actualDebtAmt_, uint actualColAmt_);
function absorb() external;
function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);
error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);
}
文件 7 的 8:iWETH9.sol
pragma solidity 0.8.21;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}
文件 8 的 8:main.sol
pragma solidity 0.8.21;
import { Owned } from "solmate/src/auth/Owned.sol";
import { IFluidVaultT1 } from "../../protocols/vault/interfaces/iVaultT1.sol";
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IWETH9 } from "../../protocols/lending/interfaces/external/iWETH9.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
interface InstaFlashInterface {
function flashLoan(address[] memory tokens, uint256[] memory amts, uint route, bytes memory data, bytes memory extraData) external;
}
interface InstaFlashReceiverInterface {
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata _data
) external returns (bool);
}
contract VaultT1Liquidator is Owned {
using SafeERC20 for IERC20;
address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
InstaFlashInterface immutable public FLA;
IWETH9 immutable public WETH;
mapping (address => bool) public rebalancer;
error FluidVaultT1Liquidator__InvalidOperation();
event Liquidated(
address indexed vault,
uint256 collateral,
uint256 debt
);
event Withdraw(
address indexed to,
address indexed token,
uint256 amount
);
event ToggleRebalancer(
address indexed rebalancer,
bool indexed status
);
struct LiquidationParams {
address vault;
address supply;
address borrow;
uint256 supplyAmount;
uint256 borrowAmount;
uint256 colPerUnitDebt;
bool absorb;
address swapRouter;
address swapApproval;
bytes swapData;
uint256 route;
}
constructor (
address owner_,
address fla_,
address weth_,
address[] memory rebalancers_
) Owned(owner_) {
FLA = InstaFlashInterface(fla_);
WETH = IWETH9(weth_);
for (uint256 i = 0; i < rebalancers_.length; i++) {
rebalancer[rebalancers_[i]] = true;
emit ToggleRebalancer(rebalancers_[i], true);
}
}
modifier isRebalancer() {
if (!rebalancer[msg.sender] && msg.sender != owner) {
revert FluidVaultT1Liquidator__InvalidOperation();
}
_;
}
function toggleRebalancer(address rebalancer_, bool status_) public onlyOwner {
rebalancer[rebalancer_] = status_;
emit ToggleRebalancer(rebalancer_, status_);
}
function spell(address[] memory targets_, bytes[] memory calldatas_) public onlyOwner {
for (uint256 i = 0; i < targets_.length; i++) {
Address.functionDelegateCall(targets_[i], calldatas_[i]);
}
}
function withdraw(address to_, address[] memory tokens_, uint256[] memory amounts_) public onlyOwner {
for (uint i = 0; i < tokens_.length; i++) {
if (tokens_[i] == ETH_ADDRESS) {
Address.sendValue(payable(to_), amounts_[i]);
} else {
IERC20(tokens_[i]).safeTransfer(to_, amounts_[i]);
}
emit Withdraw(to_, tokens_[i], amounts_[i]);
}
}
function liquidation(LiquidationParams memory params_) public isRebalancer {
address[] memory tokens = new address[](1);
uint256[] memory amts = new uint256[](1);
tokens[0] = params_.borrow == ETH_ADDRESS ? address(WETH) : params_.borrow;
amts[0] = params_.borrowAmount;
bytes memory data_ = abi.encode(params_);
FLA.flashLoan(tokens, amts, params_.route, data_, abi.encode());
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata _data
) external returns (bool) {
if (msg.sender != address(FLA)) revert FluidVaultT1Liquidator__InvalidOperation();
if (initiator != address(this)) revert FluidVaultT1Liquidator__InvalidOperation();
LiquidationParams memory params_ = abi.decode(_data, (LiquidationParams));
{
uint256 value_;
if (params_.borrow != ETH_ADDRESS) {
IERC20(params_.borrow).safeApprove(params_.vault, 0);
IERC20(params_.borrow).safeApprove(params_.vault, params_.borrowAmount);
value_ = 0;
} else {
WETH.withdraw(params_.borrowAmount);
value_ = params_.borrowAmount;
}
(uint256 debtAmount_, uint256 collateralAmount_) = IFluidVaultT1(params_.vault).liquidate{value: value_}(params_.borrowAmount, params_.colPerUnitDebt, address(this), params_.absorb);
if (params_.supply != ETH_ADDRESS) {
IERC20(params_.supply).safeApprove(params_.swapApproval, 0);
IERC20(params_.supply).safeApprove(params_.swapApproval, params_.supplyAmount);
value_ = 0;
} else {
value_ = params_.supplyAmount;
}
Address.functionCallWithValue(params_.swapRouter, params_.swapData, value_, "Swap: failed");
emit Liquidated(params_.vault, collateralAmount_, debtAmount_);
}
uint256 flashloanAmount_ = amounts[0] + premiums[0] + 10;
if (params_.borrow == ETH_ADDRESS) {
uint256 wethBalance_ = WETH.balanceOf(address(this));
if (wethBalance_ < flashloanAmount_) {
WETH.deposit{value: flashloanAmount_ - wethBalance_}();
}
}
IERC20(assets[0]).safeTransfer(msg.sender, flashloanAmount_);
return true;
}
receive() payable external {}
}
{
"compilationTarget": {
"contracts/periphery/liquidation/main.sol": "VaultT1Liquidator"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 10000000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"fla_","type":"address"},{"internalType":"address","name":"weth_","type":"address"},{"internalType":"address[]","name":"rebalancers_","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FluidVaultT1Liquidator__InvalidOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rebalancer","type":"address"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"}],"name":"ToggleRebalancer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLA","outputs":[{"internalType":"contract InstaFlashInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH9","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"premiums","type":"uint256[]"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"internalType":"uint256","name":"supplyAmount","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"colPerUnitDebt","type":"uint256"},{"internalType":"bool","name":"absorb","type":"bool"},{"internalType":"address","name":"swapRouter","type":"address"},{"internalType":"address","name":"swapApproval","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"uint256","name":"route","type":"uint256"}],"internalType":"struct VaultT1Liquidator.LiquidationParams","name":"params_","type":"tuple"}],"name":"liquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rebalancer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets_","type":"address[]"},{"internalType":"bytes[]","name":"calldatas_","type":"bytes[]"}],"name":"spell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rebalancer_","type":"address"},{"internalType":"bool","name":"status_","type":"bool"}],"name":"toggleRebalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"address[]","name":"tokens_","type":"address[]"},{"internalType":"uint256[]","name":"amounts_","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]