账户
0x55...c0e5
0x55...c0e5

0x55...c0e5

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.17+commit.8df45f5f
语言
Solidity
合同源代码
文件 1 的 8:Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    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");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    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");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    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);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    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);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    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);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    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 {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
合同源代码
文件 2 的 8:IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
合同源代码
文件 3 的 8:errors.sol
// SPDX-License-Identifier: MIT
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
// SPDX-License-Identifier: MIT
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
    );

    // @notice emitted when addDSAAuth function is called by auth
    event LogAddDSAAuthority(address indexed newAuthority);

    /// @notice Emitted when rebalancer is added or removed.
    event LogUpdateRebalancer(
        address indexed rebalancer,
        bool indexed isRebalancer
    );

    /// @notice Emitted when max pos ratio is updated.
    event LogUpdateMaxRatio(
        uint256 indexed maxPosRatioBefore,
        uint256 indexed maxPosRatioAfter
    );

    /// @notice Emitted when DSA is leveraged.
    event LogLeverage(
        uint256 indexed wETHCollAmount,
        uint256 indexed wETHBorrowAmount,
        uint256 indexed currentPosRatio
    );
}
合同源代码
文件 5 的 8:helpers.sol
// SPDX-License-Identifier: MIT
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 {
    /***********************************|
    |              MODIFIERS            |
    |__________________________________*/

    /// @dev Reverts if msg.sender is not owner or enabled rebalance.
    modifier onlyRebalancer() {
        if (!(isRebalancer[msg.sender] || owner == msg.sender)) {
            revert Helpers__NotRebalancer();
        }
        _;
    }

    /// @dev Reverts if msg.sender is not owner.
    modifier onlyOwner() {
        if (owner != msg.sender) {
            revert Helpers__NotOwner();
        }
        _;
    }

    /// @dev reentrancy gaurd.
    modifier nonReentrant() {
        if (_status == 2) revert Helpers__Reentrant();
        _status = 2;
        _;
        _status = 1;
    }

    /***********************************|
    |             DSA HELPERS           |
    |__________________________________*/

    /**
     * @dev Admin Spell function
     * @param to_ target address
     * @param calldata_ function calldata
     * @param value_ function msg.value
     * @param operation_ .call or .delegate. (0 => .call, 1 => .delegateCall)
     */
    function spell(
        address to_,
        bytes memory calldata_,
        uint256 value_,
        uint256 operation_
    ) external payable onlyOwner {
        if (operation_ == 0) {
            // .call
            Address.functionCallWithValue(
                to_,
                calldata_,
                value_,
                "spell: .call failed"
            );
        } else if (operation_ == 1) {
            // .delegateCall
            Address.functionDelegateCall(
                to_,
                calldata_,
                "spell: .delegateCall failed"
            );
        } else {
            revert("no operation");
        }
        emit LogDSASpell(to_, calldata_, value_, operation_);
    }

    /**
     * @dev Admin function to add auth on DSA
     * @param auth_ new auth address for DSA
     */
    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_);
    }

    /**
     * @dev Returns current position ratio
     */
    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_)
    {
        // In token amounts, not wei
        (, uint256 weETHSupplyCapTokens_) = AAVE_V3_DATA_PROVIDER
            .getReserveCaps(WEETH_ADDRESS);

        weETHSupplyCap_ = weETHSupplyCapTokens_ * 1e18;

        weETHSupplied_ = IERC20(A_WEETH_ADDRESS).totalSupply();
    }
}
合同源代码
文件 6 的 8:interfaces.sol
// SPDX-License-Identifier: MIT
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 {
    /// @notice Fetches the amount of eEth respective to the amount of weEth sent in
    /// @param _weETHAmount amount sent in
    /// @return The total amount for the number of shares sent in
    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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {Helpers} from "./helpers.sol";
import "./interfaces.sol";

contract OwnerContract is Helpers {
    /// @notice Initializes the contract owner.
    function setOwner(address owner_) public {
        if (_status != 0) {
            revert OwnerContract__AlreadyInitialized();
        }
        owner = owner_;

        _status = 1;
        emit LogSetOwner(owner_);
    }

    /// @notice Updates the current owner.
    function updateOwner(address owner_) public onlyOwner {
        address oldOwner_ = owner;
        owner = owner_;
        emit LogUpdateOwner(oldOwner_, owner_);
    }

    /// @notice Sets the vault DSA address.
    function setVaultDSA(address vaultDSA_) public onlyOwner {
        vaultDSA = IDSA(vaultDSA_);
        emit LogSetVaultDSA(vaultDSA_);
    }

    /// @notice Enables and disables rebalancers.
    function updateRebalancer(
        address rebalancer_,
        bool isRebalancer_
    ) public onlyOwner {
        isRebalancer[rebalancer_] = isRebalancer_;
        emit LogUpdateRebalancer(rebalancer_, isRebalancer_);
    }

    /// @notice Update maximum ratio allowed by the position.
    /// Note Sent value should be scaled by 1e4. i.e. 100% = 1e6
    function updateMaxPosRatio(uint256 maxPosRatio_) public onlyOwner {
        uint256 oldRatio_ = maxPosRatio;
        maxPosRatio = maxPosRatio_;

        emit LogUpdateMaxRatio(oldRatio_, maxPosRatio_);
    }
}

contract WeethStrategyContract is OwnerContract {

    constructor() {
        // Setting vault status as open and other configs.
        setOwner(0x3BD7c3DF5dcf67f3aA314500c683C82Dc65671d5);
        // Manually setting up as all these functions are called by onlyOwner.
        // setVaultDSA
        vaultDSA = IDSA(0xf6EDCF5261112c06539412fB760c46173d3cdb12);
        // updateRebalancer
        isRebalancer[0xad5A93B6A6baA3D9bf7a5E28d63d0E25c165bcAA] = true;
        isRebalancer[0x10F37Ceb965B477bA09d23FF725E0a0f1cdb83a5] = true;
        // updateMaxPosRatio
        maxPosRatio = 928000;
    }

    // function initialize(
    //     address owner_,
    //     address vaultDSA_,
    //     address rebalancer,
    //     uint256 maxPosRatio_
    // ) public {
    //     setOwner(owner_);
    //     vaultDSA = IDSA(vaultDSA_);
    //     isRebalancer[rebalancer] = true;
    //     maxPosRatio = maxPosRatio_;

    //     string[] memory targets_ = new string[](1);
    //     bytes[] memory calldatas_ = new bytes[](1);

    //     // Enabling Aave V3 e-mode. E-mode can be enabled without any deposit.
    //     targets_[0] = "AAVE-V3-A";
    //     calldatas_[0] = abi.encodeWithSignature(
    //         "setUserEMode(uint8)",
    //         1 // WETH correlated mode
    //     );

    //     vaultDSA.cast(targets_, calldatas_, address(this));
    // }

    // Helper struct for leverage
    struct LeverageHelper {
        uint256 spellIndex;
        uint256 spellsLength;
        string[] targets;
        bytes[] calldatas;
        uint256 WEETHSupplyCap;
        uint256 WEETHSupplyAave;
        uint256 wethAvailableLiquidity;
        uint256 wethDSABal;
        uint256 leverageFactor;
    }

    /// @notice Function to run leverage of weETH <> eth.
    /// Internally factors in the weETH supply availability and wETH borrow availability.
    function leverage() external onlyRebalancer nonReentrant {
        LeverageHelper memory lev_;

        (, uint256 posEETH_, uint256 posWeth_, uint256 currentRatio_) = getPositionRatio();

        if (currentRatio_ >= maxPosRatio) {
            revert WeethStrategyContract__MaxLeveraged();
        }

        // WEETH
        (lev_.WEETHSupplyCap, lev_.WEETHSupplyAave) = getWeETHData();
        // WETH
        lev_.wethAvailableLiquidity = wethReserveData();

        uint256 WEETHSupplyAaveWithBuffer_ = lev_.WEETHSupplyAave + 1e18;

        // Check if the supply cap is reached with a buffer of 1e18
        if (WEETHSupplyAaveWithBuffer_ > lev_.WEETHSupplyCap) {
            revert WeethStrategyContract__SupplyCapReached();
        }

        /// @dev Calculate the flash amount in weETH and weth.
        uint256 supplyAvailableInWEETH_ = lev_.WEETHSupplyCap -
            WEETHSupplyAaveWithBuffer_;
        // Supply of WEETH available in Aave (expressed in terms of WETH).
        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();
        }

        /*
         * Mint eeth with wETH
         * Wrap eeth to weETH
         * Deposit weETH to Aave V3
         * Borrow wETH
         * Flashpayback wETH
         */
        lev_.spellsLength = 5;

        lev_.targets = new string[](lev_.spellsLength);
        lev_.calldatas = new bytes[](lev_.spellsLength);

        /***********************************|
        |         MINT EETH WITH WETH       |
        |__________________________________*/

        lev_.targets[lev_.spellIndex] = "EETH-A";
        lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
            "depositWeth(uint256,uint256,uint256)",
            type(uint256).max, // Deposit all the WETH flashloan amount to mint eETH.
            0,
            0
        );
        lev_.spellIndex++;

        /***********************************|
        |              WRAP EETH            |
        |__________________________________*/

        lev_.targets[lev_.spellIndex] = "WEETH-A";
        lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
            "deposit(uint256,uint256,uint256)",
            type(uint256).max, // Wrap all the eETH amount.
            0,
            0
        );
        lev_.spellIndex++;

        /***********************************|
        |       DEPOSIT WEETH TO AAVE V3    |
        |__________________________________*/

        lev_.targets[lev_.spellIndex] = "AAVE-V3-A";
        lev_.calldatas[lev_.spellIndex] = abi.encodeWithSignature(
            "deposit(address,uint256,uint256,uint256)",
            WEETH_ADDRESS,
            type(uint256).max, // Deposit all the weETH to Aave V3
            0,
            0
        );
        lev_.spellIndex++;

        /***********************************|
        |             BORROW WETH           |
        |__________________________________*/

        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++;

        /***********************************|
        |         FLASHPAYBACK WETH         |
        |__________________________________*/

        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
        );

        /***********************************|
        |           FLASHLOAN WETH          |
        |__________________________________*/
        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
// SPDX-License-Identifier: MIT
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;

    // 100 min weETH availability
    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 {
    // 0: closed; 1: open
    uint256 internal _status;

    address public owner;

    IDSA public vaultDSA;

    /// @notice mapping to store allowed rebalancers
    ///         modifiable by auth
    mapping(address => bool) public isRebalancer;

    /// @notice max ratio that the position can reach after leverage.
    uint256 public maxPosRatio;
}
设置
{
  "compilationTarget": {
    "contracts/main.sol": "WeethStrategyContract"
  },
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "remappings": []
}
ABI
[{"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"}]