ETH Price: $2,062.21 (+1.63%)

Contract

0xCD92f7bd79e5b0f7D0E20fE7eFDf3FafB70e3904
 

Overview

ETH Balance

0.1 ETH

Eth Value

$206.22 (@ $2,062.21/ETH)

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Cancel Order130171042021-08-13 13:31:341671 days ago1628861494IN
0xCD92f7bd...fB70e3904
0 ETH0.0018385337
Create Order130167662021-08-13 12:20:391671 days ago1628857239IN
0xCD92f7bd...fB70e3904
0 ETH0.0069730155
Create Order130167372021-08-13 12:12:491671 days ago1628856769IN
0xCD92f7bd...fB70e3904
0 ETH0.0057870542.93956891
Create Order130166702021-08-13 11:55:591671 days ago1628855759IN
0xCD92f7bd...fB70e3904
0 ETH0.004391634.63902817
Create Order130166622021-08-13 11:54:281671 days ago1628855668IN
0xCD92f7bd...fB70e3904
0 ETH0.0060748840
Withdraw Fund130166602021-08-13 11:53:311671 days ago1628855611IN
0xCD92f7bd...fB70e3904
0 ETH0.0021372440
Start Automator130165252021-08-13 11:27:341671 days ago1628854054IN
0xCD92f7bd...fB70e3904
0 ETH0.0045395829.82372007

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
-130166602021-08-13 11:53:311671 days ago1628855611
0xCD92f7bd...fB70e3904
0.1 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GammaRedeemerV1

Compiler Version
v0.8.0+commit.c7dfd78e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

import {GammaOperator} from "./GammaOperator.sol";
import {IGammaRedeemerV1} from "./interfaces/IGammaRedeemerV1.sol";
import {IPokeMe} from "./interfaces/IPokeMe.sol";
import {ITaskTreasury} from "./interfaces/ITaskTreasury.sol";
import {IResolver} from "./interfaces/IResolver.sol";

/// @author Willy Shen
/// @title Gamma Automatic Redeemer
/// @notice An automatic redeemer for Gamma otoken holders and writers
contract GammaRedeemerV1 is IGammaRedeemerV1, GammaOperator {
    Order[] public orders;

    IPokeMe public automator;
    ITaskTreasury public automatorTreasury;
    bool public isAutomatorEnabled;

    // fee in 1/10.000: 1% = 100, 0.01% = 1
    uint256 public redeemFee = 50;
    uint256 public settleFee = 10;

    /**
     * @notice only automator or owner
     */
    modifier onlyAuthorized() {
        require(
            msg.sender == address(automator) || msg.sender == owner(),
            "GammaRedeemer::onlyAuthorized: Only automator or owner"
        );
        _;
    }

    constructor(
        address _gammaAddressBook,
        address _automator,
        address _automatorTreasury
    ) GammaOperator(_gammaAddressBook) {
        automator = IPokeMe(_automator);
        automatorTreasury = ITaskTreasury(_automatorTreasury);
        isAutomatorEnabled = false;
    }

    function startAutomator(address _resolver) public onlyOwner {
        require(!isAutomatorEnabled);
        isAutomatorEnabled = true;
        automator.createTask(
            address(this),
            bytes4(keccak256("processOrders(uint256[])")),
            _resolver,
            abi.encodeWithSelector(IResolver.getProcessableOrders.selector)
        );
    }

    function stopAutomator() public onlyOwner {
        require(isAutomatorEnabled);
        isAutomatorEnabled = false;
        automator.cancelTask(
            automator.getTaskId(
                address(this),
                address(this),
                bytes4(keccak256("processOrders(uint256[])"))
            )
        );
    }

    /**
     * @notice create automation order
     * @param _otoken the address of otoken (only holders)
     * @param _amount amount of otoken (only holders)
     * @param _vaultId the id of specific vault to settle (only writers)
     */
    function createOrder(
        address _otoken,
        uint256 _amount,
        uint256 _vaultId
    ) public override {
        uint256 fee;
        bool isSeller;
        if (_otoken == address(0)) {
            require(
                _amount == 0,
                "GammaRedeemer::createOrder: Amount must be 0 when creating settlement order"
            );
            fee = settleFee;
            isSeller = true;
        } else {
            require(
                isWhitelistedOtoken(_otoken),
                "GammaRedeemer::createOrder: Otoken not whitelisted"
            );
            fee = redeemFee;
        }

        uint256 orderId = orders.length;

        Order memory order;
        order.owner = msg.sender;
        order.otoken = _otoken;
        order.amount = _amount;
        order.vaultId = _vaultId;
        order.isSeller = isSeller;
        order.fee = fee;
        orders.push(order);

        emit OrderCreated(orderId, msg.sender, _otoken);
    }

    /**
     * @notice cancel automation order
     * @param _orderId the id of specific order to be cancelled
     */
    function cancelOrder(uint256 _orderId) public override {
        Order storage order = orders[_orderId];
        require(
            order.owner == msg.sender,
            "GammaRedeemer::cancelOrder: Sender is not order owner"
        );
        require(
            !order.finished,
            "GammaRedeemer::cancelOrder: Order is already finished"
        );

        order.finished = true;
        emit OrderFinished(_orderId, true);
    }

    /**
     * @notice check if processing order is profitable
     * @param _orderId the id of specific order to be processed
     * @return true if settling vault / redeeming returns more than 0 amount
     */
    function shouldProcessOrder(uint256 _orderId)
        public
        view
        override
        returns (bool)
    {
        Order memory order = orders[_orderId];
        if (order.finished) return false;

        if (order.isSeller) {
            bool shouldSettle = shouldSettleVault(order.owner, order.vaultId);
            if (!shouldSettle) return false;
        } else {
            bool shouldRedeem = shouldRedeemOtoken(
                order.owner,
                order.otoken,
                order.amount
            );
            if (!shouldRedeem) return false;
        }

        return true;
    }

    /**
     * @notice process an order
     * @dev only automator allowed
     * @param _orderId the id of specific order to process
     */
    function processOrder(uint256 _orderId) public override onlyAuthorized {
        Order storage order = orders[_orderId];
        require(
            shouldProcessOrder(_orderId),
            "GammaRedeemer::processOrder: Order should not be processed"
        );
        order.finished = true;

        if (order.isSeller) {
            settleVault(order.owner, order.vaultId, order.fee);
        } else {
            redeemOtoken(order.owner, order.otoken, order.amount, order.fee);
        }

        emit OrderFinished(_orderId, false);
    }

    /**
     * @notice process multiple orders
     * @param _orderIds array of order ids to process
     */
    function processOrders(uint256[] calldata _orderIds) public override {
        for (uint256 i = 0; i < _orderIds.length; i++) {
            processOrder(_orderIds[i]);
        }
    }

    /**
     * @notice withdraw funds from automator
     * @param _token address of token to withdraw
     * @param _amount amount of token to withdraw
     */
    function withdrawFund(address _token, uint256 _amount) public onlyOwner {
        automatorTreasury.withdrawFunds(payable(this), _token, _amount);
    }

    function setAutomator(address _automator) public onlyOwner {
        automator = IPokeMe(_automator);
    }

    function setAutomatorTreasury(address _automatorTreasury) public onlyOwner {
        automatorTreasury = ITaskTreasury(_automatorTreasury);
    }

    function setRedeemFee(uint256 _redeemFee) public onlyOwner {
        redeemFee = _redeemFee;
    }

    function setSettleFee(uint256 _settleFee) public onlyOwner {
        settleFee = _settleFee;
    }

    function getOrdersLength() public view override returns (uint256) {
        return orders.length;
    }

    function getOrders() public view override returns (Order[] memory) {
        return orders;
    }

    function getOrder(uint256 _orderId)
        public
        view
        override
        returns (Order memory)
    {
        return orders[_orderId];
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

import {IAddressBook} from "./interfaces/IAddressBook.sol";
import {IGammaController} from "./interfaces/IGammaController.sol";
import {IWhitelist} from "./interfaces/IWhitelist.sol";
import {IMarginCalculator} from "./interfaces/IMarginCalculator.sol";
import {Actions} from "./external/OpynActions.sol";
import {MarginVault} from "./external/OpynVault.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IOtoken} from "./interfaces/IOtoken.sol";

/// @author Willy Shen
/// @title Gamma Operator
/// @notice Opyn Gamma protocol adapter for redeeming otokens and settling vaults
contract GammaOperator is Ownable {
    using SafeERC20 for IERC20;

    // Gamma Protocol contracts
    IAddressBook public addressBook;
    IGammaController public controller;
    IWhitelist public whitelist;
    IMarginCalculator public calculator;

    /**
     * @dev fetch Gamma contracts from address book
     * @param _addressBook Gamma Address Book address
     */
    constructor(address _addressBook) {
        setAddressBook(_addressBook);
        refreshConfig();
    }

    /**
     * @notice redeem otoken on behalf of user
     * @param _owner owner address
     * @param _otoken otoken address
     * @param _amount amount of otoken
     * @param _fee fee in 1/10.000
     */
    function redeemOtoken(
        address _owner,
        address _otoken,
        uint256 _amount,
        uint256 _fee
    ) internal {
        uint256 actualAmount = getRedeemableAmount(_owner, _otoken, _amount);

        IERC20(_otoken).safeTransferFrom(_owner, address(this), actualAmount);

        Actions.ActionArgs memory action;
        action.actionType = Actions.ActionType.Redeem;
        action.secondAddress = address(this);
        action.asset = _otoken;
        action.amount = _amount;

        Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](1);
        actions[0] = action;

        IERC20 collateral = IERC20(IOtoken(_otoken).collateralAsset());
        uint256 startAmount = collateral.balanceOf(address(this));

        controller.operate(actions);

        uint256 endAmount = collateral.balanceOf(address(this));
        uint256 difference = endAmount - startAmount;
        uint256 finalAmount = difference - ((_fee * difference) / 10000);
        collateral.safeTransfer(_owner, finalAmount);
    }

    /**
     * @notice settle vault on behalf of user
     * @param _owner owner address
     * @param _vaultId vaultId to settle
     * @param _fee fee in 1/10.000
     */
    function settleVault(
        address _owner,
        uint256 _vaultId,
        uint256 _fee
    ) internal {
        Actions.ActionArgs memory action;
        action.actionType = Actions.ActionType.SettleVault;
        action.owner = _owner;
        action.vaultId = _vaultId;
        action.secondAddress = address(this);

        Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](1);
        actions[0] = action;
        (MarginVault.Vault memory vault, , ) = getVaultWithDetails(
            _owner,
            _vaultId
        );
        address otoken = getVaultOtoken(vault);

        IERC20 collateral = IERC20(IOtoken(otoken).collateralAsset());
        uint256 startAmount = collateral.balanceOf(address(this));

        controller.operate(actions);

        uint256 endAmount = collateral.balanceOf(address(this));
        uint256 difference = endAmount - startAmount;
        uint256 finalAmount = difference - ((_fee * difference) / 10000);
        collateral.safeTransfer(_owner, finalAmount);
    }

    /**
     * @notice return if otoken should be redeemed
     * @param _owner owner address
     * @param _otoken otoken address
     * @param _amount amount of otoken
     * @return true if otoken has expired and payout is greater than zero
     */
    function shouldRedeemOtoken(
        address _owner,
        address _otoken,
        uint256 _amount
    ) public view returns (bool) {
        uint256 actualAmount = getRedeemableAmount(_owner, _otoken, _amount);
        try this.getRedeemPayout(_otoken, actualAmount) returns (
            uint256 payout
        ) {
            if (payout == 0) return false;
        } catch {
            return false;
        }

        return true;
    }

    /**
     * @notice return if vault should be settled
     * @param _owner owner address
     * @param _vaultId vaultId to settle
     * @return true if vault can be settled, contract is operator of owner,
     *          and excess collateral is greater than zero
     */
    function shouldSettleVault(address _owner, uint256 _vaultId)
        public
        view
        returns (bool)
    {
        (
            MarginVault.Vault memory vault,
            uint256 typeVault,

        ) = getVaultWithDetails(_owner, _vaultId);

        (uint256 payout, bool isValidVault) = getExcessCollateral(
            vault,
            typeVault
        );
        if (!isValidVault || payout == 0) return false;

        return true;
    }

    /**
     * @notice set Gamma Address Book
     * @param _address Address Book address
     */
    function setAddressBook(address _address) public onlyOwner {
        require(
            _address != address(0),
            "GammaOperator::setAddressBook: Address must not be zero"
        );
        addressBook = IAddressBook(_address);
    }

    /**
     * @notice transfer operator profit
     * @param _token address token to transfer
     * @param _amount amount of token to transfer
     * @param _to transfer destination
     */
    function harvest(
        address _token,
        uint256 _amount,
        address _to
    ) public onlyOwner {
        if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
            (bool success, ) = _to.call{value: _amount}("");
            require(success, "GammaOperator::harvest: ETH transfer failed");
        } else {
            IERC20(_token).safeTransfer(_to, _amount);
        }
    }

    /**
     * @notice refresh Gamma contracts' addresses
     */
    function refreshConfig() public {
        address _controller = addressBook.getController();
        controller = IGammaController(_controller);

        address _whitelist = addressBook.getWhitelist();
        whitelist = IWhitelist(_whitelist);

        address _calculator = addressBook.getMarginCalculator();
        calculator = IMarginCalculator(_calculator);
    }

    /**
     * @notice get an oToken's payout in the collateral asset
     * @param _otoken otoken address
     * @param _amount amount of otoken to redeem
     */
    function getRedeemPayout(address _otoken, uint256 _amount)
        public
        view
        returns (uint256)
    {
        return controller.getPayout(_otoken, _amount);
    }

    /**
     * @notice get amount of otoken that can be redeemed
     * @param _owner owner address
     * @param _otoken otoken address
     * @param _amount amount of otoken
     * @return amount of otoken the contract can transferFrom owner
     */
    function getRedeemableAmount(
        address _owner,
        address _otoken,
        uint256 _amount
    ) public view returns (uint256) {
        uint256 ownerBalance = IERC20(_otoken).balanceOf(_owner);
        uint256 allowance = IERC20(_otoken).allowance(_owner, address(this));
        uint256 spendable = min(ownerBalance, allowance);
        return min(_amount, spendable);
    }

    /**
     * @notice return details of a specific vault
     * @param _owner owner address
     * @param _vaultId vaultId
     * @return vault struct and vault type and the latest timestamp when the vault was updated
     */
    function getVaultWithDetails(address _owner, uint256 _vaultId)
        public
        view
        returns (
            MarginVault.Vault memory,
            uint256,
            uint256
        )
    {
        return controller.getVaultWithDetails(_owner, _vaultId);
    }

    /**
     * @notice return the otoken from specific vault
     * @param _vault vault struct
     * @return otoken address
     */
    function getVaultOtoken(MarginVault.Vault memory _vault)
        public
        pure
        returns (address)
    {
        bool hasShort = isNotEmpty(_vault.shortOtokens);
        bool hasLong = isNotEmpty(_vault.longOtokens);

        assert(hasShort || hasLong);

        return hasShort ? _vault.shortOtokens[0] : _vault.longOtokens[0];
    }

    /**
     * @notice return amount of collateral that can be removed from a vault
     * @param _vault vault struct
     * @param _typeVault vault type
     * @return excess amount and true if excess is greater than zero
     */
    function getExcessCollateral(
        MarginVault.Vault memory _vault,
        uint256 _typeVault
    ) public view returns (uint256, bool) {
        return calculator.getExcessCollateral(_vault, _typeVault);
    }

    /**
     * @notice return if otoken is ready to be settled
     * @param _otoken otoken address
     * @return true if settlement is allowed
     */
    function isSettlementAllowed(address _otoken) public view returns (bool) {
        return controller.isSettlementAllowed(_otoken);
    }

    /**
     * @notice return if this contract is Gamma operator of an address
     * @param _owner owner address
     * @return true if address(this) is operator of _owner
     */
    function isOperatorOf(address _owner) public view returns (bool) {
        return controller.isOperator(_owner, address(this));
    }

    /**
     * @notice return if otoken is whitelisted on Gamma
     * @param _otoken otoken address
     * @return true if isWhitelistedOtoken returns true for _otoken
     */
    function isWhitelistedOtoken(address _otoken) public view returns (bool) {
        return whitelist.isWhitelistedOtoken(_otoken);
    }

    /**
     * @param _otoken otoken address
     * @return true if otoken has expired and settlement is allowed
     */
    function hasExpiredAndSettlementAllowed(address _otoken)
        public
        view
        returns (bool)
    {
        bool hasExpired = block.timestamp >= IOtoken(_otoken).expiryTimestamp();
        if (!hasExpired) return false;

        bool isAllowed = isSettlementAllowed(_otoken);
        if (!isAllowed) return false;

        return true;
    }

    /**
     * @notice return if specific vault exist
     * @param _owner owner address
     * @param _vaultId vaultId to check
     * @return true if vault exist for owner
     */
    function isValidVaultId(address _owner, uint256 _vaultId)
        public
        view
        returns (bool)
    {
        uint256 vaultCounter = controller.getAccountVaultCounter(_owner);
        return ((_vaultId > 0) && (_vaultId <= vaultCounter));
    }

    /**
     * @notice return if array is not empty
     * @param _array array of address to check
     * @return true if array length is grreater than zero & first element isn't address zero
     */
    function isNotEmpty(address[] memory _array) private pure returns (bool) {
        return (_array.length > 0) && (_array[0] != address(0));
    }

    /**
     * @notice return the lowest number
     * @param a first number
     * @param b second number
     * @return the lowest uint256
     */
    function min(uint256 a, uint256 b) private pure returns (uint256) {
        return a > b ? b : a;
    }

    receive() external payable {}
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

