ETH Price: $3,387.45 (-1.46%)
Gas: 2 Gwei

Contract

0x6753f23905f15376429e6f0c381fcc4862e48222
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Transaction Hash
Method
Block
From
To
Value
Deposit From Cvx174286372023-06-07 12:56:59387 days ago1686142619IN
0x6753f239...862e48222
0 ETH0.0071968919.77064857
Deposit From Cvx174277272023-06-07 9:52:35388 days ago1686131555IN
0x6753f239...862e48222
0 ETH0.0075982221.52989205
Deposit From Cvx174271922023-06-07 8:03:59388 days ago1686125039IN
0x6753f239...862e48222
0 ETH0.0080160623.70579816
Deposit From Cvx174261912023-06-07 4:39:35388 days ago1686112775IN
0x6753f239...862e48222
0 ETH0.008971824.24287158
Deposit From Cvx174259892023-06-07 3:58:11388 days ago1686110291IN
0x6753f239...862e48222
0 ETH0.0067780919.59893623
Claim From Vault...174226202023-06-06 16:34:23388 days ago1686069263IN
0x6753f239...862e48222
0 ETH0.0102258329.71580618
Claim From Vault...174224982023-06-06 16:09:35388 days ago1686067775IN
0x6753f239...862e48222
0 ETH0.0108666930.89376064
Deposit From Cvx174201972023-06-06 8:21:35389 days ago1686039695IN
0x6753f239...862e48222
0 ETH0.0046931118.99362932
Claim From Vault...174193482023-06-06 5:30:23389 days ago1686029423IN
0x6753f239...862e48222
0 ETH0.0132175121.09840667
Deposit From Cvx174187332023-06-06 3:25:35389 days ago1686021935IN
0x6753f239...862e48222
0 ETH0.0046522118.78900311
Deposit From Cvx174169222023-06-05 21:17:23389 days ago1685999843IN
0x6753f239...862e48222
0 ETH0.0071656530.76497631
Deposit From Eth174158832023-06-05 17:46:47389 days ago1685987207IN
0x6753f239...862e48222
1.6 ETH0.0293559544.8666171
Claim From Vault...174114672023-06-05 2:47:35390 days ago1685933255IN
0x6753f239...862e48222
0 ETH0.0101045322.33094916
Deposit From Crv174106912023-06-05 0:09:11390 days ago1685923751IN
0x6753f239...862e48222
0 ETH0.0183698920.57318097
Deposit From Cvx174061742023-06-04 8:50:23391 days ago1685868623IN
0x6753f239...862e48222
0 ETH0.0042804118.3015027
Claim From Vault...174060492023-06-04 8:25:11391 days ago1685867111IN
0x6753f239...862e48222
0 ETH0.0132425318.48645351
Claim From Vault...174056032023-06-04 6:54:23391 days ago1685861663IN
0x6753f239...862e48222
0 ETH0.0131206718.39574353
Deposit From Cvx174019272023-06-03 18:28:47391 days ago1685816927IN
0x6753f239...862e48222
0 ETH0.0065838628.14436128
Claim From Vault...173988742023-06-03 8:08:23392 days ago1685779703IN
0x6753f239...862e48222
0 ETH0.0087535620
Deposit From Cvx173974852023-06-03 3:27:59392 days ago1685762879IN
0x6753f239...862e48222
0 ETH0.0067562627.45287086
Claim From Vault...173962472023-06-02 23:17:59392 days ago1685747879IN
0x6753f239...862e48222
0 ETH0.0160770422.06936768
Claim From Vault...173952432023-06-02 19:54:35392 days ago1685735675IN
0x6753f239...862e48222
0 ETH0.0090260522.96401809
Deposit From Cvx173924642023-06-02 10:27:47392 days ago1685701667IN
0x6753f239...862e48222
0 ETH0.0090226322.63962987
Deposit From Cvx173909032023-06-02 5:10:59393 days ago1685682659IN
0x6753f239...862e48222
0 ETH0.0075396121.0776257
Deposit From Cvx173865332023-06-01 14:24:23393 days ago1685629463IN
0x6753f239...862e48222
0 ETH0.0146427940.59875924
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
174193482023-06-06 5:30:23389 days ago1686029423
0x6753f239...862e48222
0.54003918 ETH
174193482023-06-06 5:30:23389 days ago1686029423
0x6753f239...862e48222
0.54003918 ETH
174158832023-06-05 17:46:47389 days ago1685987207
0x6753f239...862e48222
1.6 ETH
174106912023-06-05 0:09:11390 days ago1685923751
0x6753f239...862e48222
0.46466061 ETH
174106912023-06-05 0:09:11390 days ago1685923751
0x6753f239...862e48222
0.46466061 ETH
174060492023-06-04 8:25:11391 days ago1685867111
0x6753f239...862e48222
6.18476608 ETH
174060492023-06-04 8:25:11391 days ago1685867111
0x6753f239...862e48222
6.18476608 ETH
174056032023-06-04 6:54:23391 days ago1685861663
0x6753f239...862e48222
0.14261974 ETH
174056032023-06-04 6:54:23391 days ago1685861663
0x6753f239...862e48222
0.14261974 ETH
173983302023-06-03 6:18:59392 days ago1685773139
0x6753f239...862e48222
0.19403085 ETH
173983302023-06-03 6:18:59392 days ago1685773139
0x6753f239...862e48222
0.19403085 ETH
173962472023-06-02 23:17:59392 days ago1685747879
0x6753f239...862e48222
0.06726565 ETH
173962472023-06-02 23:17:59392 days ago1685747879
0x6753f239...862e48222
0.06726565 ETH
173859872023-06-01 12:33:59393 days ago1685622839
0x6753f239...862e48222
0.27191212 ETH
173859872023-06-01 12:33:59393 days ago1685622839
0x6753f239...862e48222
0.27191212 ETH
173820232023-05-31 23:10:59394 days ago1685574659
0x6753f239...862e48222
0.23852846 ETH
173820232023-05-31 23:10:59394 days ago1685574659
0x6753f239...862e48222
0.23852846 ETH
173756282023-05-31 1:34:11395 days ago1685496851
0x6753f239...862e48222
0.17129761 ETH
173756282023-05-31 1:34:11395 days ago1685496851
0x6753f239...862e48222
0.17129761 ETH
173622002023-05-29 4:13:23397 days ago1685333603
0x6753f239...862e48222
0.17112676 ETH
173622002023-05-29 4:13:23397 days ago1685333603
0x6753f239...862e48222
0.17112676 ETH
173567282023-05-28 9:48:59398 days ago1685267339
0x6753f239...862e48222
0.35066309 ETH
173567282023-05-28 9:48:59398 days ago1685267339
0x6753f239...862e48222
0.35066309 ETH
173559742023-05-28 7:15:23398 days ago1685258123
0x6753f239...862e48222
0.91298827 ETH
173559742023-05-28 7:15:23398 days ago1685258123
0x6753f239...862e48222
0.91298827 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PCvxZaps

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license
File 1 of 17 : StrategyZaps.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "SafeERC20.sol";
import "ReentrancyGuard.sol";
import "ERC20.sol";
import "UnionBase.sol";
import "IGenericVault.sol";
import "IUniV2Router.sol";
import "ICurveTriCrypto.sol";
import "IERC4626.sol";
import "IPirexCVX.sol";

