编译器
0.8.17+commit.8df45f5f
文件 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:errors.sol
pragma solidity 0.8.17;
contract Errors {
error OwnerContract__AlreadyInitialized();
error Helpers__NotOwner();
error Helpers__NotRebalancer();
error Helpers__InvalidParams();
error Helpers__Reentrant();
error WeethStrategyContract__MaxLeveraged();
error WeethStrategyContract__SupplyCapReached();
error WeethStrategyContract__NoBorrowingAvailability();
error WeethStrategyContract__PosExceededRatio();
error WeethStrategyContract__MinAvailabilityNotReached();
error WeethStrategyContract__MinLimitNotReached();
}
文件 4 的 8:events.sol
pragma solidity 0.8.17;
contract Events {
event LogSetOwner(address owner);
event LogUpdateOwner(address oldOwner, address newOwner);
event LogSetVaultDSA(address vaultDSA);
event LogDSASpell(
address indexed to,
bytes data,
uint256 value,
uint256 operation
);
event LogAddDSAAuthority(address indexed newAuthority);
event LogUpdateRebalancer(
address indexed rebalancer,
bool indexed isRebalancer
);
event LogUpdateMaxRatio(
uint256 indexed maxPosRatioBefore,
uint256 indexed maxPosRatioAfter
);
event LogLeverage(
uint256 indexed wETHCollAmount,
uint256 indexed wETHBorrowAmount,
uint256 indexed currentPosRatio
);
}
文件 5 的 8:helpers.sol
pragma solidity 0.8.17;
import {Errors} from "./errors.sol";
import {Events} from "./events.sol";
import {Variables} from "./variables.sol";
import "./interfaces.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract Helpers is Errors, Events, Variables {
modifier onlyRebalancer() {
if (!(isRebalancer[msg.sender] || owner == msg.sender)) {
revert Helpers__NotRebalancer();
}
_;
}
modifier onlyOwner() {
if (owner != msg.sender) {
revert Helpers__NotOwner();
}
_;
}
modifier nonReentrant() {
if (_status == 2) revert Helpers__Reentrant();
_status = 2;
_;
_status = 1;
}
function spell(
address to_,
bytes memory calldata_,
uint256 value_,
uint256 operation_
) external payable onlyOwner {
if (operation_ == 0) {
Address.functionCallWithValue(
to_,
calldata_,
value_,
"spell: .call failed"
);
} else if (operation_ == 1) {
Address.functionDelegateCall(
to_,
calldata_,
"spell: .delegateCall failed"
);
} else {
revert("no operation");
}
emit LogDSASpell(to_, calldata_, value_, operation_);
}
function addDSAAuth(address auth_) external onlyOwner {
string[] memory targets_ = new string[](1);
bytes[] memory calldata_ = new bytes[](1);
targets_[0] = "AUTHORITY-A";
calldata_[0] = abi.encodeWithSignature("add(address)", auth_);
vaultDSA.cast(targets_, calldata_, address(this));
emit LogAddDSAAuthority(auth_);
}
function getPositionRatio()
public
view
returns (
uint256 weETHAmount_,
uint256 eETHAmount_,
uint256 wethAmount_,
uint256 ratio_
)
{
weETHAmount_ = IERC20(A_WEETH_ADDRESS).balanceOf(address(vaultDSA));
eETHAmount_ = IWEETH(WEETH_ADDRESS).getEETHByWeETH(weETHAmount_);
wethAmount_ = IERC20(D_WETH_ADDRESS).balanceOf(address(vaultDSA));
ratio_ = eETHAmount_ == 0 ? 0 : (wethAmount_ * 1e6) / eETHAmount_;
}
function wethReserveData()
public
view
returns (uint256 availableLiquidity_)
{
(
,
,
uint256 totalATokens_,
uint256 totalStableDebt_,
uint256 totalVariableDebt_,
,
,
,
,
,
,
) = AAVE_V3_DATA_PROVIDER.getReserveData(WETH_ADDRESS);
availableLiquidity_ =
totalATokens_ -
totalStableDebt_ -
totalVariableDebt_;
}
function getWeETHData()
public
view
returns (uint256 weETHSupplyCap_, uint256 weETHSupplied_)
{
(, uint256 weETHSupplyCapTokens_) = AAVE_V3_DATA_PROVIDER
.getReserveCaps(WEETH_ADDRESS);
weETHSupplyCap_ = weETHSupplyCapTokens_ * 1e18;
weETHSupplied_ = IERC20(A_WEETH_ADDRESS).totalSupply();
}
}
文件 6 的 8:interfaces.sol
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IInstaIndex {
function build(
address owner_,
uint256 accountVersion_,
address origin_
) external returns (address account_);
}
interface IDSA {
function cast(
string[] calldata _targetNames,
bytes[] calldata _datas,
address _origin
) external payable returns (bytes32);
}
interface IProxy {
function owner() external view returns (address);
}
interface IWEETH {
function getEETHByWeETH(
uint256 _weETHAmount
) external view returns (uint256);
}
interface IAaveV3ProtocolDataProvider {
function getReserveConfigurationData(
address asset
)
external
view
returns (
uint256 decimals,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
uint256 reserveFactor,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive,
bool isFrozen
);
function getReserveData(
address asset
)
external
view
returns (
uint256 unbacked,
uint256 accruedToTreasuryScaled,
uint256 totalAToken,
uint256 totalStableDebt,
uint256 totalVariableDebt,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
);
function getReserveCaps(
address asset
) external view returns (uint256 borrowCap, uint256 supplyCap);
}
interface IAaveV3Governance {
function executeProposal(uint256 proposalId) external;
}
interface IAaveV3PayloadsController {
function executePayload(uint40 payloadId) external payable;
}
文件 7 的 8:main.sol
pragma solidity 0.8.17;
import {Helpers} from "./helpers.sol";
import "./interfaces.sol";
contract OwnerContract is Helpers {
function setOwner(address owner_) public {
if (_status != 0) {
revert OwnerContract__AlreadyInitialized();
}
owner = owner_;
_status = 1;
emit LogSetOwner(owner_);
}
function updateOwner(address owner_) public onlyOwner {
address oldOwner_ = owner;
owner = owner_;
emit LogUpdateOwner(oldOwner_, owner_);
}
function setVaultDSA(address vaultDSA_) public onlyOwner {
vaultDSA = IDSA(vaultDSA_);
emit LogSetVaultDSA(vaultDSA_);
}
function updateRebalancer(
address rebalancer_,
bool isRebalancer_
) public onlyOwner {
isRebalancer[rebalancer_] = isRebalancer_;
emit LogUpdateRebalancer(rebalancer_, isRebalancer_);
}
function updateMaxPosRatio(uint256 maxPosRatio_) public onlyOwner {
uint256 oldRatio_ = maxPosRatio;
maxPosRatio = maxPosRatio_;
emit LogUpdateMaxRatio(oldRatio_, maxPosRatio_);
}
}
contract WeethStrategyContract is OwnerContract {
constructor() {
setOwner(0x3BD7c3DF5dcf67f3aA314500c683C82Dc65671d5);
vaultDSA = IDSA(0xf6EDCF5261112c06539412fB760c46173d3cdb12);
isRebalancer[0xad5A93B6A6baA3D9bf7a5E28d63d0E25c165bcAA] = true;
isRebalancer[0x10F37Ceb965B477bA09d23FF725E0a0f1cdb83a5] = true;
maxPosRatio = 928000;
}
struct LeverageHelper {
uint256 spellIndex;
uint256 spellsLength;
string[] targets;
bytes[] calldatas;
uint256 WEETHSupplyCap;
uint256 WEETHSupplyAave;
uint256 wethAvailableLiquidity;
uint256 wethDSABal;
uint256 leverageFactor;
}
function leverage() external onlyRebalancer nonReentrant {
LeverageHelper memory lev_;
(, uint256 posEETH_, uint256 posWeth_, uint256 currentRatio_) = getPositionRatio();
if (currentRatio_ >= maxPosRatio) {
revert WeethStrategyContract__MaxLeveraged();
}
(lev_.WEETHSupplyCap, lev_.WEETHSupplyAave) = getWeETHData();
lev_.wethAvailableLiquidity = wethReserveData();
uint256 WEETHSupplyAaveWithBuffer_ = lev_.WEETHSupplyAave + 1e18;
if (WEETHSupplyAaveWithBuffer_ > lev_.WEETHSupplyCap) {
revert WeethStrategyContract__SupplyCapReached();
}
uint256 supplyAvailableInWEETH_ = lev_.WEETHSupplyCap -
WEETHSupplyAaveWithBuffer_;
uint256 supplyAvailableInWeth_ = IWEETH(WEETH_ADDRESS).getEETHByWeETH(
supplyAvailableInWEETH_
);
if (supplyAvailableInWeth_ < MIN_LIMIT_AVAILABILITY) {
revert WeethStrategyContract__MinAvailabilityNotReached();
}
lev_.wethDSABal = IERC20(WETH_ADDRESS).balanceOf(address(vaultDSA));
lev_.leverageFactor = 1e6 / (1e6 - maxPosRatio);
uint256 wethFlashAmount_;
if(posWeth_ > 0) {
uint256 colCoveringDebt_ = ((posWeth_ * 1e6) / maxPosRatio);
uint256 colIdle_ = (posEETH_ - colCoveringDebt_) + lev_.wethDSABal;
uint256 newDebtBorrow_ = colIdle_ * (lev_.leverageFactor - 1);
wethFlashAmount_ =
supplyAvailableInWeth_ > newDebtBorrow_
? newDebtBorrow_
: supplyAvailableInWeth_;
} else {
uint256 wethFlashAmount1_ = supplyAvailableInWeth_ - lev_.wethDSABal;
uint256 wethFlashAmount2_ = (lev_.leverageFactor * lev_.wethDSABal) - lev_.wethDSABal;
wethFlashAmount_ = wethFlashAmount1_ < wethFlashAmount2_
? wethFlashAmount1_
: wethFlashAmount2_;
}
if (wethFlashAmount_ < MIN_LEVERAGE) {
revert WeethStrategyContract__MinLimitNotReached();
}
if (lev_.wethAvailableLiquidity < wethFlashAmount_) {
revert WeethStrategyContract__NoBorrowingAvailability();
}
lev_.spellsLength = 5;
lev_.targets = new string[](lev_.spellsLength);
lev_.calldatas = new bytes[](lev_.spellsLength);
lev_.targets[lev_.spellIndex] = "EETH-A";
lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
"depositWeth(uint256,uint256,uint256)",
type(uint256).max,
0,
0
);
lev_.spellIndex++;
lev_.targets[lev_.spellIndex] = "WEETH-A";
lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
"deposit(uint256,uint256,uint256)",
type(uint256).max,
0,
0
);
lev_.spellIndex++;
lev_.targets[lev_.spellIndex] = "AAVE-V3-A";
lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
"deposit(address,uint256,uint256,uint256)",
WEETH_ADDRESS,
type(uint256).max,
0,
0
);
lev_.spellIndex++;
lev_.targets[lev_.spellIndex] = "AAVE-V3-A";
lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
"borrow(address,uint256,uint256,uint256,uint256)",
WETH_ADDRESS,
wethFlashAmount_,
2,
0,
0
);
lev_.spellIndex++;
lev_.targets[lev_.spellIndex] = "INSTAPOOL-D";
lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
"flashPayback(address,uint256,uint256,uint256)",
WETH_ADDRESS,
wethFlashAmount_,
0,
0
);
lev_.spellIndex++;
bytes memory encodedFlashData_ = abi.encode(
lev_.targets,
lev_.calldatas
);
string[] memory flashTarget = new string[](1);
bytes[] memory flashCalldata = new bytes[](1);
flashTarget[0] = "INSTAPOOL-D";
flashCalldata[0] = abi.encodeWithSignature(
"flashBorrowAndCast(address,uint256,uint256,bytes,bytes)",
WETH_ADDRESS,
wethFlashAmount_,
10,
encodedFlashData_,
"0x"
);
vaultDSA.cast(flashTarget, flashCalldata, address(this));
(, uint256 currentEETHCol_, , uint256 currentPosRatio_) = getPositionRatio();
if (currentPosRatio_ > maxPosRatio) {
revert WeethStrategyContract__PosExceededRatio();
}
emit LogLeverage(currentEETHCol_, wethFlashAmount_, currentPosRatio_);
}
}
文件 8 的 8:variables.sol
pragma solidity 0.8.17;
import "./interfaces.sol";
contract ConstantVariables {
IInstaIndex internal constant INSTA_INDEX_CONTRACT =
IInstaIndex(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
address internal constant WEETH_ADDRESS =
0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
address internal constant WETH_ADDRESS =
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant A_WEETH_ADDRESS =
0xBdfa7b7893081B35Fb54027489e2Bc7A38275129;
address internal constant D_WETH_ADDRESS =
0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE;
address internal constant AAVE_V3_GOVERNANCE =
0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7;
address internal constant AAVE_V3_PAYLOADS_CONTROLLER =
0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5;
uint256 internal constant MIN_LIMIT_AVAILABILITY = 100000000000000000000;
uint256 internal constant MIN_LEVERAGE = 100000000000000000000;
IAaveV3ProtocolDataProvider internal constant AAVE_V3_DATA_PROVIDER =
IAaveV3ProtocolDataProvider(0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3);
}
contract Variables is ConstantVariables {
uint256 internal _status;
address public owner;
IDSA public vaultDSA;
mapping(address => bool) public isRebalancer;
uint256 public maxPosRatio;
}
{
"compilationTarget": {
"contracts/main.sol": "WeethStrategyContract"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Helpers__InvalidParams","type":"error"},{"inputs":[],"name":"Helpers__NotOwner","type":"error"},{"inputs":[],"name":"Helpers__NotRebalancer","type":"error"},{"inputs":[],"name":"Helpers__Reentrant","type":"error"},{"inputs":[],"name":"OwnerContract__AlreadyInitialized","type":"error"},{"inputs":[],"name":"WeethStrategyContract__MaxLeveraged","type":"error"},{"inputs":[],"name":"WeethStrategyContract__MinAvailabilityNotReached","type":"error"},{"inputs":[],"name":"WeethStrategyContract__MinLimitNotReached","type":"error"},{"inputs":[],"name":"WeethStrategyContract__NoBorrowingAvailability","type":"error"},{"inputs":[],"name":"WeethStrategyContract__PosExceededRatio","type":"error"},{"inputs":[],"name":"WeethStrategyContract__SupplyCapReached","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAuthority","type":"address"}],"name":"LogAddDSAAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"operation","type":"uint256"}],"name":"LogDSASpell","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"wETHCollAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wETHBorrowAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currentPosRatio","type":"uint256"}],"name":"LogLeverage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vaultDSA","type":"address"}],"name":"LogSetVaultDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"maxPosRatioBefore","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"maxPosRatioAfter","type":"uint256"}],"name":"LogUpdateMaxRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"LogUpdateOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rebalancer","type":"address"},{"indexed":true,"internalType":"bool","name":"isRebalancer","type":"bool"}],"name":"LogUpdateRebalancer","type":"event"},{"inputs":[{"internalType":"address","name":"auth_","type":"address"}],"name":"addDSAAuth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPositionRatio","outputs":[{"internalType":"uint256","name":"weETHAmount_","type":"uint256"},{"internalType":"uint256","name":"eETHAmount_","type":"uint256"},{"internalType":"uint256","name":"wethAmount_","type":"uint256"},{"internalType":"uint256","name":"ratio_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeETHData","outputs":[{"internalType":"uint256","name":"weETHSupplyCap_","type":"uint256"},{"internalType":"uint256","name":"weETHSupplied_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isRebalancer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxPosRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vaultDSA_","type":"address"}],"name":"setVaultDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"bytes","name":"calldata_","type":"bytes"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"operation_","type":"uint256"}],"name":"spell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxPosRatio_","type":"uint256"}],"name":"updateMaxPosRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rebalancer_","type":"address"},{"internalType":"bool","name":"isRebalancer_","type":"bool"}],"name":"updateRebalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultDSA","outputs":[{"internalType":"contract IDSA","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wethReserveData","outputs":[{"internalType":"uint256","name":"availableLiquidity_","type":"uint256"}],"stateMutability":"view","type":"function"}]