interface IGammaRedeemerV1 {
    struct Order {
        // address of user
        address owner;
        // address of otoken to redeem
        address otoken;
        // amount of otoken to redeem
        uint256 amount;
        // vaultId of vault to settle
        uint256 vaultId;
        // true if settle vault order, else redeem otoken
        bool isSeller;
        // convert proceed to ETH, currently unused
        bool toETH;
        // fee in 1/10.000
        uint256 fee;
        // true if order is already processed
        bool finished;
    }

    event OrderCreated(
        uint256 indexed orderId,
        address indexed owner,
        address indexed otoken
    );
    event OrderFinished(uint256 indexed orderId, bool indexed cancelled);

    function createOrder(
        address _otoken,
        uint256 _amount,
        uint256 _vaultId
    ) external;

    function cancelOrder(uint256 _orderId) external;

    function shouldProcessOrder(uint256 _orderId) external view returns (bool);

    function processOrder(uint256 _orderId) external;

    function processOrders(uint256[] calldata _orderIds) external;

    function getOrdersLength() external view returns (uint256);

    function getOrders() external view returns (Order[] memory);

    function getOrder(uint256 _orderId) external view returns (Order memory);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface IPokeMe {
    function createTask(
        address _execAddress,
        bytes4 _execSelector,
        address _resolverAddress,
        bytes calldata _resolverData
    ) external;

    function cancelTask(bytes32 _taskId) external;

    // function withdrawFunds(uint256 _amount) external;

    function getTaskId(
        address _taskCreator,
        address _execAddress,
        bytes4 _selector
    ) external pure returns (bytes32);
}

File 5 of 18 : ITaskTreasury.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface ITaskTreasury {
    function withdrawFunds(
        address payable _receiver,
        address _token,
        uint256 _amount
    ) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface IResolver {
    function getProcessableOrders()
        external
        returns (bool canExec, bytes memory execPayload);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface IAddressBook {
    function getOtokenImpl() external view returns (address);

    function getOtokenFactory() external view returns (address);

    function getWhitelist() external view returns (address);

    function getController() external view returns (address);

    function getOracle() external view returns (address);

    function getMarginPool() external view returns (address);

    function getMarginCalculator() external view returns (address);

    function getLiquidationManager() external view returns (address);

    function getAddress(bytes32 _id) external view returns (address);

    /* Setters */

    function setOtokenImpl(address _otokenImpl) external;

    function setOtokenFactory(address _factory) external;

    function setOracleImpl(address _otokenImpl) external;

    function setWhitelist(address _whitelist) external;

    function setController(address _controller) external;

    function setMarginPool(address _marginPool) external;

    function setMarginCalculator(address _calculator) external;

    function setLiquidationManager(address _liquidationManager) external;

    function setAddress(bytes32 _id, address _newImpl) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

import {Actions} from "../external/OpynActions.sol";
import {MarginVault} from "../external/OpynVault.sol";

interface IGammaController {
    function operate(Actions.ActionArgs[] memory _actions) external;

    function isSettlementAllowed(address _otoken) external view returns (bool);

    function isOperator(address _owner, address _operator)
        external
        view
        returns (bool);

    function getPayout(address _otoken, uint256 _amount)
        external
        view
        returns (uint256);

    function getVaultWithDetails(address _owner, uint256 _vaultId)
        external
        view
        returns (
            MarginVault.Vault memory,
            uint256,
            uint256
        );

    function getAccountVaultCounter(address _accountOwner)
        external
        view
        returns (uint256);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface IWhitelist {
    function isWhitelistedOtoken(address _otoken) external view returns (bool);
}

File 10 of 18 : IMarginCalculator.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

import {MarginVault} from "../external/OpynVault.sol";

interface IMarginCalculator {
    function getExcessCollateral(
        MarginVault.Vault calldata _vault,
        uint256 _vaultType
    ) external view returns (uint256 netValue, bool isExcess);
}

/**
 * SPDX-License-Identifier: UNLICENSED
 */
pragma solidity 0.8.0;

/**
 * @title Actions
 * @author Opyn Team
 * @notice A library that provides a ActionArgs struct, sub types of Action structs, and functions to parse ActionArgs into specific Actions.
 */
library Actions {
    // possible actions that can be performed
    enum ActionType {
        OpenVault,
        MintShortOption,
        BurnShortOption,
        DepositLongOption,
        WithdrawLongOption,
        DepositCollateral,
        WithdrawCollateral,
        SettleVault,
        Redeem,
        Call,
        Liquidate
    }

    struct ActionArgs {
        // type of action that is being performed on the system
        ActionType actionType;
        // address of the account owner
        address owner;
        // address which we move assets from or to (depending on the action type)
        address secondAddress;
        // asset that is to be transfered
        address asset;
        // index of the vault that is to be modified (if any)
        uint256 vaultId;
        // amount of asset that is to be transfered
        uint256 amount;
        // each vault can hold multiple short / long / collateral assets but we are restricting the scope to only 1 of each in this version
        // in future versions this would be the index of the short / long / collateral asset that needs to be modified
        uint256 index;
        // any other data that needs to be passed in for arbitrary function calls
        bytes data;
    }

    struct MintArgs {
        // address of the account owner
        address owner;
        // index of the vault from which the asset will be minted
        uint256 vaultId;
        // address to which we transfer the minted oTokens
        address to;
        // oToken that is to be minted
        address otoken;
        // each vault can hold multiple short / long / collateral assets but we are restricting the scope to only 1 of each in this version
        // in future versions this would be the index of the short / long / collateral asset that needs to be modified
        uint256 index;
        // amount of oTokens that is to be minted
        uint256 amount;
    }

    struct BurnArgs {
        // address of the account owner
        address owner;
        // index of the vault from which the oToken will be burned
        uint256 vaultId;
        // address from which we transfer the oTokens
        address from;
        // oToken that is to be burned
        address otoken;
        // each vault can hold multiple short / long / collateral assets but we are restricting the scope to only 1 of each in this version
        // in future versions this would be the index of the short / long / collateral asset that needs to be modified
        uint256 index;
        // amount of oTokens that is to be burned
        uint256 amount;
    }

    struct OpenVaultArgs {
        // address of the account owner
        address owner;
        // vault id to create
        uint256 vaultId;
        // vault type, 0 for spread/max loss and 1 for naked margin vault
        uint256 vaultType;
    }

    struct DepositArgs {
        // address of the account owner
        address owner;
        // index of the vault to which the asset will be added
        uint256 vaultId;
        // address from which we transfer the asset
        address from;
        // asset that is to be deposited
        address asset;
        // each vault can hold multiple short / long / collateral assets but we are restricting the scope to only 1 of each in this version
        // in future versions this would be the index of the short / long / collateral asset that needs to be modified
        uint256 index;
        // amount of asset that is to be deposited
        uint256 amount;
    }

    struct RedeemArgs {
        // address to which we pay out the oToken proceeds
        address receiver;
        // oToken that is to be redeemed
        address otoken;
        // amount of oTokens that is to be redeemed
        uint256 amount;
    }

    struct WithdrawArgs {
        // address of the account owner
        address owner;
        // index of the vault from which the asset will be withdrawn
        uint256 vaultId;
        // address to which we transfer the asset
        address to;
        // asset that is to be withdrawn
        address asset;
        // each vault can hold multiple short / long / collateral assets but we are restricting the scope to only 1 of each in this version
        // in future versions this would be the index of the short / long / collateral asset that needs to be modified
        uint256 index;
        // amount of asset that is to be withdrawn
        uint256 amount;
    }

    struct SettleVaultArgs {
        // address of the account owner
        address owner;
        // index of the vault to which is to be settled
        uint256 vaultId;
        // address to which we transfer the remaining collateral
        address to;
    }

    struct LiquidateArgs {
        // address of the vault owner to liquidate
        address owner;
        // address of the liquidated collateral receiver
        address receiver;
        // vault id to liquidate
        uint256 vaultId;
        // amount of debt(otoken) to repay
        uint256 amount;
        // chainlink round id
        uint256 roundId;
    }

    struct CallArgs {
        // address of the callee contract
        address callee;
        // data field for external calls
        bytes data;
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for an open vault action
     * @param _args general action arguments structure
     * @return arguments for a open vault action
     */
    function _parseOpenVaultArgs(ActionArgs memory _args)
        internal
        pure
        returns (OpenVaultArgs memory)
    {
        require(
            _args.actionType == ActionType.OpenVault,
            "Actions: can only parse arguments for open vault actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot open vault for an invalid account"
        );

        // if not _args.data included, vault type will be 0 by default
        uint256 vaultType;

        if (_args.data.length == 32) {
            // decode vault type from _args.data
            vaultType = abi.decode(_args.data, (uint256));
        }

        // for now we only have 2 vault types
        require(
            vaultType < 2,
            "Actions: cannot open vault with an invalid type"
        );

        return
            OpenVaultArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                vaultType: vaultType
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a mint action
     * @param _args general action arguments structure
     * @return arguments for a mint action
     */
    function _parseMintArgs(ActionArgs memory _args)
        internal
        pure
        returns (MintArgs memory)
    {
        require(
            _args.actionType == ActionType.MintShortOption,
            "Actions: can only parse arguments for mint actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot mint from an invalid account"
        );

        return
            MintArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                to: _args.secondAddress,
                otoken: _args.asset,
                index: _args.index,
                amount: _args.amount
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a burn action
     * @param _args general action arguments structure
     * @return arguments for a burn action
     */
    function _parseBurnArgs(ActionArgs memory _args)
        internal
        pure
        returns (BurnArgs memory)
    {
        require(
            _args.actionType == ActionType.BurnShortOption,
            "Actions: can only parse arguments for burn actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot burn from an invalid account"
        );

        return
            BurnArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                from: _args.secondAddress,
                otoken: _args.asset,
                index: _args.index,
                amount: _args.amount
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a deposit action
     * @param _args general action arguments structure
     * @return arguments for a deposit action
     */
    function _parseDepositArgs(ActionArgs memory _args)
        internal
        pure
        returns (DepositArgs memory)
    {
        require(
            (_args.actionType == ActionType.DepositLongOption) ||
                (_args.actionType == ActionType.DepositCollateral),
            "Actions: can only parse arguments for deposit actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot deposit to an invalid account"
        );

        return
            DepositArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                from: _args.secondAddress,
                asset: _args.asset,
                index: _args.index,
                amount: _args.amount
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a withdraw action
     * @param _args general action arguments structure
     * @return arguments for a withdraw action
     */
    function _parseWithdrawArgs(ActionArgs memory _args)
        internal
        pure
        returns (WithdrawArgs memory)
    {
        require(
            (_args.actionType == ActionType.WithdrawLongOption) ||
                (_args.actionType == ActionType.WithdrawCollateral),
            "Actions: can only parse arguments for withdraw actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot withdraw from an invalid account"
        );
        require(
            _args.secondAddress != address(0),
            "Actions: cannot withdraw to an invalid account"
        );

        return
            WithdrawArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                to: _args.secondAddress,
                asset: _args.asset,
                index: _args.index,
                amount: _args.amount
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for an redeem action
     * @param _args general action arguments structure
     * @return arguments for a redeem action
     */
    function _parseRedeemArgs(ActionArgs memory _args)
        internal
        pure
        returns (RedeemArgs memory)
    {
        require(
            _args.actionType == ActionType.Redeem,
            "Actions: can only parse arguments for redeem actions"
        );
        require(
            _args.secondAddress != address(0),
            "Actions: cannot redeem to an invalid account"
        );

        return
            RedeemArgs({
                receiver: _args.secondAddress,
                otoken: _args.asset,
                amount: _args.amount
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a settle vault action
     * @param _args general action arguments structure
     * @return arguments for a settle vault action
     */
    function _parseSettleVaultArgs(ActionArgs memory _args)
        internal
        pure
        returns (SettleVaultArgs memory)
    {
        require(
            _args.actionType == ActionType.SettleVault,
            "Actions: can only parse arguments for settle vault actions"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot settle vault for an invalid account"
        );
        require(
            _args.secondAddress != address(0),
            "Actions: cannot withdraw payout to an invalid account"
        );

        return
            SettleVaultArgs({
                owner: _args.owner,
                vaultId: _args.vaultId,
                to: _args.secondAddress
            });
    }

    function _parseLiquidateArgs(ActionArgs memory _args)
        internal
        pure
        returns (LiquidateArgs memory)
    {
        require(
            _args.actionType == ActionType.Liquidate,
            "Actions: can only parse arguments for liquidate action"
        );
        require(
            _args.owner != address(0),
            "Actions: cannot liquidate vault for an invalid account owner"
        );
        require(
            _args.secondAddress != address(0),
            "Actions: cannot send collateral to an invalid account"
        );
        require(
            _args.data.length == 32,
            "Actions: cannot parse liquidate action with no round id"
        );

        // decode chainlink round id from _args.data
        uint256 roundId = abi.decode(_args.data, (uint256));

        return
            LiquidateArgs({
                owner: _args.owner,
                receiver: _args.secondAddress,
                vaultId: _args.vaultId,
                amount: _args.amount,
                roundId: roundId
            });
    }

    /**
     * @notice parses the passed in action arguments to get the arguments for a call action
     * @param _args general action arguments structure
     * @return arguments for a call action
     */
    function _parseCallArgs(ActionArgs memory _args)
        internal
        pure
        returns (CallArgs memory)
    {
        require(
            _args.actionType == ActionType.Call,
            "Actions: can only parse arguments for call actions"
        );
        require(
            _args.secondAddress != address(0),
            "Actions: target address cannot be address(0)"
        );

        return CallArgs({callee: _args.secondAddress, data: _args.data});
    }
}

File 12 of 18 : OpynVault.sol
/**
 * SPDX-License-Identifier: UNLICENSED
 */
pragma solidity 0.8.0;

/**
 * @title MarginVault
 * @author Opyn Team
 * @notice A library that provides the Controller with a Vault struct and the functions that manipulate vaults.
 * Vaults describe discrete position combinations of long options, short options, and collateral assets that a user can have.
 */
library MarginVault {
    // vault is a struct of 6 arrays that describe a position a user has, a user can have multiple vaults.
    struct Vault {
        // addresses of oTokens a user has shorted (i.e. written) against this vault
        address[] shortOtokens;
        // addresses of oTokens a user has bought and deposited in this vault
        // user can be long oTokens without opening a vault (e.g. by buying on a DEX)
        // generally, long oTokens will be 'deposited' in vaults to act as collateral in order to write oTokens against (i.e. in spreads)
        address[] longOtokens;
        // addresses of other ERC-20s a user has deposited as collateral in this vault
        address[] collateralAssets;
        // quantity of oTokens minted/written for each oToken address in shortOtokens
        uint256[] shortAmounts;
        // quantity of oTokens owned and held in the vault for each oToken address in longOtokens
        uint256[] longAmounts;
        // quantity of ERC-20 deposited as collateral in the vault for each ERC-20 address in collateralAssets
        uint256[] collateralAmounts;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/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'
        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
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

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

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

interface IOtoken {
    function addressBook() external view returns (address);

    function underlyingAsset() external view returns (address);

    function strikeAsset() external view returns (address);

    function collateralAsset() external view returns (address);

    function strikePrice() external view returns (uint256);

    function expiryTimestamp() external view returns (uint256);

    function isPut() external view returns (bool);

    function init(
        address _addressBook,
        address _underlyingAsset,
        address _strikeAsset,
        address _collateralAsset,
        uint256 _strikePrice,
        uint256 _expiry,
        bool _isPut
    ) external;

    function getOtokenDetails()
        external
        view
        returns (
            address,
            address,
            address,
            uint256,
            uint256,
            bool
        );

    function mintOtoken(address account, uint256 amount) external;

    function burnOtoken(address account, uint256 amount) external;
}

// 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) {
        return msg.data;
    }
}

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

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

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

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

        (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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_gammaAddressBook","type":"address"},{"internalType":"address","name":"_automator","type":"address"},{"internalType":"address","name":"_automatorTreasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"otoken","type":"address"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"cancelled","type":"bool"}],"name":"OrderFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"addressBook","outputs":[{"internalType":"contract IAddressBook","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automator","outputs":[{"internalType":"contract IPokeMe","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automatorTreasury","outputs":[{"internalType":"contract ITaskTreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculator","outputs":[{"internalType":"contract IMarginCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IGammaController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_otoken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"createOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"shortOtokens","type":"address[]"},{"internalType":"address[]","name":"longOtokens","type":"address[]"},{"internalType":"address[]","name":"collateralAssets","type":"address[]"},{"internalType":"uint256[]","name":"shortAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"longAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"collateralAmounts","type":"uint256[]"}],"internalType":"struct MarginVault.Vault","name":"_vault","type":"tuple"},{"internalType":"uint256","name":"_typeVault","type":"uint256"}],"name":"getExcessCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"getOrder","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"otoken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"bool","name":"isSeller","type":"bool"},{"internalType":"bool","name":"toETH","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bool","name":"finished","type":"bool"}],"internalType":"struct IGammaRedeemerV1.Order","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrders","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"otoken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"bool","name":"isSeller","type":"bool"},{"internalType":"bool","name":"toETH","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bool","name":"finished","type":"bool"}],"internalType":"struct IGammaRedeemerV1.Order[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrdersLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_otoken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getRedeemPayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_otoken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getRedeemableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"shortOtokens","type":"address[]"},{"internalType":"address[]","name":"longOtokens","type":"address[]"},{"internalType":"address[]","name":"collateralAssets","type":"address[]"},{"internalType":"uint256[]","name":"shortAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"longAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"collateralAmounts","type":"uint256[]"}],"internalType":"struct MarginVault.Vault","name":"_vault","type":"tuple"}],"name":"getVaultOtoken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"getVaultWithDetails","outputs":[{"components":[{"internalType":"address[]","name":"shortOtokens","type":"address[]"},{"internalType":"address[]","name":"longOtokens","type":"address[]"},{"internalType":"address[]","name":"collateralAssets","type":"address[]"},{"internalType":"uint256[]","name":"shortAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"longAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"collateralAmounts","type":"uint256[]"}],"internalType":"struct MarginVault.Vault","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_otoken","type":"address"}],"name":"hasExpiredAndSettlementAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAutomatorEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"isOperatorOf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_otoken","type":"address"}],"name":"isSettlementAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"isValidVaultId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_otoken","type":"address"}],"name":"isWhitelistedOtoken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"orders","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"otoken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"bool","name":"isSeller","type":"bool"},{"internalType":"bool","name":"toETH","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bool","name":"finished","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"processOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_orderIds","type":"uint256[]"}],"name":"processOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refreshConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setAddressBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_automator","type":"address"}],"name":"setAutomator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_automatorTreasury","type":"address"}],"name":"setAutomatorTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_redeemFee","type":"uint256"}],"name":"setRedeemFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_settleFee","type":"uint256"}],"name":"setSettleFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"shouldProcessOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_otoken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"shouldRedeemOtoken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"shouldSettleVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_resolver","type":"address"}],"name":"startAutomator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopAutomator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelist","outputs":[{"internalType":"contract IWhitelist","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526032600855600a6009553480156200001b57600080fd5b5060405162003ce638038062003ce68339810160408190526200003e91620003c6565b82620000536200004d620000a4565b620000a8565b6200005e81620000f8565b6200006862000192565b50600680546001600160a01b03199081166001600160a01b039485161790915560078054909116919092161760ff60a01b1916905550620004a1565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b62000102620000a4565b6001600160a01b03166200011562000376565b6001600160a01b031614620001475760405162461bcd60e51b81526004016200013e906200040f565b60405180910390fd5b6001600160a01b038116620001705760405162461bcd60e51b81526004016200013e9062000444565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60015460408051633018205f60e01b815290516000926001600160a01b031691633018205f916004808301926020929190829003018186803b158015620001d857600080fd5b505afa158015620001ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002139190620003a2565b600280546001600160a01b0319166001600160a01b03838116919091179091556001546040805163d01f63f560e01b81529051939450600093919092169163d01f63f5916004808301926020929190829003018186803b1580156200027757600080fd5b505afa1580156200028c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b29190620003a2565b600380546001600160a01b0319166001600160a01b03838116919091179091556001546040805163cf28493f60e01b81529051939450600093919092169163cf28493f916004808301926020929190829003018186803b1580156200031657600080fd5b505afa1580156200032b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003519190620003a2565b600480546001600160a01b0319166001600160a01b0392909216919091179055505050565b6000546001600160a01b031690565b80516001600160a01b03811681146200039d57600080fd5b919050565b600060208284031215620003b4578081fd5b620003bf8262000385565b9392505050565b600080600060608486031215620003db578182fd5b620003e68462000385565b9250620003f66020850162000385565b9150620004066040850162000385565b90509250925092565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526037908201527f47616d6d614f70657261746f723a3a73657441646472657373426f6f6b3a204160408201527f646472657373206d757374206e6f74206265207a65726f000000000000000000606082015260800190565b61383580620004b16000396000f3fe6080604052600436106102605760003560e01c806392a1a2e711610144578063ce4905bc116100b6578063ec8daaf91161007a578063ec8daaf914610705578063f2fde38b1461071a578063f54ac2461461073a578063f5887cdd1461075a578063f77c47911461076f578063f7c8d2211461078457610267565b8063ce4905bc14610663578063d09ef24114610683578063e55107a0146106b0578063e723406c146106c5578063e7c5a6e8146106e557610267565b8063a85c38ef11610108578063a85c38ef1461058c578063acfee8ed146105c0578063c2a9a831146105e0578063c8daad3014610600578063cd43fbfb14610620578063ce3e39c01461064e57610267565b806392a1a2e7146104fe57806393e59dc114610513578063945ce2c414610528578063965fa21e146105485780639daafbe81461055d57610267565b806341929f0f116101dd578063715018a6116101a1578063715018a61461045f5780637c55ccb3146104745780638047c2fb1461048957806383781c10146104a9578063861e4e5b146104c95780638da5cb5b146104e957610267565b806341929f0f146103bf57806342ae6aba146103df57806345389e3f146103ff578063514fcac71461041f5780635d841af51461043f57610267565b80631cb78541116102245780631cb78541146103285780632c9d27ea1461033d5780632e2dc43e1461035d5780632e5187fb1461037f57806332f8e23e1461039f57610267565b806307c2e16c1461026c5780630b3448a81461029757806311946b98146102b9578063144c27ff146102e6578063182192d31461030857610267565b3661026757005b600080fd5b34801561027857600080fd5b506102816107a4565b60405161028e919061328d565b60405180910390f35b3480156102a357600080fd5b506102b76102b2366004612abd565b6107aa565b005b3480156102c557600080fd5b506102d96102d4366004612abd565b61083a565b60405161028e9190613282565b3480156102f257600080fd5b506102fb6108c3565b60405161028e9190613025565b34801561031457600080fd5b506102d9610323366004612e19565b6108d2565b34801561033457600080fd5b506102fb6109f7565b34801561034957600080fd5b50610281610358366004612af5565b610a06565b34801561036957600080fd5b50610372610b2e565b60405161028e9190613233565b34801561038b57600080fd5b506102b761039a366004612e19565b610bf5565b3480156103ab57600080fd5b506102b76103ba366004612e19565b610d35565b3480156103cb57600080fd5b506102b76103da366004612bd5565b610d79565b3480156103eb57600080fd5b506102d96103fa366004612abd565b610dca565b34801561040b57600080fd5b506102b761041a366004612abd565b610e79565b34801561042b57600080fd5b506102b761043a366004612e19565b610eda565b34801561044b57600080fd5b506102b761045a366004612e19565b610f9f565b34801561046b57600080fd5b506102b7610fe3565b34801561048057600080fd5b506102b761102e565b34801561049557600080fd5b506102d96104a4366004612b35565b611206565b3480156104b557600080fd5b506102d96104c4366004612b35565b6112a7565b3480156104d557600080fd5b506102b76104e4366004612abd565b6112f6565b3480156104f557600080fd5b506102fb61140f565b34801561050a57600080fd5b5061028161141e565b34801561051f57600080fd5b506102fb611424565b34801561053457600080fd5b506102d9610543366004612af5565b611433565b34801561055457600080fd5b506102816114db565b34801561056957600080fd5b5061057d610578366004612b35565b6114e1565b60405161028e9392919061369e565b34801561059857600080fd5b506105ac6105a7366004612e19565b611581565b60405161028e9897969594939291906130a4565b3480156105cc57600080fd5b506102b76105db366004612ba1565b6115eb565b3480156105ec57600080fd5b506102d96105fb366004612abd565b611837565b34801561060c57600080fd5b506102fb61061b366004612c76565b61186a565b34801561062c57600080fd5b5061064061063b366004612ca9565b611919565b60405161028e9291906136c3565b34801561065a57600080fd5b506102fb6119a7565b34801561066f57600080fd5b5061028161067e366004612b35565b6119b6565b34801561068f57600080fd5b506106a361069e366004612e19565b611a39565b60405161028e919061366d565b3480156106bc57600080fd5b506102d9611aec565b3480156106d157600080fd5b506102d96106e0366004612abd565b611afc565b3480156106f157600080fd5b506102b7610700366004612abd565b611b2d565b34801561071157600080fd5b506102b7611b8e565b34801561072657600080fd5b506102b7610735366004612abd565b611cec565b34801561074657600080fd5b506102b7610755366004612b60565b611d5d565b34801561076657600080fd5b506102fb611e57565b34801561077b57600080fd5b506102fb611e66565b34801561079057600080fd5b506102b761079f366004612b35565b611e75565b60055490565b6107b2611f1e565b6001600160a01b03166107c361140f565b6001600160a01b0316146107f25760405162461bcd60e51b81526004016107e9906133e5565b60405180910390fd5b6001600160a01b0381166108185760405162461bcd60e51b81526004016107e99061341a565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040516302328d7360e31b81526000916001600160a01b0316906311946b989061086b908590600401613025565b60206040518083038186803b15801561088357600080fd5b505afa158015610897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bb9190612c44565b90505b919050565b6007546001600160a01b031681565b600080600583815481106108f657634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080516101008082018352600790940290920180546001600160a01b0390811684526001820154169483019490945260028401549082015260038301546060820152600483015460ff808216151560808401529290048216151560a0820152600583015460c08201526006909201541615801560e083015290915061098b5760009150506108be565b8060800151156109c15760006109a9826000015183606001516112a7565b9050806109bb576000925050506108be565b506109ee565b60006109da826000015183602001518460400151611433565b9050806109ec576000925050506108be565b505b50600192915050565b6006546001600160a01b031681565b600080836001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610a359190613025565b60206040518083038186803b158015610a4d57600080fd5b505afa158015610a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a859190612c5e565b90506000846001600160a01b031663dd62ed3e87306040518363ffffffff1660e01b8152600401610ab792919061305d565b60206040518083038186803b158015610acf57600080fd5b505afa158015610ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b079190612c5e565b90506000610b158383611f22565b9050610b218582611f22565b93505050505b9392505050565b60606005805480602002602001604051908101604052809291908181526020016000905b82821015610bec5760008481526020908190206040805161010080820183526007870290930180546001600160a01b0390811683526001808301549091168387015260028201549383019390935260038101546060830152600481015460ff808216151560808501529490048416151560a0830152600581015460c083015260060154909216151560e08301529083529092019101610b52565b50505050905090565b6006546001600160a01b0316331480610c265750610c1161140f565b6001600160a01b0316336001600160a01b0316145b610c425760405162461bcd60e51b81526004016107e9906132a9565b600060058281548110610c6557634e487b7160e01b600052603260045260246000fd5b90600052602060002090600702019050610c7e826108d2565b610c9a5760405162461bcd60e51b81526004016107e99061353d565b60068101805460ff19166001179055600481015460ff1615610cdb57805460038201546005830154610cd6926001600160a01b03169190611f37565b610d04565b8054600182015460028301546005840154610d04936001600160a01b039081169316919061220e565b60405160009083907f5b852761bce0e9cfbd818d902f0bb52b7fa79a4453694d4fb3952668f01bdd5a908390a35050565b610d3d611f1e565b6001600160a01b0316610d4e61140f565b6001600160a01b031614610d745760405162461bcd60e51b81526004016107e9906133e5565b600955565b60005b81811015610dc557610db3838383818110610da757634e487b7160e01b600052603260045260246000fd5b90506020020135610bf5565b80610dbd816137a3565b915050610d7c565b505050565b600080826001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e0657600080fd5b505afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190612c5e565b421015905080610e525760009150506108be565b6000610e5d84611afc565b905080610e6f576000925050506108be565b5060019392505050565b610e81611f1e565b6001600160a01b0316610e9261140f565b6001600160a01b031614610eb85760405162461bcd60e51b81526004016107e9906133e5565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b600060058281548110610efd57634e487b7160e01b600052603260045260246000fd5b6000918252602090912060079091020180549091506001600160a01b03163314610f395760405162461bcd60e51b81526004016107e990613390565b600681015460ff1615610f5e5760405162461bcd60e51b81526004016107e9906134e8565b60068101805460ff1916600190811790915560405183907f5b852761bce0e9cfbd818d902f0bb52b7fa79a4453694d4fb3952668f01bdd5a90600090a35050565b610fa7611f1e565b6001600160a01b0316610fb861140f565b6001600160a01b031614610fde5760405162461bcd60e51b81526004016107e9906133e5565b600855565b610feb611f1e565b6001600160a01b0316610ffc61140f565b6001600160a01b0316146110225760405162461bcd60e51b81526004016107e9906133e5565b61102c60006124b1565b565b60015460408051633018205f60e01b815290516000926001600160a01b031691633018205f916004808301926020929190829003018186803b15801561107357600080fd5b505afa158015611087573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ab9190612ad9565b600280546001600160a01b0319166001600160a01b03838116919091179091556001546040805163d01f63f560e01b81529051939450600093919092169163d01f63f5916004808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111469190612ad9565b600380546001600160a01b0319166001600160a01b03838116919091179091556001546040805163cf28493f60e01b81529051939450600093919092169163cf28493f916004808301926020929190829003018186803b1580156111a957600080fd5b505afa1580156111bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e19190612ad9565b600480546001600160a01b0319166001600160a01b0392909216919091179055505050565b600254604051636553690d60e11b815260009182916001600160a01b039091169063caa6d21a9061123b908790600401613025565b60206040518083038186803b15801561125357600080fd5b505afa158015611267573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128b9190612c5e565b905060008311801561129d5750808311155b9150505b92915050565b60008060006112b685856114e1565b50915091506000806112c88484611919565b915091508015806112d7575081155b156112e95760009450505050506112a1565b5060019695505050505050565b6112fe611f1e565b6001600160a01b031661130f61140f565b6001600160a01b0316146113355760405162461bcd60e51b81526004016107e9906133e5565b600754600160a01b900460ff161561134c57600080fd5b6007805460ff60a01b1916600160a01b1790556006546040805160048082526024820183526020820180516001600160e01b0316631f43112360e31b17905291516345c934b560e11b81526001600160a01b0390931692638b92696a926113da9230927f41929f0f7d5d72e03f9413e78666fadfa7d110a2b9b99a2f63261ad6fd7028a692889291016130ec565b600060405180830381600087803b1580156113f457600080fd5b505af1158015611408573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031690565b60095481565b6003546001600160a01b031681565b600080611441858585610a06565b604051633392416f60e21b8152909150309063ce4905bc906114699087908590600401613132565b60206040518083038186803b15801561148157600080fd5b505afa9250505080156114b1575060408051601f3d908101601f191682019092526114ae91810190612c5e565b60015b6114bf576000915050610b27565b806114cf57600092505050610b27565b50600195945050505050565b60085481565b6114e9612742565b6002546040516313b55f7d60e31b815260009182916001600160a01b0390911690639daafbe8906115209088908890600401613132565b60006040518083038186803b15801561153857600080fd5b505afa15801561154c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115749190810190612cec565b9250925092509250925092565b6005818154811061159157600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b03958616975094909316949193909260ff808216936101009092048116921688565b6000806001600160a01b03851661162657831561161a5760405162461bcd60e51b81526004016107e990613477565b50506009546001611651565b61162f8561083a565b61164b5760405162461bcd60e51b81526004016107e99061361b565b60085491505b60055461165c612778565b338082526001600160a01b038881166020840181815260408086018b8152606087018b81528915156080890190815260c089018c81526005805460018101825560009182528b5160079091027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db081018054928c166001600160a01b031993841617905597517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db18901805491909b1691161790985592517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db286015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db3850155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db48401805460a08a015115156101000261ff001993151560ff19928316179390931692909217905590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db584015560e08701517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db6909301805493151593909116929092179091555190929185917fd4e0aaf5be9b8773c644dfebba8b63f878965712ad8589d85ca4bc9d1b671e2c9190a450505050505050565b600254604051635b1b1e7960e11b81526000916001600160a01b03169063b6363cf29061086b908590309060040161305d565b60008061187a8360000151612501565b9050600061188b8460200151612501565b905081806118965750805b6118b057634e487b7160e01b600052600160045260246000fd5b816118e75783602001516000815181106118da57634e487b7160e01b600052603260045260246000fd5b6020026020010151611911565b8351805160009061190857634e487b7160e01b600052603260045260246000fd5b60200260200101515b949350505050565b6004805460405163cd43fbfb60e01b815260009283926001600160a01b03169163cd43fbfb9161194d91889188910161367c565b604080518083038186803b15801561196457600080fd5b505afa158015611978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199c9190612e31565b915091509250929050565b6004546001600160a01b031681565b60025460405163565eea1960e01b81526000916001600160a01b03169063565eea19906119e99086908690600401613132565b60206040518083038186803b158015611a0157600080fd5b505afa158015611a15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b279190612c5e565b611a41612778565b60058281548110611a6257634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080516101008082018352600790940290920180546001600160a01b0390811684526001820154169483019490945260028401549082015260038301546060820152600483015460ff808216151560808401529290048216151560a0820152600583015460c082015260069092015416151560e08201529050919050565b600754600160a01b900460ff1681565b6002546040516339c8d01b60e21b81526000916001600160a01b03169063e723406c9061086b908590600401613025565b611b35611f1e565b6001600160a01b0316611b4661140f565b6001600160a01b031614611b6c5760405162461bcd60e51b81526004016107e9906133e5565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b611b96611f1e565b6001600160a01b0316611ba761140f565b6001600160a01b031614611bcd5760405162461bcd60e51b81526004016107e9906133e5565b600754600160a01b900460ff16611be357600080fd5b6007805460ff60a01b19169055600654604051632970562f60e11b81526001600160a01b039091169063ee8ca3b59082906352e0ac5e90611c4c90309081907f41929f0f7d5d72e03f9413e78666fadfa7d110a2b9b99a2f63261ad6fd7028a690600401613077565b60206040518083038186803b158015611c6457600080fd5b505afa158015611c78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9c9190612c5e565b6040518263ffffffff1660e01b8152600401611cb8919061328d565b600060405180830381600087803b158015611cd257600080fd5b505af1158015611ce6573d6000803e3d6000fd5b50505050565b611cf4611f1e565b6001600160a01b0316611d0561140f565b6001600160a01b031614611d2b5760405162461bcd60e51b81526004016107e9906133e5565b6001600160a01b038116611d515760405162461bcd60e51b81526004016107e9906132ff565b611d5a816124b1565b50565b611d65611f1e565b6001600160a01b0316611d7661140f565b6001600160a01b031614611d9c5760405162461bcd60e51b81526004016107e9906133e5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0384161415611e43576000816001600160a01b031683604051611dda90613022565b60006040518083038185875af1925050503d8060008114611e17576040519150601f19603f3d011682016040523d82523d6000602084013e611e1c565b606091505b5050905080611e3d5760405162461bcd60e51b81526004016107e990613345565b50610dc5565b610dc56001600160a01b0384168284612554565b6001546001600160a01b031681565b6002546001600160a01b031681565b611e7d611f1e565b6001600160a01b0316611e8e61140f565b6001600160a01b031614611eb45760405162461bcd60e51b81526004016107e9906133e5565b600754604051631c20fadd60e01b81526001600160a01b0390911690631c20fadd90611ee890309086908690600401613039565b600060405180830381600087803b158015611f0257600080fd5b505af1158015611f16573d6000803e3d6000fd5b505050505050565b3390565b6000818311611f315782610b27565b50919050565b611f3f6127bc565b600781819052506001600160a01b0384166020820152608081018390523060408083019190915280516001808252818301909252600091816020015b611f836127bc565b815260200190600190039081611f7b5790505090508181600081518110611fba57634e487b7160e01b600052603260045260246000fd5b60200260200101819052506000611fd186866114e1565b505090506000611fe08261186a565b90506000816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b15801561201d57600080fd5b505afa158015612031573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120559190612ad9565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120859190613025565b60206040518083038186803b15801561209d57600080fd5b505afa1580156120b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d59190612c5e565b600254604051635b0bf86360e11b81529192506001600160a01b03169063b617f0c69061210690889060040161314b565b600060405180830381600087803b15801561212057600080fd5b505af1158015612134573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03851691506370a0823190612167903090600401613025565b60206040518083038186803b15801561217f57600080fd5b505afa158015612193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b79190612c5e565b905060006121c58383613760565b905060006127106121d6838c613741565b6121e09190613721565b6121ea9083613760565b90506122006001600160a01b0386168d83612554565b505050505050505050505050565b600061221b858585610a06565b90506122326001600160a01b0385168630846125aa565b61223a6127bc565b60088152306040808301919091526001600160a01b038616606083015260a0820185905280516001808252818301909252600091602082015b61227b6127bc565b81526020019060019003908161227357905050905081816000815181106122b257634e487b7160e01b600052603260045260246000fd5b60200260200101819052506000866001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b1580156122f857600080fd5b505afa15801561230c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123309190612ad9565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123609190613025565b60206040518083038186803b15801561237857600080fd5b505afa15801561238c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b09190612c5e565b600254604051635b0bf86360e11b81529192506001600160a01b03169063b617f0c6906123e190869060040161314b565b600060405180830381600087803b1580156123fb57600080fd5b505af115801561240f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03851691506370a0823190612442903090600401613025565b60206040518083038186803b15801561245a57600080fd5b505afa15801561246e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124929190612c5e565b905060006124a08383613760565b905060006127106121d6838b613741565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008082511180156108bb575060006001600160a01b03168260008151811061253a57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031614159050919050565b610dc58363a9059cbb60e01b8484604051602401612573929190613132565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125cb565b611ce6846323b872dd60e01b85858560405160240161257393929190613039565b6000612620826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661265a9092919063ffffffff16565b805190915015610dc5578080602001905181019061263e9190612c44565b610dc55760405162461bcd60e51b81526004016107e9906135d1565b606061191184846000858561266e85612703565b61268a5760405162461bcd60e51b81526004016107e99061359a565b600080866001600160a01b031685876040516126a69190613006565b60006040518083038185875af1925050503d80600081146126e3576040519150601f19603f3d011682016040523d82523d6000602084013e6126e8565b606091505b50915091506126f8828286612709565b979650505050505050565b3b151590565b60608315612718575081610b27565b8251156127285782518084602001fd5b8160405162461bcd60e51b81526004016107e99190613296565b6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001606081525090565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b604080516101008101909152806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001606081525090565b600082601f83011261282d578081fd5b8135602061284261283d836136fd565b6136d3565b828152818101908583018385028701840188101561285e578586fd5b855b85811015612885578135612873816137ea565b84529284019290840190600101612860565b5090979650505050505050565b600082601f8301126128a2578081fd5b815160206128b261283d836136fd565b82815281810190858301838502870184018810156128ce578586fd5b855b858110156128855781516128e3816137ea565b845292840192908401906001016128d0565b600082601f830112612905578081fd5b8135602061291561283d836136fd565b8281528181019085830183850287018401881015612931578586fd5b855b8581101561288557813584529284019290840190600101612933565b600082601f83011261295f578081fd5b8151602061296f61283d836136fd565b828152818101908583018385028701840188101561298b578586fd5b855b858110156128855781518452928401929084019060010161298d565b805180151581146108be57600080fd5b600060c082840312156129ca578081fd5b6129d460c06136d3565b9050813567ffffffffffffffff808211156129ee57600080fd5b6129fa8583860161281d565b83526020840135915080821115612a1057600080fd5b612a1c8583860161281d565b60208401526040840135915080821115612a3557600080fd5b612a418583860161281d565b60408401526060840135915080821115612a5a57600080fd5b612a66858386016128f5565b60608401526080840135915080821115612a7f57600080fd5b612a8b858386016128f5565b608084015260a0840135915080821115612aa457600080fd5b50612ab1848285016128f5565b60a08301525092915050565b600060208284031215612ace578081fd5b8135610b27816137ea565b600060208284031215612aea578081fd5b8151610b27816137ea565b600080600060608486031215612b09578182fd5b8335612b14816137ea565b92506020840135612b24816137ea565b929592945050506040919091013590565b60008060408385031215612b47578182fd5b8235612b52816137ea565b946020939093013593505050565b600080600060608486031215612b74578081fd5b8335612b7f816137ea565b9250602084013591506040840135612b96816137ea565b809150509250925092565b600080600060608486031215612bb5578081fd5b8335612bc0816137ea565b95602085013595506040909401359392505050565b60008060208385031215612be7578182fd5b823567ffffffffffffffff80821115612bfe578384fd5b818501915085601f830112612c11578384fd5b813581811115612c1f578485fd5b8660208083028501011115612c32578485fd5b60209290920196919550909350505050565b600060208284031215612c55578081fd5b610b27826129a9565b600060208284031215612c6f578081fd5b5051919050565b600060208284031215612c87578081fd5b813567ffffffffffffffff811115612c9d578182fd5b61129d848285016129b9565b60008060408385031215612cbb578182fd5b823567ffffffffffffffff811115612cd1578283fd5b612cdd858286016129b9565b95602094909401359450505050565b600080600060608486031215612d00578081fd5b835167ffffffffffffffff80821115612d17578283fd5b9085019060c08288031215612d2a578283fd5b612d3460c06136d3565b825182811115612d42578485fd5b612d4e89828601612892565b825250602083015182811115612d62578485fd5b612d6e89828601612892565b602083015250604083015182811115612d85578485fd5b612d9189828601612892565b604083015250606083015182811115612da8578485fd5b612db48982860161294f565b606083015250608083015182811115612dcb578485fd5b612dd78982860161294f565b60808301525060a083015182811115612dee578485fd5b612dfa8982860161294f565b60a0830152506020870151604090970151909896975095945050505050565b600060208284031215612e2a578081fd5b5035919050565b60008060408385031215612e43578182fd5b82519150612e53602084016129a9565b90509250929050565b6001600160a01b03169052565b6000815180845260208085019450808401835b83811015612ea15781516001600160a01b031687529582019590820190600101612e7c565b509495945050505050565b6000815180845260208085019450808401835b83811015612ea157815187529582019590820190600101612ebf565b60008151808452612ef3816020860160208601613777565b601f01601f19169290920160200192915050565b60018060a01b0380825116835280602083015116602084015250604081015160408301526060810151606083015260808101511515608083015260a0810151151560a083015260c081015160c083015260e0810151151560e08301525050565b6000815160c08452612f7c60c0850182612e69565b905060208301518482036020860152612f958282612e69565b91505060408301518482036040860152612faf8282612e69565b91505060608301518482036060860152612fc98282612eac565b91505060808301518482036080860152612fe38282612eac565b91505060a083015184820360a0860152612ffd8282612eac565b95945050505050565b60008251613018818460208701613777565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b0398891681529690971660208701526040860194909452606085019290925215156080840152151560a083015260c082015290151560e08201526101000190565b6001600160a01b0385811682526001600160e01b0319851660208301528316604082015260806060820181905260009061312890830184612edb565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b60208082528251828201819052600091906040908185019080840286018301878501865b8381101561322557603f1989840301855281516101008151600b81106131a357634e487b7160e01b8b52602160045260248bfd5b8552818901516131b58a870182612e5c565b50878201516131c689870182612e5c565b506060808301516131d982880182612e5c565b50506080828101519086015260a0808301519086015260c0808301519086015260e09182015191850181905261321181860183612edb565b96890196945050509086019060010161316f565b509098975050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561327657613262838551612f07565b92840192610100929092019160010161324f565b50909695505050505050565b901515815260200190565b90815260200190565b600060208252610b276020830184612edb565b60208082526036908201527f47616d6d6152656465656d65723a3a6f6e6c79417574686f72697a65643a204f60408201527537363c9030baba37b6b0ba37b91037b91037bbb732b960511b606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252602b908201527f47616d6d614f70657261746f723a3a686172766573743a20455448207472616e60408201526a1cd9995c8819985a5b195960aa1b606082015260800190565b60208082526035908201527f47616d6d6152656465656d65723a3a63616e63656c4f726465723a2053656e6460408201527432b91034b9903737ba1037b93232b91037bbb732b960591b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526037908201527f47616d6d614f70657261746f723a3a73657441646472657373426f6f6b3a204160408201527f646472657373206d757374206e6f74206265207a65726f000000000000000000606082015260800190565b6020808252604b908201527f47616d6d6152656465656d65723a3a6372656174654f726465723a20416d6f7560408201527f6e74206d7573742062652030207768656e206372656174696e6720736574746c60608201526a32b6b2b73a1037b93232b960a91b608082015260a00190565b60208082526035908201527f47616d6d6152656465656d65723a3a63616e63656c4f726465723a204f7264656040820152741c881a5cc8185b1c9958591e48199a5b9a5cda1959605a1b606082015260800190565b6020808252603a908201527f47616d6d6152656465656d65723a3a70726f636573734f726465723a204f726460408201527f65722073686f756c64206e6f742062652070726f636573736564000000000000606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526032908201527f47616d6d6152656465656d65723a3a6372656174654f726465723a204f746f6b604082015271195b881b9bdd081dda1a5d195b1a5cdd195960721b606082015260800190565b61010081016112a18284612f07565b60006040825261368f6040830185612f67565b90508260208301529392505050565b6000606082526136b16060830186612f67565b60208301949094525060400152919050565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156136f5576136f56137d4565b604052919050565b600067ffffffffffffffff821115613717576137176137d4565b5060209081020190565b60008261373c57634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561375b5761375b6137be565b500290565b600082821015613772576137726137be565b500390565b60005b8381101561379257818101518382015260200161377a565b83811115611ce65750506000910152565b60006000198214156137b7576137b76137be565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611d5a57600080fdfea2646970667358221220ed63631ee15fd9b26167c3d98e6b3216376d3deae4affabd21f946989258024a64736f6c634300080000330000000000000000000000001e31f2dcbad4dc572004eae6355fb18f9615cbe400000000000000000000000089a26d08c26e00ce935a775ba74a984ad346679b00000000000000000000000066e2f69df68c8f56837142be2e8c290efe76da9f