contract PCvxZaps is UnionBase, ReentrancyGuard {
    using SafeERC20 for IERC20;

    address private constant PIREX_CVX =
        0x35A398425d9f1029021A92bc3d2557D42C8588D7;
    address private constant PXCVX_TOKEN =
        0xBCe0Cf87F513102F22232436CCa2ca49e815C3aC;
    address private constant PXCVX_VAULT =
        0x8659Fc767cad6005de79AF65dAfE4249C57927AF;
    address private constant WETH_TOKEN =
        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address private constant TRICRYPTO =
        0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
    address private constant USDT_TOKEN =
        0xdAC17F958D2ee523a2206206994597C13D831ec7;
    address private constant CURVE_CVX_PCVX_POOL =
        0xF3456E8061461e144b3f252E69DcD5b6070fdEE0;
    IERC4626 vault = IERC4626(PXCVX_VAULT);
    ICurveTriCrypto triCryptoSwap = ICurveTriCrypto(TRICRYPTO);

    /// @notice Set approvals for the contracts used when swapping & staking
    function setApprovals() external {
        IERC20(PXCVX_TOKEN).safeApprove(PXCVX_VAULT, 0);
        IERC20(PXCVX_TOKEN).safeApprove(PXCVX_VAULT, type(uint256).max);

        IERC20(CVX_TOKEN).safeApprove(PIREX_CVX, 0);
        IERC20(CVX_TOKEN).safeApprove(PIREX_CVX, type(uint256).max);

        IERC20(CVX_TOKEN).safeApprove(CURVE_CVX_ETH_POOL, 0);
        IERC20(CVX_TOKEN).safeApprove(CURVE_CVX_ETH_POOL, type(uint256).max);

        IERC20(CVX_TOKEN).safeApprove(CURVE_CVX_PCVX_POOL, 0);
        IERC20(CVX_TOKEN).safeApprove(CURVE_CVX_PCVX_POOL, type(uint256).max);

        IERC20(PXCVX_TOKEN).safeApprove(CURVE_CVX_PCVX_POOL, 0);
        IERC20(PXCVX_TOKEN).safeApprove(CURVE_CVX_PCVX_POOL, type(uint256).max);

        IERC20(CVXCRV_TOKEN).safeApprove(CURVE_CVXCRV_CRV_POOL, 0);
        IERC20(CVXCRV_TOKEN).safeApprove(
            CURVE_CVXCRV_CRV_POOL,
            type(uint256).max
        );

        IERC20(CRV_TOKEN).safeApprove(CURVE_CRV_ETH_POOL, 0);
        IERC20(CRV_TOKEN).safeApprove(CURVE_CRV_ETH_POOL, type(uint256).max);

        IERC20(CRV_TOKEN).safeApprove(CURVE_CVXCRV_CRV_POOL, 0);
        IERC20(CRV_TOKEN).safeApprove(CURVE_CVXCRV_CRV_POOL, type(uint256).max);
    }

    function _deposit(
        uint256 _amount,
        uint256 _minAmountOut,
        address _to
    ) internal {
        if (ICurveV2Pool(CURVE_CVX_PCVX_POOL).price_oracle() < 1 ether) {
            uint256 _pxCvxAmount = ICurveV2Pool(CURVE_CVX_PCVX_POOL).exchange(
                0,
                1,
                _amount,
                _minAmountOut,
                false,
                address(this)
            );
            vault.deposit(_pxCvxAmount, _to);
        } else {
            require(_amount >= _minAmountOut, "slippage");
            IPirexCVX(PIREX_CVX).deposit(_amount, _to, true, address(0));
        }
    }

    /// @notice Deposit into the pounder from ETH
    /// @param minAmountOut - min amount of pCVX tokens expected
    /// @param to - address to stake on behalf of
    function depositFromEth(uint256 minAmountOut, address to)
        external
        payable
        notToZeroAddress(to)
    {
        require(msg.value > 0, "cheap");
        _depositFromEth(msg.value, minAmountOut, to);
    }

    /// @notice Deposit into the pounder from CRV
    /// @param minAmountOut - min amount of pCVX tokens expected
    /// @param to - address to stake on behalf of
    function depositFromCrv(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) external notToZeroAddress(to) {
        IERC20(CRV_TOKEN).safeTransferFrom(msg.sender, address(this), amount);
        uint256 _ethBalance = _swapCrvToEth(amount);
        _depositFromEth(_ethBalance, minAmountOut, to);
    }

    /// @notice Deposit into the pounder from CVX
    /// @param minAmountOut - min amount of pCVX tokens expected
    /// @param to - address to stake on behalf of
    function depositFromCvx(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) external notToZeroAddress(to) {
        IERC20(CVX_TOKEN).safeTransferFrom(msg.sender, address(this), amount);
        _deposit(amount, minAmountOut, to);
    }

    /// @notice Deposit into the pounder from cvxCRV
    /// @param minAmountOut - min amount of pCVX tokens expected
    /// @param to - address to stake on behalf of
    function depositFromCvxCrv(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) external notToZeroAddress(to) {
        IERC20(CVXCRV_TOKEN).safeTransferFrom(
            msg.sender,
            address(this),
            amount
        );
        uint256 _crvBalance = _swapCvxCrvToCrv(amount, address(this));
        uint256 _ethBalance = _swapCrvToEth(_crvBalance);
        _depositFromEth(_ethBalance, minAmountOut, to);
    }

    /// @notice Internal function to deposit ETH to the pounder
    /// @param _amount - amount of ETH
    /// @param _minAmountOut - min amount of tokens expected
    /// @param _to - address to stake on behalf of
    function _depositFromEth(
        uint256 _amount,
        uint256 _minAmountOut,
        address _to
    ) internal {
        uint256 _cvxBalance = _swapEthToCvx(_amount);
        _deposit(_cvxBalance, _minAmountOut, _to);
    }

    /// @notice Deposit into the pounder from any token via Uni interface
    /// @notice Use at your own risk
    /// @dev Zap contract needs approval for spending of inputToken
    /// @param amount - min amount of input token
    /// @param minAmountOut - min amount of cvxCRV expected
    /// @param router - address of the router to use. e.g. 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F for Sushi
    /// @param inputToken - address of the token to swap from, needs to have an ETH pair on router used
    /// @param to - address to stake on behalf of
    function depositViaUniV2EthPair(
        uint256 amount,
        uint256 minAmountOut,
        address router,
        address inputToken,
        address to
    ) external notToZeroAddress(to) {
        require(router != address(0));

        IERC20(inputToken).safeTransferFrom(msg.sender, address(this), amount);
        address[] memory _path = new address[](2);
        _path[0] = inputToken;
        _path[1] = WETH_TOKEN;

        IERC20(inputToken).safeApprove(router, 0);
        IERC20(inputToken).safeApprove(router, amount);

        IUniV2Router(router).swapExactTokensForETH(
            amount,
            1,
            _path,
            address(this),
            block.timestamp + 1
        );
        _depositFromEth(address(this).balance, minAmountOut, to);
    }

    /// @notice Unstake and converts pxCVX to CVX
    /// @param _amount - amount to withdraw
    /// @param _minAmountOut - minimum amount of LP tokens expected
    /// @param _to - receiver
    /// @return amount of underlying withdrawn
    function _claimAsCvx(
        uint256 _amount,
        uint256 _minAmountOut,
        address _to
    ) internal returns (uint256) {
        return
            ICurveV2Pool(CURVE_CVX_PCVX_POOL).exchange(
                1,
                0,
                _amount,
                _minAmountOut,
                false,
                _to
            );
    }

    /// @notice Retrieves a user's vault shares and withdraw all
    /// @param _amount - amount of shares to retrieve
    function _claimAndWithdraw(uint256 _amount) internal {
        require(
            vault.transferFrom(msg.sender, address(this), _amount),
            "error"
        );
        vault.redeem(_amount, address(this), address(this));
    }

    /// @notice Claim as CVX
    /// @param amount - amount to withdraw
    /// @param minAmountOut - minimum amount of underlying tokens expected
    /// @param to - address to send withdrawn underlying to
    /// @return amount of underlying withdrawn
    function claimFromVaultAsCvx(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) public notToZeroAddress(to) returns (uint256) {
        _claimAndWithdraw(amount);
        return
            _claimAsCvx(
                IERC20(PXCVX_TOKEN).balanceOf(address(this)),
                minAmountOut,
                to
            );
    }

    /// @notice Claim as native ETH
    /// @param amount - amount to withdraw
    /// @param minAmountOut - minimum amount of ETH expected
    /// @param to - address to send ETH to
    /// @return amount of ETH withdrawn
    function claimFromVaultAsEth(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) public notToZeroAddress(to) returns (uint256) {
        uint256 _ethAmount = _claimAsEth(amount);
        require(_ethAmount >= minAmountOut, "slippage");
        (bool success, ) = to.call{value: _ethAmount}("");
        require(success, "ETH transfer failed");
        return _ethAmount;
    }

    /// @notice Withdraw as native ETH (internal)
    /// @param _amount - amount to withdraw
    /// @return amount of ETH withdrawn
    function _claimAsEth(uint256 _amount)
        public
        nonReentrant
        returns (uint256)
    {
        _claimAndWithdraw(_amount);
        uint256 _cvxAmount = _claimAsCvx(
            IERC20(PXCVX_TOKEN).balanceOf(address(this)),
            0,
            address(this)
        );
        return
            cvxEthSwap.exchange_underlying(
                CVXETH_CVX_INDEX,
                CVXETH_ETH_INDEX,
                _cvxAmount,
                0
            );
    }

    /// @notice Claim to any token via a univ2 router
    /// @notice Use at your own risk
    /// @param amount - amount to unstake
    /// @param minAmountOut - min amount of output token expected
    /// @param router - address of the router to use. e.g. 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F for Sushi
    /// @param outputToken - address of the token to swap to
    /// @param to - address of the final recipient of the swapped tokens
    function claimFromVaultViaUniV2EthPair(
        uint256 amount,
        uint256 minAmountOut,
        address router,
        address outputToken,
        address to
    ) public notToZeroAddress(to) {
        require(router != address(0));
        _claimAsEth(amount);
        address[] memory _path = new address[](2);
        _path[0] = WETH_TOKEN;
        _path[1] = outputToken;
        IUniV2Router(router).swapExactETHForTokens{
            value: address(this).balance
        }(minAmountOut, _path, to, block.timestamp + 1);
    }

    /// @notice Claim as USDT via Tricrypto
    /// @param amount - the amount to unstake
    /// @param minAmountOut - the min expected amount of USDT to receive
    /// @param to - the adress that will receive the USDT
    /// @return amount of USDT obtained
    function claimFromVaultAsUsdt(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) public notToZeroAddress(to) returns (uint256) {
        uint256 _ethAmount = _claimAsEth(amount);
        _swapEthToUsdt(_ethAmount, minAmountOut);
        uint256 _usdtAmount = IERC20(USDT_TOKEN).balanceOf(address(this));
        IERC20(USDT_TOKEN).safeTransfer(to, _usdtAmount);
        return _usdtAmount;
    }

    /// @notice Withdraw as CRV (internal)
    /// @param _amount - amount to withdraw
    /// @param _minAmountOut - min amount received
    /// @return amount of CRV withdrawn
    function _claimAsCrv(uint256 _amount, uint256 _minAmountOut)
        internal
        returns (uint256)
    {
        uint256 _ethAmount = _claimAsEth(_amount);
        return _swapEthToCrv(_ethAmount, _minAmountOut);
    }

    /// @notice Claim as CRV
    /// @param amount - the amount to unstake
    /// @param minAmountOut - the min expected amount received
    /// @param to - receiver address
    /// @return amount obtained
    function claimFromVaultAsCrv(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) public notToZeroAddress(to) returns (uint256) {
        uint256 _crvAmount = _claimAsCrv(amount, minAmountOut);
        IERC20(CRV_TOKEN).safeTransfer(to, _crvAmount);
        return _crvAmount;
    }

    /// @notice Claim as cvxCRV
    /// @param amount - the amount to unstake
    /// @param minAmountOut - the min expected amount received
    /// @param to - receiver address
    /// @return amount obtained
    function claimFromVaultAsCvxCrv(
        uint256 amount,
        uint256 minAmountOut,
        address to
    ) public notToZeroAddress(to) returns (uint256) {
        uint256 _crvAmount = _claimAsCrv(amount, 0);
        return _swapCrvToCvxCrv(_crvAmount, to, minAmountOut);
    }

    /// @notice swap ETH to USDT via Curve's tricrypto
    /// @param _amount - the amount of ETH to swap
    /// @param _minAmountOut - the minimum amount expected
    function _swapEthToUsdt(uint256 _amount, uint256 _minAmountOut) internal {
        triCryptoSwap.exchange{value: _amount}(
            2, // ETH
            0, // USDT
            _amount,
            _minAmountOut,
            true
        );
    }

    receive() external payable {}
}

File 2 of 17 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC20.sol";
import "Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
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));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        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));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 3 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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);
}

File 4 of 17 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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://diligence.consensys.net/posts/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.5.11/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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 5 of 17 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 6 of 17 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC20.sol";
import "IERC20Metadata.sol";
import "Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The defaut value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - subtractedValue);

        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

File 7 of 17 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 8 of 17 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 9 of 17 : UnionBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "ICurveV2Pool.sol";
import "ICurveFactoryPool.sol";
import "IBasicRewards.sol";

// Common variables and functions
contract UnionBase {
    address public constant CVXCRV_STAKING_CONTRACT =
        0x3Fe65692bfCD0e6CF84cB1E7d24108E434A7587e;
    address public constant CURVE_CRV_ETH_POOL =
        0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511;
    address public constant CURVE_CVX_ETH_POOL =
        0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4;
    address public constant CURVE_CVXCRV_CRV_POOL =
        0x9D0464996170c6B9e75eED71c68B99dDEDf279e8;

    address public constant CRV_TOKEN =
        0xD533a949740bb3306d119CC777fa900bA034cd52;
    address public constant CVXCRV_TOKEN =
        0x62B9c7356A2Dc64a1969e19C23e4f579F9810Aa7;
    address public constant CVX_TOKEN =
        0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;

    uint256 public constant CRVETH_ETH_INDEX = 0;
    uint256 public constant CRVETH_CRV_INDEX = 1;
    int128 public constant CVXCRV_CRV_INDEX = 0;
    int128 public constant CVXCRV_CVXCRV_INDEX = 1;
    uint256 public constant CVXETH_ETH_INDEX = 0;
    uint256 public constant CVXETH_CVX_INDEX = 1;

    IBasicRewards cvxCrvStaking = IBasicRewards(CVXCRV_STAKING_CONTRACT);
    ICurveV2Pool cvxEthSwap = ICurveV2Pool(CURVE_CVX_ETH_POOL);
    ICurveV2Pool crvEthSwap = ICurveV2Pool(CURVE_CRV_ETH_POOL);
    ICurveFactoryPool crvCvxCrvSwap = ICurveFactoryPool(CURVE_CVXCRV_CRV_POOL);

    /// @notice Swap CRV for cvxCRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @return amount of CRV obtained after the swap
    function _swapCrvToCvxCrv(uint256 amount, address recipient)
        internal
        returns (uint256)
    {
        return _crvToCvxCrv(amount, recipient, 0);
    }

    /// @notice Swap CRV for cvxCRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _swapCrvToCvxCrv(
        uint256 amount,
        address recipient,
        uint256 minAmountOut
    ) internal returns (uint256) {
        return _crvToCvxCrv(amount, recipient, minAmountOut);
    }

    /// @notice Swap CRV for cvxCRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _crvToCvxCrv(
        uint256 amount,
        address recipient,
        uint256 minAmountOut
    ) internal returns (uint256) {
        return
            crvCvxCrvSwap.exchange(
                CVXCRV_CRV_INDEX,
                CVXCRV_CVXCRV_INDEX,
                amount,
                minAmountOut,
                recipient
            );
    }

    /// @notice Swap cvxCRV for CRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @return amount of CRV obtained after the swap
    function _swapCvxCrvToCrv(uint256 amount, address recipient)
        internal
        returns (uint256)
    {
        return _cvxCrvToCrv(amount, recipient, 0);
    }

    /// @notice Swap cvxCRV for CRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _swapCvxCrvToCrv(
        uint256 amount,
        address recipient,
        uint256 minAmountOut
    ) internal returns (uint256) {
        return _cvxCrvToCrv(amount, recipient, minAmountOut);
    }

    /// @notice Swap cvxCRV for CRV on Curve
    /// @param amount - amount to swap
    /// @param recipient - where swapped tokens will be sent to
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _cvxCrvToCrv(
        uint256 amount,
        address recipient,
        uint256 minAmountOut
    ) internal returns (uint256) {
        return
            crvCvxCrvSwap.exchange(
                CVXCRV_CVXCRV_INDEX,
                CVXCRV_CRV_INDEX,
                amount,
                minAmountOut,
                recipient
            );
    }

    /// @notice Swap CRV for native ETH on Curve
    /// @param amount - amount to swap
    /// @return amount of ETH obtained after the swap
    function _swapCrvToEth(uint256 amount) internal returns (uint256) {
        return _crvToEth(amount, 0);
    }

    /// @notice Swap CRV for native ETH on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of ETH obtained after the swap
    function _swapCrvToEth(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return _crvToEth(amount, minAmountOut);
    }

    /// @notice Swap CRV for native ETH on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of ETH obtained after the swap
    function _crvToEth(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return
            crvEthSwap.exchange_underlying{value: 0}(
                CRVETH_CRV_INDEX,
                CRVETH_ETH_INDEX,
                amount,
                minAmountOut
            );
    }

    /// @notice Swap native ETH for CRV on Curve
    /// @param amount - amount to swap
    /// @return amount of CRV obtained after the swap
    function _swapEthToCrv(uint256 amount) internal returns (uint256) {
        return _ethToCrv(amount, 0);
    }

    /// @notice Swap native ETH for CRV on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _swapEthToCrv(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return _ethToCrv(amount, minAmountOut);
    }

    /// @notice Swap native ETH for CRV on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _ethToCrv(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return
            crvEthSwap.exchange_underlying{value: amount}(
                CRVETH_ETH_INDEX,
                CRVETH_CRV_INDEX,
                amount,
                minAmountOut
            );
    }

    /// @notice Swap native ETH for CVX on Curve
    /// @param amount - amount to swap
    /// @return amount of CRV obtained after the swap
    function _swapEthToCvx(uint256 amount) internal returns (uint256) {
        return _ethToCvx(amount, 0);
    }

    /// @notice Swap native ETH for CVX on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _swapEthToCvx(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return _ethToCvx(amount, minAmountOut);
    }

    /// @notice Swap native ETH for CVX on Curve
    /// @param amount - amount to swap
    /// @param minAmountOut - minimum expected amount of output tokens
    /// @return amount of CRV obtained after the swap
    function _ethToCvx(uint256 amount, uint256 minAmountOut)
        internal
        returns (uint256)
    {
        return
            cvxEthSwap.exchange_underlying{value: amount}(
                CVXETH_ETH_INDEX,
                CVXETH_CVX_INDEX,
                amount,
                minAmountOut
            );
    }

    modifier notToZeroAddress(address _to) {
        require(_to != address(0), "Invalid address!");
        _;
    }
}

File 10 of 17 : ICurveV2Pool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface ICurveV2Pool {
    function get_dy(
        uint256 i,
        uint256 j,
        uint256 dx
    ) external view returns (uint256);

    function calc_token_amount(uint256[2] calldata amounts)
        external
        view
        returns (uint256);

    function exchange_underlying(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy
    ) external payable returns (uint256);

    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount)
        external
        returns (uint256);

    function lp_price() external view returns (uint256);

    function exchange(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy
    ) external payable returns (uint256);

    function exchange(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy,
        bool use_eth
    ) external payable returns (uint256);

    function exchange(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy,
        bool use_eth,
        address receiver
    ) external payable returns (uint256);

    function price_oracle() external view returns (uint256);

    function remove_liquidity_one_coin(
        uint256 token_amount,
        uint256 i,
        uint256 min_amount,
        bool use_eth,
        address receiver
    ) external returns (uint256);
}