Deployed Bytecode

0x6080604052600436106102605760003560e01c806392a1a2e711610144578063ce4905bc116100b6578063ec8daaf91161007a578063ec8daaf914610705578063f2fde38b1461071a578063f54ac2461461073a578063f5887cdd1461075a578063f77c47911461076f578063f7c8d2211461078457610267565b8063ce4905bc14610663578063d09ef24114610683578063e55107a0146106b0578063e723406c146106c5578063e7c5a6e8146106e557610267565b8063a85c38ef11610108578063a85c38ef1461058c578063acfee8ed146105c0578063c2a9a831146105e0578063c8daad3014610600578063cd43fbfb14610620578063ce3e39c01461064e57610267565b806392a1a2e7146104fe57806393e59dc114610513578063945ce2c414610528578063965fa21e146105485780639daafbe81461055d57610267565b806341929f0f116101dd578063715018a6116101a1578063715018a61461045f5780637c55ccb3146104745780638047c2fb1461048957806383781c10146104a9578063861e4e5b146104c95780638da5cb5b146104e957610267565b806341929f0f146103bf57806342ae6aba146103df57806345389e3f146103ff578063514fcac71461041f5780635d841af51461043f57610267565b80631cb78541116102245780631cb78541146103285780632c9d27ea1461033d5780632e2dc43e1461035d5780632e5187fb1461037f57806332f8e23e1461039f57610267565b806307c2e16c1461026c5780630b3448a81461029757806311946b98146102b9578063144c27ff146102e6578063182192d31461030857610267565b3661026757005b600080fd5b34801561027857600080fd5b506102816107a4565b60405161028e919061328d565b60405180910390f35b3480156102a357600080fd5b506102b76102b2366004612abd565b6107aa565b005b3480156102c557600080fd5b506102d96102d4366004612abd565b61083a565b60405161028e9190613282565b3480156102f257600080fd5b506102fb6108c3565b60405161028e9190613025565b34801561031457600080fd5b506102d9610323366004612e19565b6108d2565b34801561033457600080fd5b506102fb6109f7565b34801561034957600080fd5b50610281610358366004612af5565b610a06565b34801561036957600080fd5b50610372610b2e565b60405161028e9190613233565b34801561038b57600080fd5b506102b761039a366004612e19565b610bf5565b3480156103ab57600080fd5b506102b76103ba366004612e19565b610d35565b3480156103cb57600080fd5b506102b76103da366004612bd5565b610d79565b3480156103eb57600080fd5b506102d96103fa366004612abd565b610dca565b34801561040b57600080fd5b506102b761041a366004612abd565b610e79565b34801561042b57600080fd5b506102b761043a366004612e19565b610eda565b34801561044b57600080fd5b506102b761045a366004612e19565b610f9f565b34801561046b57600080fd5b506102b7610fe3565b34801561048057600080fd5b506102b761102e565b34801561049557600080fd5b506102d96104a4366004612b35565b611206565b3480156104b557600080fd5b506102d96104c4366004612b35565b6112a7565b3480156104d557600080fd5b506102b76104e4366004612abd565b6112f6565b3480156104f557600080fd5b506102fb61140f565b34801561050a57600080fd5b5061028161141e565b34801561051f57600080fd5b506102fb611424565b34801561053457600080fd5b506102d9610543366004612af5565b611433565b34801561055457600080fd5b506102816114db565b34801561056957600080fd5b5061057d610578366004612b35565b6114e1565b60405161028e9392919061369e565b34801561059857600080fd5b506105ac6105a7366004612e19565b611581565b60405161028e9897969594939291906130a4565b3480156105cc57600080fd5b506102b76105db366004612ba1565b6115eb565b3480156105ec57600080fd5b506102d96105fb366004612abd565b611837565b34801561060c57600080fd5b506102fb61061b366004612c76565b61186a565b34801561062c57600080fd5b5061064061063b366004612ca9565b611919565b60405161028e9291906136c3565b34801561065a57600080fd5b506102fb6119a7565b34801561066f57600080fd5b5061028161067e366004612b35565b6119b6565b34801561068f57600080fd5b506106a361069e366004612e19565b611a39565b60405161028e919061366d565b3480156106bc57600080fd5b506102d9611aec565b3480156106d157600080fd5b506102d96106e0366004612abd565b611afc565b3480156106f157600080fd5b506102b7610700366004612abd565b611b2d565b34801561071157600080fd5b506102b7611b8e565b34801561072657600080fd5b506102b7610735366004612abd565b611cec565b34801561074657600080fd5b506102b7610755366004612b60565b611d5d565b34801561076657600080fd5b506102fb611e57565b34801561077b57600080fd5b506102fb611e66565b34801561079057600080fd5b506102b761079f366004612b35565b611e75565b60055490565b6107b2611f1e565b6001600160a01b03166107c361140f565b6001600160a01b0316146107f25760405162461bcd60e51b81526004016107e9906133e5565b60405180910390fd5b6001600160a01b0381166108185760405162461bcd60e51b81526004016107e99061341a565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040516302328d7360e31b81526000916001600160a01b0316906311946b989061086b908590600401613025565b60206040518083038186803b15801561088357600080fd5b505afa158015610897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bb9190612c44565b90505b919050565b6007546001600160a01b031681565b600080600583815481106108f657634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080516101008082018352600790940290920180546001600160a01b0390811684526001820154169483019490945260028401549082015260038301546060820152600483015460ff808216151560808401529290048216151560a0820152600583015460c08201526006909201541615801560e083015290915061098b5760009150506108be565b8060800151156109c15760006109a9826000015183606001516112a7565b9050806109bb576000925050506108be565b506109ee565b60006109da826000015183602001518460400151611433565b9050806109ec576000925050506108be565b505b50600192915050565b6006546001600160a01b031681565b600080836001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610a359190613025565b60206040518083038186803b158015610a4d57600080fd5b505afa158015610a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a859190612c5e565b90506000846001600160a01b031663dd62ed3e87306040518363ffffffff1660e01b8152600401610ab792919061305d565b60206040518083038186803b158015610acf57600080fd5b505afa158015610ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b079190612c5e565b90506000610b158383611f22565b9050610b218582611f22565b93505050505b9392505050565b60606005805480602002602001604051908101604052809291908181526020016000905b82821015610bec5760008481526020908190206040805161010080820183526007870290930180546001600160a01b0390811683526001808301549091168387015260028201549383019390935260038101546060830152600481015460ff808216151560808501529490048416151560a0830152600581015460c083015260060154909216151560e08301529083529092019101610b52565b50505050905090565b6006546001600160a01b0316331480610c265750610c1161140f565b6001600160a01b0316336001600160a01b0316145b610c425760405162461bcd60e51b81526004016107e9906132a9565b600060058281548110610c6557634e487b7160e01b600052603260045260246000fd5b90600052602060002090600702019050610c7e826108d2565b610c9a5760405162461bcd60e51b81526004016107e99061353d565b60068101805460ff19166001179055600481015460ff1615610cdb57805460038201546005830154610cd6926001600160a01b03169190611f37565b610d04565b8054600182015460028301546005840154610d04936001600160a01b039081169316919061220e565b60405160009083907f5b852761bce0e9cfbd818d902f0bb52b7fa79a4453694d4fb3952668f01bdd5a908390a35050565b610d3d611f1e565b6001600160a01b0316610d4e61140f565b6001600160a01b031614610d745760405162461bcd60e51b81526004016107e9906133e5565b600955565b60005b81811015610dc557610db3838383818110610da757634e487b7160e01b600052603260045260246000fd5b90506020020135610bf5565b80610dbd816137a3565b915050610d7c565b505050565b600080826001600160a01b031663ade6e2aa6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e0657600080fd5b505afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190612c5e565b421015905080610e525760009150506108be565b6000610e5d84611afc565b905080610e6f576000925050506108be565b5060019392505050565b610e81611f1e565b6001600160a01b0316610e9261140f565b6001600160a01b031614610eb85760405162461bcd60e51b81526004016107e9906133e5565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b600060058281548110610efd57634e487b7160e01b600052603260045260246000fd5b6000918252602090912060079091020180549091506001600160a01b03163314610f395760405162461bcd60e51b81526004016107e990613390565b600681015460ff1615610f5e5760405162461bcd60e51b81526004016107e9906134e8565b60068101805460ff1916600190811790915560405183907f5b852761bce0e9cfbd818d902f0bb52b7fa79a4453694d4fb3952668f01bdd5a90600090a35050565b610fa7611f1e565b6001600160a01b0316610fb861140f565b6001600160a01b031614610fde5760405162461bcd60e51b81526004016107e9906133e5565b600855565b610feb611f1e565b6001600160a01b0316610ffc61140f565b6001600160a01b0316146110225760405162461bcd60e51b81526004016107e9906133e5565b61102c60006124b1565b565b60015460408051633018205f60e01b815290516000926001600160a01b031691633018205f916004808301926020929190829003018186803b15801561107357600080fd5b505afa158015611087573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ab9190612ad9565b600280546001600160a01b0319166001600160a01b03838116919091179091556001546040805163d01f63f560e01b81529051939450600093919092169163d01f63f5916004808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111469190612ad9565b600380546001600160a01b0319166001600160a01b03838116919091179091556001546040805163cf28493f60e01b81529051939450600093919092169163cf28493f916004808301926020929190829003018186803b1580156111a957600080fd5b505afa1580156111bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e19190612ad9565b600480546001600160a01b0319166001600160a01b0392909216919091179055505050565b600254604051636553690d60e11b815260009182916001600160a01b039091169063caa6d21a9061123b908790600401613025565b60206040518083038186803b15801561125357600080fd5b505afa158015611267573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128b9190612c5e565b905060008311801561129d5750808311155b9150505b92915050565b60008060006112b685856114e1565b50915091506000806112c88484611919565b915091508015806112d7575081155b156112e95760009450505050506112a1565b5060019695505050505050565b6112fe611f1e565b6001600160a01b031661130f61140f565b6001600160a01b0316146113355760405162461bcd60e51b81526004016107e9906133e5565b600754600160a01b900460ff161561134c57600080fd5b6007805460ff60a01b1916600160a01b1790556006546040805160048082526024820183526020820180516001600160e01b0316631f43112360e31b17905291516345c934b560e11b81526001600160a01b0390931692638b92696a926113da9230927f41929f0f7d5d72e03f9413e78666fadfa7d110a2b9b99a2f63261ad6fd7028a692889291016130ec565b600060405180830381600087803b1580156113f457600080fd5b505af1158015611408573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031690565b60095481565b6003546001600160a01b031681565b600080611441858585610a06565b604051633392416f60e21b8152909150309063ce4905bc906114699087908590600401613132565b60206040518083038186803b15801561148157600080fd5b505afa9250505080156114b1575060408051601f3d908101601f191682019092526114ae91810190612c5e565b60015b6114bf576000915050610b27565b806114cf57600092505050610b27565b50600195945050505050565b60085481565b6114e9612742565b6002546040516313b55f7d60e31b815260009182916001600160a01b0390911690639daafbe8906115209088908890600401613132565b60006040518083038186803b15801561153857600080fd5b505afa15801561154c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115749190810190612cec565b9250925092509250925092565b6005818154811061159157600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b03958616975094909316949193909260ff808216936101009092048116921688565b6000806001600160a01b03851661162657831561161a5760405162461bcd60e51b81526004016107e990613477565b50506009546001611651565b61162f8561083a565b61164b5760405162461bcd60e51b81526004016107e99061361b565b60085491505b60055461165c612778565b338082526001600160a01b038881166020840181815260408086018b8152606087018b81528915156080890190815260c089018c81526005805460018101825560009182528b5160079091027f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db081018054928c166001600160a01b031993841617905597517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db18901805491909b1691161790985592517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db286015590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db3850155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db48401805460a08a015115156101000261ff001993151560ff19928316179390931692909217905590517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db584015560e08701517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db6909301805493151593909116929092179091555190929185917fd4e0aaf5be9b8773c644dfebba8b63f878965712ad8589d85ca4bc9d1b671e2c9190a450505050505050565b600254604051635b1b1e7960e11b81526000916001600160a01b03169063b6363cf29061086b908590309060040161305d565b60008061187a8360000151612501565b9050600061188b8460200151612501565b905081806118965750805b6118b057634e487b7160e01b600052600160045260246000fd5b816118e75783602001516000815181106118da57634e487b7160e01b600052603260045260246000fd5b6020026020010151611911565b8351805160009061190857634e487b7160e01b600052603260045260246000fd5b60200260200101515b949350505050565b6004805460405163cd43fbfb60e01b815260009283926001600160a01b03169163cd43fbfb9161194d91889188910161367c565b604080518083038186803b15801561196457600080fd5b505afa158015611978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199c9190612e31565b915091509250929050565b6004546001600160a01b031681565b60025460405163565eea1960e01b81526000916001600160a01b03169063565eea19906119e99086908690600401613132565b60206040518083038186803b158015611a0157600080fd5b505afa158015611a15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b279190612c5e565b611a41612778565b60058281548110611a6257634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080516101008082018352600790940290920180546001600160a01b0390811684526001820154169483019490945260028401549082015260038301546060820152600483015460ff808216151560808401529290048216151560a0820152600583015460c082015260069092015416151560e08201529050919050565b600754600160a01b900460ff1681565b6002546040516339c8d01b60e21b81526000916001600160a01b03169063e723406c9061086b908590600401613025565b611b35611f1e565b6001600160a01b0316611b4661140f565b6001600160a01b031614611b6c5760405162461bcd60e51b81526004016107e9906133e5565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b611b96611f1e565b6001600160a01b0316611ba761140f565b6001600160a01b031614611bcd5760405162461bcd60e51b81526004016107e9906133e5565b600754600160a01b900460ff16611be357600080fd5b6007805460ff60a01b19169055600654604051632970562f60e11b81526001600160a01b039091169063ee8ca3b59082906352e0ac5e90611c4c90309081907f41929f0f7d5d72e03f9413e78666fadfa7d110a2b9b99a2f63261ad6fd7028a690600401613077565b60206040518083038186803b158015611c6457600080fd5b505afa158015611c78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9c9190612c5e565b6040518263ffffffff1660e01b8152600401611cb8919061328d565b600060405180830381600087803b158015611cd257600080fd5b505af1158015611ce6573d6000803e3d6000fd5b50505050565b611cf4611f1e565b6001600160a01b0316611d0561140f565b6001600160a01b031614611d2b5760405162461bcd60e51b81526004016107e9906133e5565b6001600160a01b038116611d515760405162461bcd60e51b81526004016107e9906132ff565b611d5a816124b1565b50565b611d65611f1e565b6001600160a01b0316611d7661140f565b6001600160a01b031614611d9c5760405162461bcd60e51b81526004016107e9906133e5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0384161415611e43576000816001600160a01b031683604051611dda90613022565b60006040518083038185875af1925050503d8060008114611e17576040519150601f19603f3d011682016040523d82523d6000602084013e611e1c565b606091505b5050905080611e3d5760405162461bcd60e51b81526004016107e990613345565b50610dc5565b610dc56001600160a01b0384168284612554565b6001546001600160a01b031681565b6002546001600160a01b031681565b611e7d611f1e565b6001600160a01b0316611e8e61140f565b6001600160a01b031614611eb45760405162461bcd60e51b81526004016107e9906133e5565b600754604051631c20fadd60e01b81526001600160a01b0390911690631c20fadd90611ee890309086908690600401613039565b600060405180830381600087803b158015611f0257600080fd5b505af1158015611f16573d6000803e3d6000fd5b505050505050565b3390565b6000818311611f315782610b27565b50919050565b611f3f6127bc565b600781819052506001600160a01b0384166020820152608081018390523060408083019190915280516001808252818301909252600091816020015b611f836127bc565b815260200190600190039081611f7b5790505090508181600081518110611fba57634e487b7160e01b600052603260045260246000fd5b60200260200101819052506000611fd186866114e1565b505090506000611fe08261186a565b90506000816001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b15801561201d57600080fd5b505afa158015612031573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120559190612ad9565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120859190613025565b60206040518083038186803b15801561209d57600080fd5b505afa1580156120b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d59190612c5e565b600254604051635b0bf86360e11b81529192506001600160a01b03169063b617f0c69061210690889060040161314b565b600060405180830381600087803b15801561212057600080fd5b505af1158015612134573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03851691506370a0823190612167903090600401613025565b60206040518083038186803b15801561217f57600080fd5b505afa158015612193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b79190612c5e565b905060006121c58383613760565b905060006127106121d6838c613741565b6121e09190613721565b6121ea9083613760565b90506122006001600160a01b0386168d83612554565b505050505050505050505050565b600061221b858585610a06565b90506122326001600160a01b0385168630846125aa565b61223a6127bc565b60088152306040808301919091526001600160a01b038616606083015260a0820185905280516001808252818301909252600091602082015b61227b6127bc565b81526020019060019003908161227357905050905081816000815181106122b257634e487b7160e01b600052603260045260246000fd5b60200260200101819052506000866001600160a01b031663aabaecd66040518163ffffffff1660e01b815260040160206040518083038186803b1580156122f857600080fd5b505afa15801561230c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123309190612ad9565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123609190613025565b60206040518083038186803b15801561237857600080fd5b505afa15801561238c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b09190612c5e565b600254604051635b0bf86360e11b81529192506001600160a01b03169063b617f0c6906123e190869060040161314b565b600060405180830381600087803b1580156123fb57600080fd5b505af115801561240f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03851691506370a0823190612442903090600401613025565b60206040518083038186803b15801561245a57600080fd5b505afa15801561246e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124929190612c5e565b905060006124a08383613760565b905060006127106121d6838b613741565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008082511180156108bb575060006001600160a01b03168260008151811061253a57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031614159050919050565b610dc58363a9059cbb60e01b8484604051602401612573929190613132565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125cb565b611ce6846323b872dd60e01b85858560405160240161257393929190613039565b6000612620826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661265a9092919063ffffffff16565b805190915015610dc5578080602001905181019061263e9190612c44565b610dc55760405162461bcd60e51b81526004016107e9906135d1565b606061191184846000858561266e85612703565b61268a5760405162461bcd60e51b81526004016107e99061359a565b600080866001600160a01b031685876040516126a69190613006565b60006040518083038185875af1925050503d80600081146126e3576040519150601f19603f3d011682016040523d82523d6000602084013e6126e8565b606091505b50915091506126f8828286612709565b979650505050505050565b3b151590565b60608315612718575081610b27565b8251156127285782518084602001fd5b8160405162461bcd60e51b81526004016107e99190613296565b6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001606081525090565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b604080516101008101909152806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001606081525090565b600082601f83011261282d578081fd5b8135602061284261283d836136fd565b6136d3565b828152818101908583018385028701840188101561285e578586fd5b855b85811015612885578135612873816137ea565b84529284019290840190600101612860565b5090979650505050505050565b600082601f8301126128a2578081fd5b815160206128b261283d836136fd565b82815281810190858301838502870184018810156128ce578586fd5b855b858110156128855781516128e3816137ea565b845292840192908401906001016128d0565b600082601f830112612905578081fd5b8135602061291561283d836136fd565b8281528181019085830183850287018401881015612931578586fd5b855b8581101561288557813584529284019290840190600101612933565b600082601f83011261295f578081fd5b8151602061296f61283d836136fd565b828152818101908583018385028701840188101561298b578586fd5b855b858110156128855781518452928401929084019060010161298d565b805180151581146108be57600080fd5b600060c082840312156129ca578081fd5b6129d460c06136d3565b9050813567ffffffffffffffff808211156129ee57600080fd5b6129fa8583860161281d565b83526020840135915080821115612a1057600080fd5b612a1c8583860161281d565b60208401526040840135915080821115612a3557600080fd5b612a418583860161281d565b60408401526060840135915080821115612a5a57600080fd5b612a66858386016128f5565b60608401526080840135915080821115612a7f57600080fd5b612a8b858386016128f5565b608084015260a0840135915080821115612aa457600080fd5b50612ab1848285016128f5565b60a08301525092915050565b600060208284031215612ace578081fd5b8135610b27816137ea565b600060208284031215612aea578081fd5b8151610b27816137ea565b600080600060608486031215612b09578182fd5b8335612b14816137ea565b92506020840135612b24816137ea565b929592945050506040919091013590565b60008060408385031215612b47578182fd5b8235612b52816137ea565b946020939093013593505050565b600080600060608486031215612b74578081fd5b8335612b7f816137ea565b9250602084013591506040840135612b96816137ea565b809150509250925092565b600080600060608486031215612bb5578081fd5b8335612bc0816137ea565b95602085013595506040909401359392505050565b60008060208385031215612be7578182fd5b823567ffffffffffffffff80821115612bfe578384fd5b818501915085601f830112612c11578384fd5b813581811115612c1f578485fd5b8660208083028501011115612c32578485fd5b60209290920196919550909350505050565b600060208284031215612c55578081fd5b610b27826129a9565b600060208284031215612c6f578081fd5b5051919050565b600060208284031215612c87578081fd5b813567ffffffffffffffff811115612c9d578182fd5b61129d848285016129b9565b60008060408385031215612cbb578182fd5b823567ffffffffffffffff811115612cd1578283fd5b612cdd858286016129b9565b95602094909401359450505050565b600080600060608486031215612d00578081fd5b835167ffffffffffffffff80821115612d17578283fd5b9085019060c08288031215612d2a578283fd5b612d3460c06136d3565b825182811115612d42578485fd5b612d4e89828601612892565b825250602083015182811115612d62578485fd5b612d6e89828601612892565b602083015250604083015182811115612d85578485fd5b612d9189828601612892565b604083015250606083015182811115612da8578485fd5b612db48982860161294f565b606083015250608083015182811115612dcb578485fd5b612dd78982860161294f565b60808301525060a083015182811115612dee578485fd5b612dfa8982860161294f565b60a0830152506020870151604090970151909896975095945050505050565b600060208284031215612e2a578081fd5b5035919050565b60008060408385031215612e43578182fd5b82519150612e53602084016129a9565b90509250929050565b6001600160a01b03169052565b6000815180845260208085019450808401835b83811015612ea15781516001600160a01b031687529582019590820190600101612e7c565b509495945050505050565b6000815180845260208085019450808401835b83811015612ea157815187529582019590820190600101612ebf565b60008151808452612ef3816020860160208601613777565b601f01601f19169290920160200192915050565b60018060a01b0380825116835280602083015116602084015250604081015160408301526060810151606083015260808101511515608083015260a0810151151560a083015260c081015160c083015260e0810151151560e08301525050565b6000815160c08452612f7c60c0850182612e69565b905060208301518482036020860152612f958282612e69565b91505060408301518482036040860152612faf8282612e69565b91505060608301518482036060860152612fc98282612eac565b91505060808301518482036080860152612fe38282612eac565b91505060a083015184820360a0860152612ffd8282612eac565b95945050505050565b60008251613018818460208701613777565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b0398891681529690971660208701526040860194909452606085019290925215156080840152151560a083015260c082015290151560e08201526101000190565b6001600160a01b0385811682526001600160e01b0319851660208301528316604082015260806060820181905260009061312890830184612edb565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b60208082528251828201819052600091906040908185019080840286018301878501865b8381101561322557603f1989840301855281516101008151600b81106131a357634e487b7160e01b8b52602160045260248bfd5b8552818901516131b58a870182612e5c565b50878201516131c689870182612e5c565b506060808301516131d982880182612e5c565b50506080828101519086015260a0808301519086015260c0808301519086015260e09182015191850181905261321181860183612edb565b96890196945050509086019060010161316f565b509098975050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561327657613262838551612f07565b92840192610100929092019160010161324f565b50909695505050505050565b901515815260200190565b90815260200190565b600060208252610b276020830184612edb565b60208082526036908201527f47616d6d6152656465656d65723a3a6f6e6c79417574686f72697a65643a204f60408201527537363c9030baba37b6b0ba37b91037b91037bbb732b960511b606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252602b908201527f47616d6d614f70657261746f723a3a686172766573743a20455448207472616e60408201526a1cd9995c8819985a5b195960aa1b606082015260800190565b60208082526035908201527f47616d6d6152656465656d65723a3a63616e63656c4f726465723a2053656e6460408201527432b91034b9903737ba1037b93232b91037bbb732b960591b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526037908201527f47616d6d614f70657261746f723a3a73657441646472657373426f6f6b3a204160408201527f646472657373206d757374206e6f74206265207a65726f000000000000000000606082015260800190565b6020808252604b908201527f47616d6d6152656465656d65723a3a6372656174654f726465723a20416d6f7560408201527f6e74206d7573742062652030207768656e206372656174696e6720736574746c60608201526a32b6b2b73a1037b93232b960a91b608082015260a00190565b60208082526035908201527f47616d6d6152656465656d65723a3a63616e63656c4f726465723a204f7264656040820152741c881a5cc8185b1c9958591e48199a5b9a5cda1959605a1b606082015260800190565b6020808252603a908201527f47616d6d6152656465656d65723a3a70726f636573734f726465723a204f726460408201527f65722073686f756c64206e6f742062652070726f636573736564000000000000606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526032908201527f47616d6d6152656465656d65723a3a6372656174654f726465723a204f746f6b604082015271195b881b9bdd081dda1a5d195b1a5cdd195960721b606082015260800190565b61010081016112a18284612f07565b60006040825261368f6040830185612f67565b90508260208301529392505050565b6000606082526136b16060830186612f67565b60208301949094525060400152919050565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156136f5576136f56137d4565b604052919050565b600067ffffffffffffffff821115613717576137176137d4565b5060209081020190565b60008261373c57634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561375b5761375b6137be565b500290565b600082821015613772576137726137be565b500390565b60005b8381101561379257818101518382015260200161377a565b83811115611ce65750506000910152565b60006000198214156137b7576137b76137be565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611d5a57600080fdfea2646970667358221220ed63631ee15fd9b26167c3d98e6b3216376d3deae4affabd21f946989258024a64736f6c63430008000033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001e31f2dcbad4dc572004eae6355fb18f9615cbe400000000000000000000000089a26d08c26e00ce935a775ba74a984ad346679b00000000000000000000000066e2f69df68c8f56837142be2e8c290efe76da9f

-----Decoded View---------------
Arg [0] : _gammaAddressBook (address): 0x1E31F2DCBad4dc572004Eae6355fB18F9615cBe4
Arg [1] : _automator (address): 0x89a26d08c26E00cE935a775Ba74A984Ad346679b
Arg [2] : _automatorTreasury (address): 0x66e2F69df68C8F56837142bE2E8C290EfE76DA9f

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001e31f2dcbad4dc572004eae6355fb18f9615cbe4
Arg [1] : 00000000000000000000000089a26d08c26e00ce935a775ba74a984ad346679b
Arg [2] : 00000000000000000000000066e2f69df68c8f56837142be2e8c290efe76da9f


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
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.