File 11 of 17 : ICurveFactoryPool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface ICurveFactoryPool {
    function get_dy(
        int128 i,
        int128 j,
        uint256 dx
    ) external view returns (uint256);

    function get_balances() external view returns (uint256[2] memory);

    function add_liquidity(
        uint256[2] memory _amounts,
        uint256 _min_mint_amount,
        address _receiver
    ) external returns (uint256);

    function exchange(
        int128 i,
        int128 j,
        uint256 _dx,
        uint256 _min_dy,
        address _receiver
    ) external returns (uint256);
}

File 12 of 17 : IBasicRewards.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.9;

interface IBasicRewards {
    function stakeFor(address, uint256) external returns (bool);

    function balanceOf(address) external view returns (uint256);

    function earned(address) external view returns (uint256);

    function withdrawAll(bool) external returns (bool);

    function withdraw(uint256, bool) external returns (bool);

    function withdrawAndUnwrap(uint256 amount, bool claim)
        external
        returns (bool);

    function getReward() external returns (bool);

    function stake(uint256) external returns (bool);

    function extraRewards(uint256) external view returns (address);

    function exit() external returns (bool);
}

File 13 of 17 : IGenericVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface IGenericVault {
    function withdraw(address _to, uint256 _shares)
        external
        returns (uint256 withdrawn);

    function withdrawAll(address _to) external returns (uint256 withdrawn);

    function depositAll(address _to) external returns (uint256 _shares);

    function deposit(address _to, uint256 _amount)
        external
        returns (uint256 _shares);

    function harvest() external;

    function balanceOfUnderlying(address user)
        external
        view
        returns (uint256 amount);

    function totalUnderlying() external view returns (uint256 total);

    function totalSupply() external view returns (uint256 total);

    function underlying() external view returns (address);

    function strategy() external view returns (address);

    function platform() external view returns (address);

    function setPlatform(address _platform) external;

    function setPlatformFee(uint256 _fee) external;

    function setCallIncentive(uint256 _incentive) external;

    function setWithdrawalPenalty(uint256 _penalty) external;

    function setApprovals() external;

    function callIncentive() external view returns (uint256);

    function platformFee() external view returns (uint256);
}

File 14 of 17 : IUniV2Router.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface IUniV2Router {
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function getAmountsOut(uint256 amountIn, address[] memory path)
        external
        view
        returns (uint256[] memory amounts);
}

File 15 of 17 : ICurveTriCrypto.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface ICurveTriCrypto {
    function exchange(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy,
        bool use_eth
    ) external payable;

    function get_dy(
        uint256 i,
        uint256 j,
        uint256 dx
    ) external view returns (uint256);
}

File 16 of 17 : IERC4626.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

/**
 * @title EIP 4626 specification
 * @notice Interface of EIP 4626 Interface
 * as defined in https://eips.ethereum.org/EIPS/eip-4626
 */
interface IERC4626 {
    /**
     * @notice Event indicating that `caller` exchanged `assets` for `shares`, and transferred those `shares` to `owner`
     * @dev Emitted when tokens are deposited into the vault via {mint} and {deposit} methods
     */
    event Deposit(
        address indexed caller,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @notice Event indicating that `caller` exchanged `shares`, owned by `owner`, for `assets`, and transferred those
     * `assets` to `receiver`
     * @dev Emitted when shares are withdrawn from the vault via {redeem} or {withdraw} methods
     */
    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @notice Returns the address of the underlying token used by the Vault
     * @return assetTokenAddress The address of the underlying ERC20 Token
     * @dev MUST be an ERC-20 token contract
     *
     * MUST not revert
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @notice Returns the total amount of the underlying asset managed by the Vault
     * @return totalManagedAssets Amount of the underlying asset
     * @dev Should include any compounding that occurs from yield.
     *
     * Should be inclusive of any fees that are charged against assets in the vault.
     *
     * Must not revert
     *
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     *
     * @notice Returns the amount of shares that, in an ideal scenario, the vault would exchange for the amount of assets
     * provided
     *
     * @param assets Amount of assets to convert
     * @return shares Amount of shares that would be exchanged for the provided amount of assets
     *
     * @dev MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     *
     * MUST NOT show any variations depending on the caller.
     *
     * MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     *
     * MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     *
     * MUST round down towards 0.
     *
     * This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and from.
     */
    function convertToShares(uint256 assets)
        external
        view
        returns (uint256 shares);

    /**
     *
     * @notice Returns the amount of assets that the vault would exchange for the amount of shares provided
     *
     * @param shares Amount of vault shares to convert
     * @return assets Amount of assets that would be exchanged for the provided amount of shares
     *
     * @dev MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     *
     * MUST NOT show any variations depending on the caller.
     *
     * MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     *
     * MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     *
     * MUST round down towards 0.
     *
     * This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and from.
     */
    function convertToAssets(uint256 shares)
        external
        view
        returns (uint256 assets);

    /**
     *
     * @notice Returns the maximum amount of the underlying asset that can be deposited into the vault for the `receiver`
     * through a {deposit} call
     *
     * @param receiver Address whose maximum deposit is being queries
     * @return maxAssets
     *
     * @dev MUST return the maximum amount of assets {deposit} would allow to be deposited for receiver and not cause a
     * revert, which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if
     *necessary). This assumes that the user has infinite assets, i.e. MUST NOT rely on {balanceOf} of asset.
     *
     * MUST factor in both global and user-specific limits, like if deposits are entirely disabled (even temporarily)
     * it MUST return 0.
     *
     * MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     *
     * MUST NOT revert.
     */
    function maxDeposit(address receiver)
        external
        view
        returns (uint256 maxAssets);

    /**
     * @notice Simulate the effects of a user's deposit at the current block, given current on-chain conditions
     * @param assets Amount of assets
     * @return shares Amount of shares
     * @dev MUST return as close to and no more than the exact amount of Vault shares that would be minted in a {deposit}
     * call in the same transaction. I.e. deposit should return the same or more shares as {previewDeposit} if called in
     * the same transaction. (I.e. {previewDeposit} should underestimate or round-down)
     *
     * MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     * deposit would be accepted, regardless if the user has enough tokens approved, etc.
     *
     * MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     *
     * MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also
     * cause deposit to revert.
     *
     * Note that any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage
     * in share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets)
        external
        view
        returns (uint256 shares);

    /**
     * @notice Mints `shares` Vault shares to `receiver` by depositing exactly `amount` of underlying tokens
     * @param assets Amount of assets
     * @param receiver Address to deposit underlying tokens into
     * @dev Must emit the {Deposit} event
     *
     * MUST support ERC-20 {approve} / {transferFrom} on asset as a deposit flow. MAY support an additional flow in
     * which the underlying tokens are owned by the Vault contract before the {deposit} execution, and are accounted for
     * during {deposit}.
     *
     * MUST revert if all of `assets` cannot be deposited (due to deposit limit being reached, slippage, the user not
     * approving enough underlying tokens to the Vault contract, etc).
     *
     * Note that most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver)
        external
        returns (uint256 shares);

    /**
     * @notice Returns the maximum amount of shares that can be minted from the vault for the `receiver``, via a `mint`
     * call
     * @param receiver Address to deposit minted shares into
     * @return maxShares The maximum amount of shares
     * @dev MUST return the maximum amount of shares mint would allow to be deposited to receiver and not cause a revert,
     * which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if necessary).
     * This assumes that the user has infinite assets, i.e. MUST NOT rely on balanceOf of asset.
     *
     * MUST factor in both global and user-specific limits, like if mints are entirely disabled (even temporarily) it
     *
     * MUST return 0.
     *
     * MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     *
     * MUST NOT revert.
     */
    function maxMint(address receiver)
        external
        view
        returns (uint256 maxShares);

    /**
     * @notice Simulate the effects of a user's mint at the current block, given current on-chain conditions
     * @param shares Amount of shares to mint
     * @return assets Amount of assets required to mint `mint` amount of shares
     * @dev MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the same
     * transaction. (I.e. {previewMint} should overestimate or round-up)
     *
     * MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     * would be accepted, regardless if the user has enough tokens approved, etc.
     *
     * MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     *
     * MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also
     * cause mint to revert.
     *
     * Note that any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @notice Mints exactly `shares` vault shares to `receiver` by depositing `amount` of underlying tokens
     * @param shares Amount of shares to mint
     * @param receiver Address to deposit minted shares into
     * @return assets Amount of assets transferred to vault
     * @dev Must emit the {Deposit} event
     *
     * MUST support ERC-20 {approve} / {transferFrom} on asset as a mint flow. MAY support an additional flow in
     *  which the underlying tokens are owned by the Vault contract before the mint execution, and are accounted for
     * during mint.
     *
     * MUST revert if all of `shares` cannot be minted (due to deposit limit being reached, slippage, the user not
     * approving enough underlying tokens to the Vault contract, etc).
     *
     * Note that most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver)
        external
        returns (uint256 assets);

    /**
     * @notice Returns the maximum amount of the underlying asset that can be withdrawn from the `owner` balance in the
     * vault, through a `withdraw` call.
     * @param owner Address of the owner whose max withdrawal amount is being queries
     * @return maxAssets Maximum amount of underlying asset that can be withdrawn
     * @dev MUST return the maximum amount of assets that could be transferred from `owner` through {withdraw} and not
     * cause a revert, which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if
     * necessary).
     *
     * MUST factor in both global and user-specific limits, like if withdrawals are entirely disabled
     * (even temporarily)  it MUST return 0.
     *
     * MUST NOT revert.
     */
    function maxWithdraw(address owner)
        external
        view
        returns (uint256 maxAssets);

    /**
     * @notice Simulate the effects of a user's withdrawal at the current block, given current on-chain conditions.
     * @param assets Amount of assets
     * @return shares Amount of shares
     * @dev MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a
     * {withdraw} call in the same transaction. I.e. {withdraw} should return the same or fewer shares as
     * {previewWithdraw} if called in the same transaction. (I.e. {previewWithdraw should overestimate or round-up})
     *
     * MUST NOT account for withdrawal limits like those returned from {maxWithdraw} and should always act as though
     * the withdrawal would be accepted, regardless if the user has enough shares, etc.
     *
     * MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     *
     * MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also
     * cause {withdraw} to revert.
     *
     * Note that any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets)
        external
        view
        returns (uint256 shares);

    /**
     * @notice Burns `shares` from `owner` and sends exactly `assets` of underlying tokens to `receiver`
     * @param assets Amount of underling assets to withdraw
     * @return shares Amount of shares that will be burned
     * @dev Must emit the {Withdraw} event
     *
     * MUST support a withdraw flow where the shares are burned from `owner` directly where `owner` is `msg.sender`
     * or `msg.sender` has ERC-20 approval over the shares of `owner`. MAY support an additional flow in which the shares
     * are transferred to the Vault contract before the withdraw execution, and are accounted for during withdraw.
     *
     * MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     * not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     *  Those methods should be performed separately.
     */
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) external returns (uint256 shares);

    /**
     * @notice Returns the maximum amount of vault shares that can be redeemed from the `owner` balance in the vault, via
     * a `redeem` call.
     * @param owner Address of the owner whose shares are being queries
     * @return maxShares Maximum amount of shares that can be redeemed
     * @dev MUST return the maximum amount of shares that could be transferred from `owner` through `redeem` and not cause
     * a revert, which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if
     * necessary).
     *
     * MUST factor in both global and user-specific limits, like if redemption is entirely disabled
     * (even temporarily) it MUST return 0.
     *
     * MUST NOT revert
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @notice Simulate the effects of a user's redemption at the current block, given current on-chain conditions
     * @param shares Amount of shares that are being simulated to be redeemed
     * @return assets Amount of underlying assets that can be redeemed
     * @dev MUST return as close to and no more than the exact amount of `assets `that would be withdrawn in a {redeem}
     * call in the same transaction. I.e. {redeem} should return the same or more assets as {previewRedeem} if called in
     * the same transaction. I.e. {previewRedeem} should underestimate/round-down
     *
     * MUST NOT account for redemption limits like those returned from {maxRedeem} and should always act as though
     * the redemption would be accepted, regardless if the user has enough shares, etc.
     *
     * MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     *
     * MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also
     * cause {redeem} to revert.
     *
     * Note that any unfavorable discrepancy between {convertToAssets} and {previewRedeem} SHOULD be considered
     * slippage in share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares)
        external
        view
        returns (uint256 assets);

    /**
     * @notice Burns exactly `shares` from `owner` and sends `assets` of underlying tokens to `receiver`
     * @param shares Amount of shares to burn
     * @param receiver Address to deposit redeemed underlying tokens to
     * @return assets Amount of underlying tokens redeemed
     * @dev Must emit the {Withdraw} event
     * MUST support a {redeem} flow where the shares are burned from owner directly where `owner` is `msg.sender` or
     *
     * `msg.sender` has ERC-20 approval over the shares of `owner`. MAY support an additional flow in which the shares
     * are transferred to the Vault contract before the {redeem} execution, and are accounted for during {redeem}.
     *
     * MUST revert if all of {shares} cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     * not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}

File 17 of 17 : IPirexCVX.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPirexCVX {
    function deposit(
        uint256 assets,
        address receiver,
        bool shouldCompound,
        address developer
    ) external;
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "libraries": {
    "StrategyZaps.sol": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"CRVETH_CRV_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CRVETH_ETH_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CRV_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE_CRV_ETH_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE_CVXCRV_CRV_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE_CVX_ETH_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXCRV_CRV_INDEX","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXCRV_CVXCRV_INDEX","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXCRV_STAKING_CONTRACT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXCRV_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXETH_CVX_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVXETH_ETH_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVX_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"_claimAsEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultAsCrv","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultAsCvx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultAsCvxCrv","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultAsEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultAsUsdt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromVaultViaUniV2EthPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"depositFromCrv","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"depositFromCvx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"depositFromCvxCrv","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"depositFromEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"depositViaUniV2EthPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052600080546001600160a01b0319908116733fe65692bfcd0e6cf84cb1e7d24108e434a7587e1790915560018054821673b576491f1e6e5e62f1d8f26062ee822b40b0e0d4179055600280548216738301ae4fc9c624d1d396cbdaa1ed877821d7c511179055600380548216739d0464996170c6b9e75eed71c68b99ddedf279e8179055600580548216738659fc767cad6005de79af65dafe4249c57927af1790556006805490911673d51a44d3fae010294c616388b506acda1bfaae461790553480156100d057600080fd5b5060016004556120d1806100e56000396000f3fe6080604052600436106101855760003560e01c806379e8aeeb116100d1578063a8d9693d1161008a578063d8697a5011610064578063d8697a5014610448578063dbc199d71461045d578063f1d5253e1461047d578063f521d3d3146104a557600080fd5b8063a8d9693d14610400578063ab6e25cd14610226578063c70eddff1461042057600080fd5b806379e8aeeb146103335780637ec5508a146103535780638702ca5c1461037b5780638757b15b1461039b57806393516676146103b0578063961deefe146103d857600080fd5b8063311e91061161013e578063657428a311610118578063657428a3146102c35780636acabc2e146102ae5780637506ceb9146102eb578063775491dc1461031357600080fd5b8063311e91061461026e57806331247e061461028e57806360c3a38c146102ae57600080fd5b806306c240d0146101915780630960b7fa146101b357806310c9d009146101f85780631857b3081461022657806326600ecb1461023b578063311e23af1461024e57600080fd5b3661018c57005b600080fd5b34801561019d57600080fd5b506101b16101ac366004611d25565b6104c5565b005b3480156101bf57600080fd5b506101db734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561020457600080fd5b50610218610213366004611d25565b610526565b6040519081526020016101ef565b34801561023257600080fd5b50610218600081565b6101b1610249366004611d5a565b610573565b34801561025a57600080fd5b50610218610269366004611d86565b6105e2565b34801561027a57600080fd5b50610218610289366004611d25565b61077a565b34801561029a57600080fd5b506101b16102a9366004611d25565b610842565b3480156102ba57600080fd5b50610218600181565b3480156102cf57600080fd5b506101db73d533a949740bb3306d119cc777fa900ba034cd5281565b3480156102f757600080fd5b506101db739d0464996170c6b9e75eed71c68b99ddedf279e881565b34801561031f57600080fd5b5061021861032e366004611d25565b6108a8565b34801561033f57600080fd5b506101b161034e366004611d9f565b61098e565b34801561035f57600080fd5b506101db7362b9c7356a2dc64a1969e19c23e4f579f9810aa781565b34801561038757600080fd5b506101b1610396366004611d9f565b610b3b565b3480156103a757600080fd5b506101b1610ca7565b3480156103bc57600080fd5b506103c5600181565b604051600f9190910b81526020016101ef565b3480156103e457600080fd5b506101db73b576491f1e6e5e62f1d8f26062ee822b40b0e0d481565b34801561040c57600080fd5b5061021861041b366004611d25565b610ff1565b34801561042c57600080fd5b506101db733fe65692bfcd0e6cf84cb1e7d24108e434a7587e81565b34801561045457600080fd5b506103c5600081565b34801561046957600080fd5b50610218610478366004611d25565b611047565b34801561048957600080fd5b506101db738301ae4fc9c624d1d396cbdaa1ed877821d7c51181565b3480156104b157600080fd5b506101b16104c0366004611d25565b61115b565b806001600160a01b0381166104f55760405162461bcd60e51b81526004016104ec90611df6565b60405180910390fd5b610515734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3330876111d0565b61052084848461123b565b50505050565b6000816001600160a01b03811661054f5760405162461bcd60e51b81526004016104ec90611df6565b600061055c8660006114ba565b90506105698185876114da565b9695505050505050565b806001600160a01b03811661059a5760405162461bcd60e51b81526004016104ec90611df6565b600034116105d25760405162461bcd60e51b8152602060048201526005602482015264063686561760dc1b60448201526064016104ec565b6105dd3484846114f1565b505050565b6000600260045414156106375760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104ec565b600260045561064582611509565b6040516370a0823160e01b81523060048201526000906106d69073bce0cf87f513102f22232436cca2ca49e815c3ac906370a082319060240160206040518083038186803b15801561069657600080fd5b505afa1580156106aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ce9190611e20565b600030611656565b600180546040516365b2489b60e01b815260048101929092526000602483018190526044830184905260648301529192506001600160a01b03909116906365b2489b90608401602060405180830381600087803b15801561073657600080fd5b505af115801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e9190611e20565b60016004559392505050565b6000816001600160a01b0381166107a35760405162461bcd60e51b81526004016104ec90611df6565b6107ac85611509565b6040516370a0823160e01b81523060048201526108399073bce0cf87f513102f22232436cca2ca49e815c3ac906370a082319060240160206040518083038186803b1580156107fa57600080fd5b505afa15801561080e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108329190611e20565b8585611656565b95945050505050565b806001600160a01b0381166108695760405162461bcd60e51b81526004016104ec90611df6565b61088973d533a949740bb3306d119cc777fa900ba034cd523330876111d0565b60006108948561170a565b90506108a18185856114f1565b5050505050565b6000816001600160a01b0381166108d15760405162461bcd60e51b81526004016104ec90611df6565b60006108dc866105e2565b90506108e8818661171d565b6040516370a0823160e01b815230600482015260009073dac17f958d2ee523a2206206994597c13d831ec7906370a082319060240160206040518083038186803b15801561093557600080fd5b505afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d9190611e20565b905061056973dac17f958d2ee523a2206206994597c13d831ec78683611780565b806001600160a01b0381166109b55760405162461bcd60e51b81526004016104ec90611df6565b6001600160a01b0384166109c857600080fd5b6109dd6001600160a01b0384163330896111d0565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110610a1257610a12611e4f565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610a5a57610a5a611e4f565b6001600160a01b039283166020918202929092010152610a7e9085168660006117b0565b610a926001600160a01b03851686896117b0565b6001600160a01b0385166318cbafe58860018430610ab04284611e65565b6040518663ffffffff1660e01b8152600401610ad0959493929190611ecf565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b269190810190611f0b565b50610b324787856114f1565b50505050505050565b806001600160a01b038116610b625760405162461bcd60e51b81526004016104ec90611df6565b6001600160a01b038416610b7557600080fd5b610b7e866105e2565b5060408051600280825260608201835260009260208301908036833701905050905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600081518110610bc857610bc8611e4f565b60200260200101906001600160a01b031690816001600160a01b0316815250508381600181518110610bfc57610bfc611e4f565b6001600160a01b0392831660209182029290920101528516637ff36ab547888487610c28426001611e65565b6040518663ffffffff1660e01b8152600401610c479493929190611fc9565b6000604051808303818588803b158015610c6057600080fd5b505af1158015610c74573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610c9d9190810190611f0b565b5050505050505050565b610cdb73bce0cf87f513102f22232436cca2ca49e815c3ac738659fc767cad6005de79af65dafe4249c57927af60006117b0565b610d1073bce0cf87f513102f22232436cca2ca49e815c3ac738659fc767cad6005de79af65dafe4249c57927af6000196117b0565b610d44734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b7335a398425d9f1029021a92bc3d2557d42c8588d760006117b0565b610d79734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b7335a398425d9f1029021a92bc3d2557d42c8588d76000196117b0565b610dad734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73b576491f1e6e5e62f1d8f26062ee822b40b0e0d460006117b0565b610de2734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73b576491f1e6e5e62f1d8f26062ee822b40b0e0d46000196117b0565b610e16734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73f3456e8061461e144b3f252e69dcd5b6070fdee060006117b0565b610e4b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73f3456e8061461e144b3f252e69dcd5b6070fdee06000196117b0565b610e7f73bce0cf87f513102f22232436cca2ca49e815c3ac73f3456e8061461e144b3f252e69dcd5b6070fdee060006117b0565b610eb473bce0cf87f513102f22232436cca2ca49e815c3ac73f3456e8061461e144b3f252e69dcd5b6070fdee06000196117b0565b610ee87362b9c7356a2dc64a1969e19c23e4f579f9810aa7739d0464996170c6b9e75eed71c68b99ddedf279e860006117b0565b610f1d7362b9c7356a2dc64a1969e19c23e4f579f9810aa7739d0464996170c6b9e75eed71c68b99ddedf279e86000196117b0565b610f5173d533a949740bb3306d119cc777fa900ba034cd52738301ae4fc9c624d1d396cbdaa1ed877821d7c51160006117b0565b610f8673d533a949740bb3306d119cc777fa900ba034cd52738301ae4fc9c624d1d396cbdaa1ed877821d7c5116000196117b0565b610fba73d533a949740bb3306d119cc777fa900ba034cd52739d0464996170c6b9e75eed71c68b99ddedf279e860006117b0565b610fef73d533a949740bb3306d119cc777fa900ba034cd52739d0464996170c6b9e75eed71c68b99ddedf279e86000196117b0565b565b6000816001600160a01b03811661101a5760405162461bcd60e51b81526004016104ec90611df6565b600061102686866114ba565b905061083973d533a949740bb3306d119cc777fa900ba034cd528583611780565b6000816001600160a01b0381166110705760405162461bcd60e51b81526004016104ec90611df6565b600061107b866105e2565b9050848110156110b85760405162461bcd60e51b8152602060048201526008602482015267736c69707061676560c01b60448201526064016104ec565b6000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611105576040519150601f19603f3d011682016040523d82523d6000602084013e61110a565b606091505b50509050806111515760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016104ec565b5095945050505050565b806001600160a01b0381166111825760405162461bcd60e51b81526004016104ec90611df6565b6111a27362b9c7356a2dc64a1969e19c23e4f579f9810aa73330876111d0565b60006111ae85306118d4565b905060006111bb8261170a565b90506111c88186866114f1565b505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526105209085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526118e2565b670de0b6b3a764000073f3456e8061461e144b3f252e69dcd5b6070fdee06001600160a01b03166386fc88d36040518163ffffffff1660e01b815260040160206040518083038186803b15801561129157600080fd5b505afa1580156112a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c99190611e20565b10156114015760405163ce7d650360e01b8152600060048201819052600160248301526044820185905260648201849052608482018190523060a48301529073f3456e8061461e144b3f252e69dcd5b6070fdee09063ce7d65039060c401602060405180830381600087803b15801561134157600080fd5b505af1158015611355573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113799190611e20565b600554604051636e553f6560e01b8152600481018390526001600160a01b038581166024830152929350911690636e553f6590604401602060405180830381600087803b1580156113c957600080fd5b505af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190611e20565b8183101561143c5760405162461bcd60e51b8152602060048201526008602482015267736c69707061676560c01b60448201526064016104ec565b604051636117ca0360e11b8152600481018490526001600160a01b038216602482015260016044820152600060648201527335a398425d9f1029021a92bc3d2557d42c8588d79063c22f940690608401600060405180830381600087803b1580156114a657600080fd5b505af1158015610b32573d6000803e3d6000fd5b6000806114c6846105e2565b90506114d281846119b4565b949350505050565b60006114e78484846119c0565b90505b9392505050565b60006114fc84611a10565b905061052081848461123b565b6005546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd90606401602060405180830381600087803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115939190611ffe565b6115c75760405162461bcd60e51b815260206004820152600560248201526432b93937b960d91b60448201526064016104ec565b600554604051635d043b2960e11b815260048101839052306024820181905260448201526001600160a01b039091169063ba08765290606401602060405180830381600087803b15801561161a57600080fd5b505af115801561162e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116529190611e20565b5050565b60405163ce7d650360e01b8152600160048201526000602482018190526044820185905260648201849052608482018190526001600160a01b03831660a48301529073f3456e8061461e144b3f252e69dcd5b6070fdee09063ce7d65039060c4015b602060405180830381600087803b1580156116d257600080fd5b505af11580156116e6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190611e20565b6000611717826000611a1d565b92915050565b60065460405163394747c560e01b815260026004820152600060248201526044810184905260648101839052600160848201526001600160a01b039091169063394747c590849060a4016000604051808303818588803b1580156114a657600080fd5b6040516001600160a01b0383166024820152604481018290526105dd90849063a9059cbb60e01b90606401611204565b8015806118395750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156117ff57600080fd5b505afa158015611813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118379190611e20565b155b6118a45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016104ec565b6040516001600160a01b0383166024820152604481018290526105dd90849063095ea7b360e01b90606401611204565b60006114ea83836000611ab4565b6000611937826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b049092919063ffffffff16565b8051909150156105dd57808060200190518101906119559190611ffe565b6105dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104ec565b60006114ea8383611b13565b60035460405163ddc1f59d60e01b81526000600482018190526001602483015260448201869052606482018490526001600160a01b0385811660848401529092169063ddc1f59d9060a4016116b8565b6000611717826000611b5c565b6002546040516365b2489b60e01b8152600160048201526000602482018190526044820185905260648201849052916001600160a01b0316906365b2489b9083906084015b6020604051808303818588803b158015611a7b57600080fd5b505af1158015611a8f573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906114ea9190611e20565b60035460405163ddc1f59d60e01b81526001600482015260006024820181905260448201869052606482018490526001600160a01b0385811660848401529092169063ddc1f59d9060a4016116b8565b60606114e78484600085611ba8565b6002546040516365b2489b60e01b8152600060048201819052600160248301526044820185905260648201849052916001600160a01b0316906365b2489b908590608401611a62565b600180546040516365b2489b60e01b8152600060048201819052602482019390935260448101859052606481018490526001600160a01b03909116906365b2489b908590608401611a62565b606082471015611c095760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104ec565b843b611c575760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104ec565b600080866001600160a01b03168587604051611c73919061204c565b60006040518083038185875af1925050503d8060008114611cb0576040519150601f19603f3d011682016040523d82523d6000602084013e611cb5565b606091505b5091509150611cc5828286611cd0565b979650505050505050565b60608315611cdf5750816114ea565b825115611cef5782518084602001fd5b8160405162461bcd60e51b81526004016104ec9190612068565b80356001600160a01b0381168114611d2057600080fd5b919050565b600080600060608486031215611d3a57600080fd5b8335925060208401359150611d5160408501611d09565b90509250925092565b60008060408385031215611d6d57600080fd5b82359150611d7d60208401611d09565b90509250929050565b600060208284031215611d9857600080fd5b5035919050565b600080600080600060a08688031215611db757600080fd5b8535945060208601359350611dce60408701611d09565b9250611ddc60608701611d09565b9150611dea60808701611d09565b90509295509295909350565b60208082526010908201526f496e76616c696420616464726573732160801b604082015260600190565b600060208284031215611e3257600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008219821115611e8657634e487b7160e01b600052601160045260246000fd5b500190565b600081518084526020808501945080840160005b83811015611ec45781516001600160a01b031687529582019590820190600101611e9f565b509495945050505050565b85815284602082015260a060408201526000611eee60a0830186611e8b565b6001600160a01b0394909416606083015250608001529392505050565b60006020808385031215611f1e57600080fd5b825167ffffffffffffffff80821115611f3657600080fd5b818501915085601f830112611f4a57600080fd5b815181811115611f5c57611f5c611e39565b8060051b604051601f19603f83011681018181108582111715611f8157611f81611e39565b604052918252848201925083810185019188831115611f9f57600080fd5b938501935b82851015611fbd57845184529385019392850192611fa4565b98975050505050505050565b848152608060208201526000611fe26080830186611e8b565b6001600160a01b03949094166040830152506060015292915050565b60006020828403121561201057600080fd5b815180151581146114ea57600080fd5b60005b8381101561203b578181015183820152602001612023565b838111156105205750506000910152565b6000825161205e818460208701612020565b9190910192915050565b6020815260008251806020840152612087816040850160208701612020565b601f01601f1916919091016040019291505056fea264697066735822122004eebab2183dab68f978e9f9ca16f322f4acc897dbc17a4e677549716c50c34164736f6c63430008090033

Deployed Bytecode

0x6080604052600436106101855760003560e01c806379e8aeeb116100d1578063a8d9693d1161008a578063d8697a5011610064578063d8697a5014610448578063dbc199d71461045d578063f1d5253e1461047d578063f521d3d3146104a557600080fd5b8063a8d9693d14610400578063ab6e25cd14610226578063c70eddff1461042057600080fd5b806379e8aeeb146103335780637ec5508a146103535780638702ca5c1461037b5780638757b15b1461039b57806393516676146103b0578063961deefe146103d857600080fd5b8063311e91061161013e578063657428a311610118578063657428a3146102c35780636acabc2e146102ae5780637506ceb9146102eb578063775491dc1461031357600080fd5b8063311e91061461026e57806331247e061461028e57806360c3a38c146102ae57600080fd5b806306c240d0146101915780630960b7fa146101b357806310c9d009146101f85780631857b3081461022657806326600ecb1461023b578063311e23af1461024e57600080fd5b3661018c57005b600080fd5b34801561019d57600080fd5b506101b16101ac366004611d25565b6104c5565b005b3480156101bf57600080fd5b506101db734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561020457600080fd5b50610218610213366004611d25565b610526565b6040519081526020016101ef565b34801561023257600080fd5b50610218600081565b6101b1610249366004611d5a565b610573565b34801561025a57600080fd5b50610218610269366004611d86565b6105e2565b34801561027a57600080fd5b50610218610289366004611d25565b61077a565b34801561029a57600080fd5b506101b16102a9366004611d25565b610842565b3480156102ba57600080fd5b50610218600181565b3480156102cf57600080fd5b506101db73d533a949740bb3306d119cc777fa900ba034cd5281565b3480156102f757600080fd5b506101db739d0464996170c6b9e75eed71c68b99ddedf279e881565b34801561031f57600080fd5b5061021861032e366004611d25565b6108a8565b34801561033f57600080fd5b506101b161034e366004611d9f565b61098e565b34801561035f57600080fd5b506101db7362b9c7356a2dc64a1969e19c23e4f579f9810aa781565b34801561038757600080fd5b506101b1610396366004611d9f565b610b3b565b3480156103a757600080fd5b506101b1610ca7565b3480156103bc57600080fd5b506103c5600181565b604051600f9190910b81526020016101ef565b3480156103e457600080fd5b506101db73b576491f1e6e5e62f1d8f26062ee822b40b0e0d481565b34801561040c57600080fd5b5061021861041b366004611d25565b610ff1565b34801561042c57600080fd5b506101db733fe65692bfcd0e6cf84cb1e7d24108e434a7587e81565b34801561045457600080fd5b506103c5600081565b34801561046957600080fd5b50610218610478366004611d25565b611047565b34801561048957600080fd5b506101db738301ae4fc9c624d1d396cbdaa1ed877821d7c51181565b3480156104b157600080fd5b506101b16104c0366004611d25565b61115b565b806001600160a01b0381166104f55760405162461bcd60e51b81526004016104ec90611df6565b60405180910390fd5b610515734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b3330876111d0565b61052084848461123b565b50505050565b6000816001600160a01b03811661054f5760405162461bcd60e51b81526004016104ec90611df6565b600061055c8660006114ba565b90506105698185876114da565b9695505050505050565b806001600160a01b03811661059a5760405162461bcd60e51b81526004016104ec90611df6565b600034116105d25760405162461bcd60e51b8152602060048201526005602482015264063686561760dc1b60448201526064016104ec565b6105dd3484846114f1565b505050565b6000600260045414156106375760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104ec565b600260045561064582611509565b6040516370a0823160e01b81523060048201526000906106d69073bce0cf87f513102f22232436cca2ca49e815c3ac906370a082319060240160206040518083038186803b15801561069657600080fd5b505afa1580156106aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ce9190611e20565b600030611656565b600180546040516365b2489b60e01b815260048101929092526000602483018190526044830184905260648301529192506001600160a01b03909116906365b2489b90608401602060405180830381600087803b15801561073657600080fd5b505af115801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e9190611e20565b60016004559392505050565b6000816001600160a01b0381166107a35760405162461bcd60e51b81526004016104ec90611df6565b6107ac85611509565b6040516370a0823160e01b81523060048201526108399073bce0cf87f513102f22232436cca2ca49e815c3ac906370a082319060240160206040518083038186803b1580156107fa57600080fd5b505afa15801561080e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108329190611e20565b8585611656565b95945050505050565b806001600160a01b0381166108695760405162461bcd60e51b81526004016104ec90611df6565b61088973d533a949740bb3306d119cc777fa900ba034cd523330876111d0565b60006108948561170a565b90506108a18185856114f1565b5050505050565b6000816001600160a01b0381166108d15760405162461bcd60e51b81526004016104ec90611df6565b60006108dc866105e2565b90506108e8818661171d565b6040516370a0823160e01b815230600482015260009073dac17f958d2ee523a2206206994597c13d831ec7906370a082319060240160206040518083038186803b15801561093557600080fd5b505afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d9190611e20565b905061056973dac17f958d2ee523a2206206994597c13d831ec78683611780565b806001600160a01b0381166109b55760405162461bcd60e51b81526004016104ec90611df6565b6001600160a01b0384166109c857600080fd5b6109dd6001600160a01b0384163330896111d0565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110610a1257610a12611e4f565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610a5a57610a5a611e4f565b6001600160a01b039283166020918202929092010152610a7e9085168660006117b0565b610a926001600160a01b03851686896117b0565b6001600160a01b0385166318cbafe58860018430610ab04284611e65565b6040518663ffffffff1660e01b8152600401610ad0959493929190611ecf565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b269190810190611f0b565b50610b324787856114f1565b50505050505050565b806001600160a01b038116610b625760405162461bcd60e51b81526004016104ec90611df6565b6001600160a01b038416610b7557600080fd5b610b7e866105e2565b5060408051600280825260608201835260009260208301908036833701905050905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600081518110610bc857610bc8611e4f565b60200260200101906001600160a01b031690816001600160a01b0316815250508381600181518110610bfc57610bfc611e4f565b6001600160a01b0392831660209182029290920101528516637ff36ab547888487610c28426001611e65565b6040518663ffffffff1660e01b8152600401610c479493929190611fc9565b6000604051808303818588803b158015610c6057600080fd5b505af1158015610c74573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610c9d9190810190611f0b565b5050505050505050565b610cdb73bce0cf87f513102f22232436cca2ca49e815c3ac738659fc767cad6005de79af65dafe4249c57927af60006117b0565b610d1073bce0cf87f513102f22232436cca2ca49e815c3ac738659fc767cad6005de79af65dafe4249c57927af6000196117b0565b610d44734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b7335a398425d9f1029021a92bc3d2557d42c8588d760006117b0565b610d79734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b7335a398425d9f1029021a92bc3d2557d42c8588d76000196117b0565b610dad734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73b576491f1e6e5e62f1d8f26062ee822b40b0e0d460006117b0565b610de2734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73b576491f1e6e5e62f1d8f26062ee822b40b0e0d46000196117b0565b610e16734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73f3456e8061461e144b3f252e69dcd5b6070fdee060006117b0565b610e4b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73f3456e8061461e144b3f252e69dcd5b6070fdee06000196117b0565b610e7f73bce0cf87f513102f22232436cca2ca49e815c3ac73f3456e8061461e144b3f252e69dcd5b6070fdee060006117b0565b610eb473bce0cf87f513102f22232436cca2ca49e815c3ac73f3456e8061461e144b3f252e69dcd5b6070fdee06000196117b0565b610ee87362b9c7356a2dc64a1969e19c23e4f579f9810aa7739d0464996170c6b9e75eed71c68b99ddedf279e860006117b0565b610f1d7362b9c7356a2dc64a1969e19c23e4f579f9810aa7739d0464996170c6b9e75eed71c68b99ddedf279e86000196117b0565b610f5173d533a949740bb3306d119cc777fa900ba034cd52738301ae4fc9c624d1d396cbdaa1ed877821d7c51160006117b0565b610f8673d533a949740bb3306d119cc777fa900ba034cd52738301ae4fc9c624d1d396cbdaa1ed877821d7c5116000196117b0565b610fba73d533a949740bb3306d119cc777fa900ba034cd52739d0464996170c6b9e75eed71c68b99ddedf279e860006117b0565b610fef73d533a949740bb3306d119cc777fa900ba034cd52739d0464996170c6b9e75eed71c68b99ddedf279e86000196117b0565b565b6000816001600160a01b03811661101a5760405162461bcd60e51b81526004016104ec90611df6565b600061102686866114ba565b905061083973d533a949740bb3306d119cc777fa900ba034cd528583611780565b6000816001600160a01b0381166110705760405162461bcd60e51b81526004016104ec90611df6565b600061107b866105e2565b9050848110156110b85760405162461bcd60e51b8152602060048201526008602482015267736c69707061676560c01b60448201526064016104ec565b6000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611105576040519150601f19603f3d011682016040523d82523d6000602084013e61110a565b606091505b50509050806111515760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016104ec565b5095945050505050565b806001600160a01b0381166111825760405162461bcd60e51b81526004016104ec90611df6565b6111a27362b9c7356a2dc64a1969e19c23e4f579f9810aa73330876111d0565b60006111ae85306118d4565b905060006111bb8261170a565b90506111c88186866114f1565b505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526105209085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526118e2565b670de0b6b3a764000073f3456e8061461e144b3f252e69dcd5b6070fdee06001600160a01b03166386fc88d36040518163ffffffff1660e01b815260040160206040518083038186803b15801561129157600080fd5b505afa1580156112a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c99190611e20565b10156114015760405163ce7d650360e01b8152600060048201819052600160248301526044820185905260648201849052608482018190523060a48301529073f3456e8061461e144b3f252e69dcd5b6070fdee09063ce7d65039060c401602060405180830381600087803b15801561134157600080fd5b505af1158015611355573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113799190611e20565b600554604051636e553f6560e01b8152600481018390526001600160a01b038581166024830152929350911690636e553f6590604401602060405180830381600087803b1580156113c957600080fd5b505af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190611e20565b8183101561143c5760405162461bcd60e51b8152602060048201526008602482015267736c69707061676560c01b60448201526064016104ec565b604051636117ca0360e11b8152600481018490526001600160a01b038216602482015260016044820152600060648201527335a398425d9f1029021a92bc3d2557d42c8588d79063c22f940690608401600060405180830381600087803b1580156114a657600080fd5b505af1158015610b32573d6000803e3d6000fd5b6000806114c6846105e2565b90506114d281846119b4565b949350505050565b60006114e78484846119c0565b90505b9392505050565b60006114fc84611a10565b905061052081848461123b565b6005546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd90606401602060405180830381600087803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115939190611ffe565b6115c75760405162461bcd60e51b815260206004820152600560248201526432b93937b960d91b60448201526064016104ec565b600554604051635d043b2960e11b815260048101839052306024820181905260448201526001600160a01b039091169063ba08765290606401602060405180830381600087803b15801561161a57600080fd5b505af115801561162e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116529190611e20565b5050565b60405163ce7d650360e01b8152600160048201526000602482018190526044820185905260648201849052608482018190526001600160a01b03831660a48301529073f3456e8061461e144b3f252e69dcd5b6070fdee09063ce7d65039060c4015b602060405180830381600087803b1580156116d257600080fd5b505af11580156116e6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190611e20565b6000611717826000611a1d565b92915050565b60065460405163394747c560e01b815260026004820152600060248201526044810184905260648101839052600160848201526001600160a01b039091169063394747c590849060a4016000604051808303818588803b1580156114a657600080fd5b6040516001600160a01b0383166024820152604481018290526105dd90849063a9059cbb60e01b90606401611204565b8015806118395750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156117ff57600080fd5b505afa158015611813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118379190611e20565b155b6118a45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016104ec565b6040516001600160a01b0383166024820152604481018290526105dd90849063095ea7b360e01b90606401611204565b60006114ea83836000611ab4565b6000611937826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b049092919063ffffffff16565b8051909150156105dd57808060200190518101906119559190611ffe565b6105dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104ec565b60006114ea8383611b13565b60035460405163ddc1f59d60e01b81526000600482018190526001602483015260448201869052606482018490526001600160a01b0385811660848401529092169063ddc1f59d9060a4016116b8565b6000611717826000611b5c565b6002546040516365b2489b60e01b8152600160048201526000602482018190526044820185905260648201849052916001600160a01b0316906365b2489b9083906084015b6020604051808303818588803b158015611a7b57600080fd5b505af1158015611a8f573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906114ea9190611e20565b60035460405163ddc1f59d60e01b81526001600482015260006024820181905260448201869052606482018490526001600160a01b0385811660848401529092169063ddc1f59d9060a4016116b8565b60606114e78484600085611ba8565b6002546040516365b2489b60e01b8152600060048201819052600160248301526044820185905260648201849052916001600160a01b0316906365b2489b908590608401611a62565b600180546040516365b2489b60e01b8152600060048201819052602482019390935260448101859052606481018490526001600160a01b03909116906365b2489b908590608401611a62565b606082471015611c095760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104ec565b843b611c575760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104ec565b600080866001600160a01b03168587604051611c73919061204c565b60006040518083038185875af1925050503d8060008114611cb0576040519150601f19603f3d011682016040523d82523d6000602084013e611cb5565b606091505b5091509150611cc5828286611cd0565b979650505050505050565b60608315611cdf5750816114ea565b825115611cef5782518084602001fd5b8160405162461bcd60e51b81526004016104ec9190612068565b80356001600160a01b0381168114611d2057600080fd5b919050565b600080600060608486031215611d3a57600080fd5b8335925060208401359150611d5160408501611d09565b90509250925092565b60008060408385031215611d6d57600080fd5b82359150611d7d60208401611d09565b90509250929050565b600060208284031215611d9857600080fd5b5035919050565b600080600080600060a08688031215611db757600080fd5b8535945060208601359350611dce60408701611d09565b9250611ddc60608701611d09565b9150611dea60808701611d09565b90509295509295909350565b60208082526010908201526f496e76616c696420616464726573732160801b604082015260600190565b600060208284031215611e3257600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008219821115611e8657634e487b7160e01b600052601160045260246000fd5b500190565b600081518084526020808501945080840160005b83811015611ec45781516001600160a01b031687529582019590820190600101611e9f565b509495945050505050565b85815284602082015260a060408201526000611eee60a0830186611e8b565b6001600160a01b0394909416606083015250608001529392505050565b60006020808385031215611f1e57600080fd5b825167ffffffffffffffff80821115611f3657600080fd5b818501915085601f830112611f4a57600080fd5b815181811115611f5c57611f5c611e39565b8060051b604051601f19603f83011681018181108582111715611f8157611f81611e39565b604052918252848201925083810185019188831115611f9f57600080fd5b938501935b82851015611fbd57845184529385019392850192611fa4565b98975050505050505050565b848152608060208201526000611fe26080830186611e8b565b6001600160a01b03949094166040830152506060015292915050565b60006020828403121561201057600080fd5b815180151581146114ea57600080fd5b60005b8381101561203b578181015183820152602001612023565b838111156105205750506000910152565b6000825161205e818460208701612020565b9190910192915050565b6020815260008251806020840152612087816040850160208701612020565b601f01601f1916919091016040019291505056fea264697066735822122004eebab2183dab68f978e9f9ca16f322f4acc897dbc17a4e677549716c50c34164736f6c63430008090033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.