ETH Price: $2,981.29 (+2.10%)
Gas: 2 Gwei

Contract

0x48657E3e5dcc79749D658917317c91681BC4D04F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Boost For122897712021-04-22 11:38:491170 days ago1619091529IN
0x48657E3e...81BC4D04F
0 ETH0.08652129102
Boost For122897712021-04-22 11:38:491170 days ago1619091529IN
0x48657E3e...81BC4D04F
0 ETH0.08672764102
Boost For122897712021-04-22 11:38:491170 days ago1619091529IN
0x48657E3e...81BC4D04F
0 ETH0.08971889102
Boost For122897712021-04-22 11:38:491170 days ago1619091529IN
0x48657E3e...81BC4D04F
0 ETH0.09378777102
Boost For122897712021-04-22 11:38:491170 days ago1619091529IN
0x48657E3e...81BC4D04F
0 ETH0.08981079102
Repay For122895332021-04-22 10:45:261170 days ago1619088326IN
0x48657E3e...81BC4D04F
0 ETH0.1253307399
Boost For122893362021-04-22 10:05:121170 days ago1619085912IN
0x48657E3e...81BC4D04F
0 ETH0.09582581135.36
Boost For122893362021-04-22 10:05:121170 days ago1619085912IN
0x48657E3e...81BC4D04F
0 ETH0.10355743135.36
Boost For122884402021-04-22 6:36:411170 days ago1619073401IN
0x48657E3e...81BC4D04F
0 ETH0.15516091176.4
Boost For122884402021-04-22 6:36:411170 days ago1619073401IN
0x48657E3e...81BC4D04F
0 ETH0.14502055176.4
Boost For122884402021-04-22 6:36:411170 days ago1619073401IN
0x48657E3e...81BC4D04F
0 ETH0.15531773176.4
Repay For122867242021-04-22 0:02:251171 days ago1619049745IN
0x48657E3e...81BC4D04F
0 ETH0.12531029147
Repay For122864152021-04-21 22:55:111171 days ago1619045711IN
0x48657E3e...81BC4D04F
0 ETH0.00965719138.00717883
Boost For122856132021-04-21 20:04:171171 days ago1619035457IN
0x48657E3e...81BC4D04F
0 ETH0.11350276143.5
Boost For122853902021-04-21 19:19:231171 days ago1619032763IN
0x48657E3e...81BC4D04F
0 ETH0.12906174148.78
Boost For122848452021-04-21 17:16:031171 days ago1619025363IN
0x48657E3e...81BC4D04F
0 ETH0.19903353156
Boost For122844002021-04-21 15:36:021171 days ago1619019362IN
0x48657E3e...81BC4D04F
0 ETH0.18026864196
Boost For122842252021-04-21 14:55:191171 days ago1619016919IN
0x48657E3e...81BC4D04F
0 ETH0.15447734181
Boost For122840002021-04-21 14:05:251171 days ago1619013925IN
0x48657E3e...81BC4D04F
0 ETH0.13923728182
Boost For122839992021-04-21 14:05:171171 days ago1619013917IN
0x48657E3e...81BC4D04F
0 ETH0.16024845182
Boost For122835912021-04-21 12:39:421171 days ago1619008782IN
0x48657E3e...81BC4D04F
0 ETH0.14882095199
Boost For122835912021-04-21 12:39:421171 days ago1619008782IN
0x48657E3e...81BC4D04F
0 ETH0.1742426199
Boost For122802152021-04-21 0:05:201172 days ago1618963520IN
0x48657E3e...81BC4D04F
0 ETH0.18735416213
Boost For122802152021-04-21 0:05:201172 days ago1618963520IN
0x48657E3e...81BC4D04F
0 ETH0.19952136213
Boost For122802142021-04-21 0:05:011172 days ago1618963501IN
0x48657E3e...81BC4D04F
0 ETH0.18650599213
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
122617632021-04-18 3:45:201175 days ago1618717520
0x48657E3e...81BC4D04F
0.157248 ETH
122617632021-04-18 3:45:201175 days ago1618717520
0x48657E3e...81BC4D04F
0.157248 ETH
122617622021-04-18 3:45:001175 days ago1618717500
0x48657E3e...81BC4D04F
0.052416 ETH
122616782021-04-18 3:27:231175 days ago1618716443
0x48657E3e...81BC4D04F
0.02128 ETH
121697542021-04-04 0:04:571189 days ago1617494697
0x48657E3e...81BC4D04F
0.017808 ETH
120908872021-03-22 20:49:531201 days ago1616446193
0x48657E3e...81BC4D04F
0.030016 ETH
119831042021-03-06 6:04:591217 days ago1615010699
0x48657E3e...81BC4D04F
0.008176 ETH
119772742021-03-05 8:41:071218 days ago1614933667
0x48657E3e...81BC4D04F
0.034496 ETH
119315252021-02-26 7:39:381225 days ago1614325178
0x48657E3e...81BC4D04F
0.039872 ETH
119298392021-02-26 1:24:311226 days ago1614302671
0x48657E3e...81BC4D04F
0.02912 ETH
119298382021-02-26 1:23:581226 days ago1614302638
0x48657E3e...81BC4D04F
0.02912 ETH
119296502021-02-26 0:41:321226 days ago1614300092
0x48657E3e...81BC4D04F
0.029232 ETH
119125382021-02-23 9:45:101228 days ago1614073510
0x48657E3e...81BC4D04F
0.085904 ETH
119125162021-02-23 9:40:071228 days ago1614073207
0x48657E3e...81BC4D04F
0.323568 ETH
119125122021-02-23 9:39:181228 days ago1614073158
0x48657E3e...81BC4D04F
0.323568 ETH
119125112021-02-23 9:39:071228 days ago1614073147
0x48657E3e...81BC4D04F
0.107856 ETH
119125102021-02-23 9:39:041228 days ago1614073144
0x48657E3e...81BC4D04F
0.336336 ETH
119125062021-02-23 9:38:281228 days ago1614073108
0x48657E3e...81BC4D04F
0.230048 ETH
119124852021-02-23 9:33:081228 days ago1614072788
0x48657E3e...81BC4D04F
0.290528 ETH
119124732021-02-23 9:31:581228 days ago1614072718
0x48657E3e...81BC4D04F
0.244608 ETH
119124482021-02-23 9:25:001228 days ago1614072300
0x48657E3e...81BC4D04F
0.427392 ETH
119124472021-02-23 9:24:501228 days ago1614072290
0x48657E3e...81BC4D04F
0.126896 ETH
119124472021-02-23 9:24:501228 days ago1614072290
0x48657E3e...81BC4D04F
0.321888 ETH
119124442021-02-23 9:22:511228 days ago1614072171
0x48657E3e...81BC4D04F
0.321888 ETH
119124352021-02-23 9:21:401228 days ago1614072100
0x48657E3e...81BC4D04F
0.313824 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CompoundMonitor

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-12-01
*/

pragma solidity ^0.6.0; 
pragma experimental ABIEncoderV2;

 interface ERC20 {
    function totalSupply() external view returns (uint256 supply);

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

    function transfer(address _to, uint256 _value) external returns (bool success);

    function transferFrom(address _from, address _to, uint256 _value)
        external
        returns (bool success);

    function approve(address _spender, uint256 _value) external returns (bool success);

    function allowance(address _owner, address _spender) external view returns (uint256 remaining);

    function decimals() external view returns (uint256 digits);

    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}  library Address {
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}  library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}  library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(ERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(ERC20 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.
     */
    function safeApprove(ERC20 token, address spender, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function _callOptionalReturn(ERC20 token, bytes memory data) private {

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

    using SafeERC20 for ERC20;

    address public owner;
    address public admin;

    modifier onlyOwner() {
        require(owner == msg.sender);
        _;
    }

    modifier onlyAdmin() {
        require(admin == msg.sender);
        _;
    }

    constructor() public {
        owner = msg.sender;
        admin = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9;
    }

    /// @notice Admin is set by owner first time, after that admin is super role and has permission to change owner
    /// @param _admin Address of multisig that becomes admin
    function setAdminByOwner(address _admin) public {
        require(msg.sender == owner);
        require(admin == address(0));

        admin = _admin;
    }

    /// @notice Admin is able to set new admin
    /// @param _admin Address of multisig that becomes new admin
    function setAdminByAdmin(address _admin) public {
        require(msg.sender == admin);

        admin = _admin;
    }

    /// @notice Admin is able to change owner
    /// @param _owner Address of new owner
    function setOwnerByAdmin(address _owner) public {
        require(msg.sender == admin);

        owner = _owner;
    }

    /// @notice Destroy the contract
    function kill() public onlyOwner {
        selfdestruct(payable(owner));
    }

    /// @notice  withdraw stuck funds
    function withdrawStuckFunds(address _token, uint _amount) public onlyOwner {
        if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
            payable(owner).transfer(_amount);
        } else {
            ERC20(_token).safeTransfer(owner, _amount);
        }
    }
}  contract BotRegistry is AdminAuth {

    mapping (address => bool) public botList;

    constructor() public {
        botList[0x776B4a13093e30B05781F97F6A4565B6aa8BE330] = true;

        botList[0xAED662abcC4FA3314985E67Ea993CAD064a7F5cF] = true;
        botList[0xa5d330F6619d6bF892A5B87D80272e1607b3e34D] = true;
        botList[0x5feB4DeE5150B589a7f567EA7CADa2759794A90A] = true;
        botList[0x7ca06417c1d6f480d3bB195B80692F95A6B66158] = true;
    }

    function setBot(address _botAddr, bool _state) public onlyOwner {
        botList[_botAddr] = _state;
    }

}  abstract contract GasTokenInterface is ERC20 {
    function free(uint256 value) public virtual returns (bool success);

    function freeUpTo(uint256 value) public virtual returns (uint256 freed);

    function freeFrom(address from, uint256 value) public virtual returns (bool success);

    function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed);
}  contract GasBurner {
    // solhint-disable-next-line const-name-snakecase
    GasTokenInterface public constant gasToken = GasTokenInterface(0x0000000000b3F879cb30FE243b4Dfee438691c04);

    modifier burnGas(uint _amount) {
        if (gasToken.balanceOf(address(this)) >= _amount) {
            gasToken.free(_amount);
        }

        _;
    }
}  abstract contract DSProxyInterface {

    /// Truffle wont compile if this isn't commented
    // function execute(bytes memory _code, bytes memory _data)
    //     public virtual
    //     payable
    //     returns (address, bytes32);

    function execute(address _target, bytes memory _data) public virtual payable returns (bytes32);

    function setCache(address _cacheAddr) public virtual payable returns (bool);

    function owner() public virtual returns (address);
}  /// @title Contract with the actuall DSProxy permission calls the automation operations
contract CompoundMonitorProxy is AdminAuth {

    using SafeERC20 for ERC20;

    uint public CHANGE_PERIOD;
    address public monitor;
    address public newMonitor;
    address public lastMonitor;
    uint public changeRequestedTimestamp;

    mapping(address => bool) public allowed;

    event MonitorChangeInitiated(address oldMonitor, address newMonitor);
    event MonitorChangeCanceled();
    event MonitorChangeFinished(address monitor);
    event MonitorChangeReverted(address monitor);

    // if someone who is allowed become malicious, owner can't be changed
    modifier onlyAllowed() {
        require(allowed[msg.sender] || msg.sender == owner);
        _;
    }

    modifier onlyMonitor() {
        require (msg.sender == monitor);
        _;
    }

    constructor(uint _changePeriod) public {
        CHANGE_PERIOD = _changePeriod * 1 days;
    }

    /// @notice Only monitor contract is able to call execute on users proxy
    /// @param _owner Address of cdp owner (users DSProxy address)
    /// @param _compoundSaverProxy Address of CompoundSaverProxy
    /// @param _data Data to send to CompoundSaverProxy
    function callExecute(address _owner, address _compoundSaverProxy, bytes memory _data) public payable onlyMonitor {
        // execute reverts if calling specific method fails
        DSProxyInterface(_owner).execute{value: msg.value}(_compoundSaverProxy, _data);

        // return if anything left
        if (address(this).balance > 0) {
            msg.sender.transfer(address(this).balance);
        }
    }

    /// @notice Allowed users are able to set Monitor contract without any waiting period first time
    /// @param _monitor Address of Monitor contract
    function setMonitor(address _monitor) public onlyAllowed {
        require(monitor == address(0));
        monitor = _monitor;
    }

    /// @notice Allowed users are able to start procedure for changing monitor
    /// @dev after CHANGE_PERIOD needs to call confirmNewMonitor to actually make a change
    /// @param _newMonitor address of new monitor
    function changeMonitor(address _newMonitor) public onlyAllowed {
        require(changeRequestedTimestamp == 0);

        changeRequestedTimestamp = now;
        lastMonitor = monitor;
        newMonitor = _newMonitor;

        emit MonitorChangeInitiated(lastMonitor, newMonitor);
    }

    /// @notice At any point allowed users are able to cancel monitor change
    function cancelMonitorChange() public onlyAllowed {
        require(changeRequestedTimestamp > 0);

        changeRequestedTimestamp = 0;
        newMonitor = address(0);

        emit MonitorChangeCanceled();
    }

    /// @notice Anyone is able to confirm new monitor after CHANGE_PERIOD if process is started
    function confirmNewMonitor() public onlyAllowed {
        require((changeRequestedTimestamp + CHANGE_PERIOD) < now);
        require(changeRequestedTimestamp != 0);
        require(newMonitor != address(0));

        monitor = newMonitor;
        newMonitor = address(0);
        changeRequestedTimestamp = 0;

        emit MonitorChangeFinished(monitor);
    }

    /// @notice Its possible to revert monitor to last used monitor
    function revertMonitor() public onlyAllowed {
        require(lastMonitor != address(0));

        monitor = lastMonitor;

        emit MonitorChangeReverted(monitor);
    }


    /// @notice Allowed users are able to add new allowed user
    /// @param _user Address of user that will be allowed
    function addAllowed(address _user) public onlyAllowed {
        allowed[_user] = true;
    }

    /// @notice Allowed users are able to remove allowed user
    /// @dev owner is always allowed even if someone tries to remove it from allowed mapping
    /// @param _user Address of allowed user
    function removeAllowed(address _user) public onlyAllowed {
        allowed[_user] = false;
    }

    function setChangePeriod(uint _periodInDays) public onlyAllowed {
        require(_periodInDays * 1 days > CHANGE_PERIOD);

        CHANGE_PERIOD = _periodInDays * 1 days;
    }

    /// @notice In case something is left in contract, owner is able to withdraw it
    /// @param _token address of token to withdraw balance
    function withdrawToken(address _token) public onlyOwner {
        uint balance = ERC20(_token).balanceOf(address(this));
        ERC20(_token).safeTransfer(msg.sender, balance);
    }

    /// @notice In case something is left in contract, owner is able to withdraw it
    function withdrawEth() public onlyOwner {
        uint balance = address(this).balance;
        msg.sender.transfer(balance);
    }
}  



/// @title Stores subscription information for Compound automatization
contract CompoundSubscriptions is AdminAuth {

    struct CompoundHolder {
        address user;
        uint128 minRatio;
        uint128 maxRatio;
        uint128 optimalRatioBoost;
        uint128 optimalRatioRepay;
        bool boostEnabled;
    }

    struct SubPosition {
        uint arrPos;
        bool subscribed;
    }

    CompoundHolder[] public subscribers;
    mapping (address => SubPosition) public subscribersPos;

    uint public changeIndex;

    event Subscribed(address indexed user);
    event Unsubscribed(address indexed user);
    event Updated(address indexed user);
    event ParamUpdates(address indexed user, uint128, uint128, uint128, uint128, bool);

    /// @dev Called by the DSProxy contract which owns the Compound position
    /// @notice Adds the users Compound poistion in the list of subscriptions so it can be monitored
    /// @param _minRatio Minimum ratio below which repay is triggered
    /// @param _maxRatio Maximum ratio after which boost is triggered
    /// @param _optimalBoost Ratio amount which boost should target
    /// @param _optimalRepay Ratio amount which repay should target
    /// @param _boostEnabled Boolean determing if boost is enabled
    function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) external {

        // if boost is not enabled, set max ratio to max uint
        uint128 localMaxRatio = _boostEnabled ? _maxRatio : uint128(-1);
        require(checkParams(_minRatio, localMaxRatio), "Must be correct params");

        SubPosition storage subInfo = subscribersPos[msg.sender];

        CompoundHolder memory subscription = CompoundHolder({
                minRatio: _minRatio,
                maxRatio: localMaxRatio,
                optimalRatioBoost: _optimalBoost,
                optimalRatioRepay: _optimalRepay,
                user: msg.sender,
                boostEnabled: _boostEnabled
            });

        changeIndex++;

        if (subInfo.subscribed) {
            subscribers[subInfo.arrPos] = subscription;

            emit Updated(msg.sender);
            emit ParamUpdates(msg.sender, _minRatio, localMaxRatio, _optimalBoost, _optimalRepay, _boostEnabled);
        } else {
            subscribers.push(subscription);

            subInfo.arrPos = subscribers.length - 1;
            subInfo.subscribed = true;

            emit Subscribed(msg.sender);
        }
    }

    /// @notice Called by the users DSProxy
    /// @dev Owner who subscribed cancels his subscription
    function unsubscribe() external {
        _unsubscribe(msg.sender);
    }

    /// @dev Checks limit if minRatio is bigger than max
    /// @param _minRatio Minimum ratio, bellow which repay can be triggered
    /// @param _maxRatio Maximum ratio, over which boost can be triggered
    /// @return Returns bool if the params are correct
    function checkParams(uint128 _minRatio, uint128 _maxRatio) internal pure returns (bool) {

        if (_minRatio > _maxRatio) {
            return false;
        }

        return true;
    }

    /// @dev Internal method to remove a subscriber from the list
    /// @param _user The actual address that owns the Compound position
    function _unsubscribe(address _user) internal {
        require(subscribers.length > 0, "Must have subscribers in the list");

        SubPosition storage subInfo = subscribersPos[_user];

        require(subInfo.subscribed, "Must first be subscribed");

        address lastOwner = subscribers[subscribers.length - 1].user;

        SubPosition storage subInfo2 = subscribersPos[lastOwner];
        subInfo2.arrPos = subInfo.arrPos;

        subscribers[subInfo.arrPos] = subscribers[subscribers.length - 1];
        subscribers.pop(); // remove last element and reduce arr length

        changeIndex++;
        subInfo.subscribed = false;
        subInfo.arrPos = 0;

        emit Unsubscribed(msg.sender);
    }

    /// @dev Checks if the user is subscribed
    /// @param _user The actual address that owns the Compound position
    /// @return If the user is subscribed
    function isSubscribed(address _user) public view returns (bool) {
        SubPosition storage subInfo = subscribersPos[_user];

        return subInfo.subscribed;
    }

    /// @dev Returns subscribtion information about a user
    /// @param _user The actual address that owns the Compound position
    /// @return Subscription information about the user if exists
    function getHolder(address _user) public view returns (CompoundHolder memory) {
        SubPosition storage subInfo = subscribersPos[_user];

        return subscribers[subInfo.arrPos];
    }

    /// @notice Helper method to return all the subscribed CDPs
    /// @return List of all subscribers
    function getSubscribers() public view returns (CompoundHolder[] memory) {
        return subscribers;
    }

    /// @notice Helper method for the frontend, returns all the subscribed CDPs paginated
    /// @param _page What page of subscribers you want
    /// @param _perPage Number of entries per page
    /// @return List of all subscribers for that page
    function getSubscribersByPage(uint _page, uint _perPage) public view returns (CompoundHolder[] memory) {
        CompoundHolder[] memory holders = new CompoundHolder[](_perPage);

        uint start = _page * _perPage;
        uint end = start + _perPage;

        end = (end > holders.length) ? holders.length : end;

        uint count = 0;
        for (uint i = start; i < end; i++) {
            holders[count] = subscribers[i];
            count++;
        }

        return holders;
    }

    ////////////// ADMIN METHODS ///////////////////

    /// @notice Admin function to unsubscribe a CDP
    /// @param _user The actual address that owns the Compound position
    function unsubscribeByAdmin(address _user) public onlyOwner {
        SubPosition storage subInfo = subscribersPos[_user];

        if (subInfo.subscribed) {
            _unsubscribe(_user);
        }
    }
}  contract DSMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x);
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x);
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x / y;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x <= y ? x : y;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x >= y ? x : y;
    }

    function imin(int256 x, int256 y) internal pure returns (int256 z) {
        return x <= y ? x : y;
    }

    function imax(int256 x, int256 y) internal pure returns (int256 z) {
        return x >= y ? x : y;
    }

    uint256 constant WAD = 10**18;
    uint256 constant RAY = 10**27;

    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }

    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, WAD), y / 2) / y;
    }

    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}  contract DefisaverLogger {
    event LogEvent(
        address indexed contractAddress,
        address indexed caller,
        string indexed logName,
        bytes data
    );

    // solhint-disable-next-line func-name-mixedcase
    function Log(address _contract, address _caller, string memory _logName, bytes memory _data)
        public
    {
        emit LogEvent(_contract, _caller, _logName, _data);
    }
}  abstract contract CompoundOracleInterface {
    function getUnderlyingPrice(address cToken) external view virtual returns (uint);
}     

abstract contract ComptrollerInterface {
    struct CompMarketState {
        uint224 index;
        uint32 block;
    }

    function claimComp(address holder) public virtual;
    function claimComp(address holder, address[] memory cTokens) public virtual;
    function claimComp(address[] memory holders, address[] memory cTokens, bool borrowers, bool suppliers) public virtual;

    function compSupplyState(address) public view virtual returns (CompMarketState memory);
    function compSupplierIndex(address,address) public view virtual returns (uint);
    function compAccrued(address) public view virtual returns (uint);

    function compBorrowState(address) public view virtual returns (CompMarketState memory);
    function compBorrowerIndex(address,address) public view virtual returns (uint);

    function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory);

    function exitMarket(address cToken) external virtual returns (uint256);

    function getAssetsIn(address account) external virtual view returns (address[] memory);

    function markets(address account) public virtual view returns (bool, uint256);

    function getAccountLiquidity(address account) external virtual view returns (uint256, uint256, uint256);

    function oracle() public virtual view returns (address);
}  abstract contract CTokenInterface is ERC20 {
    function mint(uint256 mintAmount) external virtual returns (uint256);

    // function mint() external virtual payable;

    function accrueInterest() public virtual returns (uint);

    function redeem(uint256 redeemTokens) external virtual returns (uint256);

    function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);

    function borrow(uint256 borrowAmount) external virtual returns (uint256);
    function borrowIndex() public view virtual returns (uint);
    function borrowBalanceStored(address) public view virtual returns(uint);

    function repayBorrow(uint256 repayAmount) external virtual returns (uint256);

    function repayBorrow() external virtual payable;

    function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);

    function repayBorrowBehalf(address borrower) external virtual payable;

    function liquidateBorrow(address borrower, uint256 repayAmount, address cTokenCollateral)
        external virtual
        returns (uint256);

    function liquidateBorrow(address borrower, address cTokenCollateral) external virtual payable;

    function exchangeRateCurrent() external virtual returns (uint256);

    function supplyRatePerBlock() external virtual returns (uint256);

    function borrowRatePerBlock() external virtual returns (uint256);

    function totalReserves() external virtual returns (uint256);

    function reserveFactorMantissa() external virtual returns (uint256);

    function borrowBalanceCurrent(address account) external virtual returns (uint256);

    function totalBorrowsCurrent() external virtual returns (uint256);

    function getCash() external virtual returns (uint256);

    function balanceOfUnderlying(address owner) external virtual returns (uint256);

    function underlying() external virtual returns (address);

    function getAccountSnapshot(address account) external virtual view returns (uint, uint, uint, uint);
}  contract CarefulMath {

    /**
     * @dev Possible error codes that we can return
     */
    enum MathError {
        NO_ERROR,
        DIVISION_BY_ZERO,
        INTEGER_OVERFLOW,
        INTEGER_UNDERFLOW
    }

    /**
    * @dev Multiplies two numbers, returns an error on overflow.
    */
    function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (a == 0) {
            return (MathError.NO_ERROR, 0);
        }

        uint c = a * b;

        if (c / a != b) {
            return (MathError.INTEGER_OVERFLOW, 0);
        } else {
            return (MathError.NO_ERROR, c);
        }
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b == 0) {
            return (MathError.DIVISION_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a / b);
    }

    /**
    * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
    */
    function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b <= a) {
            return (MathError.NO_ERROR, a - b);
        } else {
            return (MathError.INTEGER_UNDERFLOW, 0);
        }
    }

    /**
    * @dev Adds two numbers, returns an error on overflow.
    */
    function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
        uint c = a + b;

        if (c >= a) {
            return (MathError.NO_ERROR, c);
        } else {
            return (MathError.INTEGER_OVERFLOW, 0);
        }
    }

    /**
    * @dev add a and b and then subtract c
    */
    function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
        (MathError err0, uint sum) = addUInt(a, b);

        if (err0 != MathError.NO_ERROR) {
            return (err0, 0);
        }

        return subUInt(sum, c);
    }
}  contract Exponential is CarefulMath {
    uint constant expScale = 1e18;
    uint constant doubleScale = 1e36;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

    /**
     * @dev Creates an exponential from numerator and denominator values.
     *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
     *            or if `denom` is zero.
     */
    function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        (MathError err1, uint rational) = divUInt(scaledNumerator, denom);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: rational}));
    }

    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Multiply an Exp by a scalar, returning a new Exp.
     */
    function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(product));
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return addUInt(truncate(product), addend);
    }

    /**
     * @dev Divide an Exp by a scalar, returning a new Exp.
     */
    function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
    }

    /**
     * @dev Divide a scalar by an Exp, returning a new Exp.
     */
    function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
        /*
          We are doing this as:
          getExp(mulUInt(expScale, scalar), divisor.mantissa)

          How it works:
          Exp = a / b;
          Scalar = s;
          `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
        (MathError err0, uint numerator) = mulUInt(expScale, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }
        return getExp(numerator, divisor.mantissa);
    }

    /**
     * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
     */
    function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
        (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(fraction));
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {

        (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        // We add half the scale before dividing so that we get rounding instead of truncation.
        //  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
        // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
        (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
        // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
        assert(err2 == MathError.NO_ERROR);

        return (MathError.NO_ERROR, Exp({mantissa: product}));
    }

    /**
     * @dev Multiplies two exponentials given their mantissas, returning a new exponential.
     */
    function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
        return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
    }

    /**
     * @dev Multiplies three exponentials, returning a new exponential.
     */
    function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
        (MathError err, Exp memory ab) = mulExp(a, b);
        if (err != MathError.NO_ERROR) {
            return (err, ab);
        }
        return mulExp(ab, c);
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
     *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
     */
    function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        return getExp(a.mantissa, b.mantissa);
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if left Exp > right Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return sub_(a, b, "subtraction underflow");
    }

    function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return mul_(a, b, "multiplication overflow");
    }

    function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        if (a == 0 || b == 0) {
            return 0;
        }
        uint c = a * b;
        require(c / a == b, errorMessage);
        return c;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return div_(a, b, "divide by zero");
    }

    function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b > 0, errorMessage);
        return a / b;
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return add_(a, b, "addition overflow");
    }

    function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        uint c = a + b;
        require(c >= a, errorMessage);
        return c;
    }
}  contract CompoundSafetyRatio is Exponential, DSMath {
    // solhint-disable-next-line const-name-snakecase
    ComptrollerInterface public constant comp = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);

    /// @notice Calcualted the ratio of debt / adjusted collateral
    /// @param _user Address of the user
    function getSafetyRatio(address _user) public view returns (uint) {
        // For each asset the account is in
        address[] memory assets = comp.getAssetsIn(_user);
        address oracleAddr = comp.oracle();


        uint sumCollateral = 0;
        uint sumBorrow = 0;

        for (uint i = 0; i < assets.length; i++) {
            address asset = assets[i];

            (, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa)
                                        = CTokenInterface(asset).getAccountSnapshot(_user);

            Exp memory oraclePrice;

            if (cTokenBalance != 0 || borrowBalance != 0) {
                oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)});
            }

            // Sum up collateral in Usd
            if (cTokenBalance != 0) {

                (, uint collFactorMantissa) = comp.markets(address(asset));

                Exp memory collateralFactor = Exp({mantissa: collFactorMantissa});
                Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa});

                (, Exp memory tokensToUsd) = mulExp3(collateralFactor, exchangeRate, oraclePrice);

                (, sumCollateral) = mulScalarTruncateAddUInt(tokensToUsd, cTokenBalance, sumCollateral);
            }

            // Sum up debt in Usd
            if (borrowBalance != 0) {
                (, sumBorrow) = mulScalarTruncateAddUInt(oraclePrice, borrowBalance, sumBorrow);
            }
        }

        if (sumBorrow == 0) return uint(-1);

        uint borrowPowerUsed = (sumBorrow * 10**18) / sumCollateral;
        return wdiv(1e18, borrowPowerUsed);
    }
}  abstract contract TokenInterface {
    function allowance(address, address) public virtual returns (uint256);

    function balanceOf(address) public virtual returns (uint256);

    function approve(address, uint256) public virtual;

    function transfer(address, uint256) public virtual returns (bool);

    function transferFrom(address, address, uint256) public virtual returns (bool);

    function deposit() public virtual payable;

    function withdraw(uint256) public virtual;
}  interface ExchangeInterfaceV2 {
    function sell(address _srcAddr, address _destAddr, uint _srcAmount) external payable returns (uint);

    function buy(address _srcAddr, address _destAddr, uint _destAmount) external payable returns(uint);

    function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint);

    function getBuyRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint);
}  contract ZrxAllowlist is AdminAuth {

    mapping (address => bool) public zrxAllowlist;
    mapping(address => bool) private nonPayableAddrs;

    constructor() public {
        zrxAllowlist[0x6958F5e95332D93D21af0D7B9Ca85B8212fEE0A5] = true;
        zrxAllowlist[0x61935CbDd02287B511119DDb11Aeb42F1593b7Ef] = true;
        zrxAllowlist[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true;
        zrxAllowlist[0x080bf510FCbF18b91105470639e9561022937712] = true;

        nonPayableAddrs[0x080bf510FCbF18b91105470639e9561022937712] = true;
    }

    function setAllowlistAddr(address _zrxAddr, bool _state) public onlyOwner {
        zrxAllowlist[_zrxAddr] = _state;
    }

    function isZrxAddr(address _zrxAddr) public view returns (bool) {
        return zrxAllowlist[_zrxAddr];
    }

    function addNonPayableAddr(address _nonPayableAddr) public onlyOwner {
		nonPayableAddrs[_nonPayableAddr] = true;
	}

	function removeNonPayableAddr(address _nonPayableAddr) public onlyOwner {
		nonPayableAddrs[_nonPayableAddr] = false;
	}

	function isNonPayableAddr(address _addr) public view returns(bool) {
		return nonPayableAddrs[_addr];
	}
}  contract Discount {
    address public owner;
    mapping(address => CustomServiceFee) public serviceFees;

    uint256 constant MAX_SERVICE_FEE = 400;

    struct CustomServiceFee {
        bool active;
        uint256 amount;
    }

    constructor() public {
        owner = msg.sender;
    }

    function isCustomFeeSet(address _user) public view returns (bool) {
        return serviceFees[_user].active;
    }

    function getCustomServiceFee(address _user) public view returns (uint256) {
        return serviceFees[_user].amount;
    }

    function setServiceFee(address _user, uint256 _fee) public {
        require(msg.sender == owner, "Only owner");
        require(_fee >= MAX_SERVICE_FEE || _fee == 0);

        serviceFees[_user] = CustomServiceFee({active: true, amount: _fee});
    }

    function disableServiceFee(address _user) public {
        require(msg.sender == owner, "Only owner");

        serviceFees[_user] = CustomServiceFee({active: false, amount: 0});
    }
}  contract SaverExchangeHelper {

    using SafeERC20 for ERC20;

    address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08;
    address public constant DISCOUNT_ADDRESS = 0x1b14E8D511c9A4395425314f849bD737BAF8208F;
    address public constant SAVER_EXCHANGE_REGISTRY = 0x25dd3F51e0C3c3Ff164DDC02A8E4D65Bb9cBB12D;

    address public constant ERC20_PROXY_0X = 0x95E6F48254609A6ee006F7D493c8e5fB97094ceF;
    address public constant ZRX_ALLOWLIST_ADDR = 0x4BA1f38427b33B8ab7Bb0490200dAE1F1C36823F;


    function getDecimals(address _token) internal view returns (uint256) {
        if (_token == KYBER_ETH_ADDRESS) return 18;

        return ERC20(_token).decimals();
    }

    function getBalance(address _tokenAddr) internal view returns (uint balance) {
        if (_tokenAddr == KYBER_ETH_ADDRESS) {
            balance = address(this).balance;
        } else {
            balance = ERC20(_tokenAddr).balanceOf(address(this));
        }
    }

    function approve0xProxy(address _tokenAddr, uint _amount) internal {
        if (_tokenAddr != KYBER_ETH_ADDRESS) {
            ERC20(_tokenAddr).safeApprove(address(ERC20_PROXY_0X), _amount);
        }
    }

    function sendLeftover(address _srcAddr, address _destAddr, address payable _to) internal {
        // send back any leftover ether or tokens
        if (address(this).balance > 0) {
            _to.transfer(address(this).balance);
        }

        if (getBalance(_srcAddr) > 0) {
            ERC20(_srcAddr).safeTransfer(_to, getBalance(_srcAddr));
        }

        if (getBalance(_destAddr) > 0) {
            ERC20(_destAddr).safeTransfer(_to, getBalance(_destAddr));
        }
    }

    function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) {
        require(bs.length >= start + 32, "slicing out of range");

        uint256 x;
        assembly {
            x := mload(add(bs, add(0x20, start)))
        }

        return x;
    }
}  contract SaverExchangeRegistry is AdminAuth {

	mapping(address => bool) private wrappers;

	constructor() public {
		wrappers[0x880A845A85F843a5c67DB2061623c6Fc3bB4c511] = true;
		wrappers[0x4c9B55f2083629A1F7aDa257ae984E03096eCD25] = true;
		wrappers[0x42A9237b872368E1bec4Ca8D26A928D7d39d338C] = true;
	}

	function addWrapper(address _wrapper) public onlyOwner {
		wrappers[_wrapper] = true;
	}

	function removeWrapper(address _wrapper) public onlyOwner {
		wrappers[_wrapper] = false;
	}

	function isWrapper(address _wrapper) public view returns(bool) {
		return wrappers[_wrapper];
	}
}     








contract SaverExchangeCore is SaverExchangeHelper, DSMath {

    // first is empty to keep the legacy order in place
    enum ExchangeType { _, OASIS, KYBER, UNISWAP, ZEROX }

    enum ActionType { SELL, BUY }

    struct ExchangeData {
        address srcAddr;
        address destAddr;
        uint srcAmount;
        uint destAmount;
        uint minPrice;
        address wrapper;
        address exchangeAddr;
        bytes callData;
        uint256 price0x;
    }

    /// @notice Internal method that preforms a sell on 0x/on-chain
    /// @dev Usefull for other DFS contract to integrate for exchanging
    /// @param exData Exchange data struct
    /// @return (address, uint) Address of the wrapper used and destAmount
    function _sell(ExchangeData memory exData) internal returns (address, uint) {

        address wrapper;
        uint swapedTokens;
        bool success;
        uint tokensLeft = exData.srcAmount;

        // if selling eth, convert to weth
        if (exData.srcAddr == KYBER_ETH_ADDRESS) {
            exData.srcAddr = ethToWethAddr(exData.srcAddr);
            TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)();
        }

        // Try 0x first and then fallback on specific wrapper
        if (exData.price0x > 0) {
            approve0xProxy(exData.srcAddr, exData.srcAmount);

            uint ethAmount = getProtocolFee(exData.srcAddr, exData.srcAmount);
            (success, swapedTokens, tokensLeft) = takeOrder(exData, ethAmount, ActionType.SELL);

            if (success) {
                wrapper = exData.exchangeAddr;
            }
        }

        // fallback to desired wrapper if 0x failed
        if (!success) {
            swapedTokens = saverSwap(exData, ActionType.SELL);
            wrapper = exData.wrapper;
        }

        require(getBalance(exData.destAddr) >= wmul(exData.minPrice, exData.srcAmount), "Final amount isn't correct");

        // if anything is left in weth, pull it to user as eth
        if (getBalance(WETH_ADDRESS) > 0) {
            TokenInterface(WETH_ADDRESS).withdraw(
                TokenInterface(WETH_ADDRESS).balanceOf(address(this))
            );
        }

        return (wrapper, swapedTokens);
    }

    /// @notice Internal method that preforms a buy on 0x/on-chain
    /// @dev Usefull for other DFS contract to integrate for exchanging
    /// @param exData Exchange data struct
    /// @return (address, uint) Address of the wrapper used and srcAmount
    function _buy(ExchangeData memory exData) internal returns (address, uint) {

        address wrapper;
        uint swapedTokens;
        bool success;

        require(exData.destAmount != 0, "Dest amount must be specified");

        // if selling eth, convert to weth
        if (exData.srcAddr == KYBER_ETH_ADDRESS) {
            exData.srcAddr = ethToWethAddr(exData.srcAddr);
            TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)();
        }

        if (exData.price0x > 0) {
            approve0xProxy(exData.srcAddr, exData.srcAmount);

            uint ethAmount = getProtocolFee(exData.srcAddr, exData.srcAmount);
            (success, swapedTokens,) = takeOrder(exData, ethAmount, ActionType.BUY);

            if (success) {
                wrapper = exData.exchangeAddr;
            }
        }

        // fallback to desired wrapper if 0x failed
        if (!success) {
            swapedTokens = saverSwap(exData, ActionType.BUY);
            wrapper = exData.wrapper;
        }

        require(getBalance(exData.destAddr) >= exData.destAmount, "Final amount isn't correct");

        // if anything is left in weth, pull it to user as eth
        if (getBalance(WETH_ADDRESS) > 0) {
            TokenInterface(WETH_ADDRESS).withdraw(
                TokenInterface(WETH_ADDRESS).balanceOf(address(this))
            );
        }

        return (wrapper, getBalance(exData.destAddr));
    }

    /// @notice Takes order from 0x and returns bool indicating if it is successful
    /// @param _exData Exchange data
    /// @param _ethAmount Ether fee needed for 0x order
    function takeOrder(
        ExchangeData memory _exData,
        uint256 _ethAmount,
        ActionType _type
    ) private returns (bool success, uint256, uint256) {

        // write in the exact amount we are selling/buing in an order
        if (_type == ActionType.SELL) {
            writeUint256(_exData.callData, 36, _exData.srcAmount);
        } else {
            writeUint256(_exData.callData, 36, _exData.destAmount);
        }

        if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isNonPayableAddr(_exData.exchangeAddr)) {
            _ethAmount = 0;
        }

        uint256 tokensBefore = getBalance(_exData.destAddr);

        if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isZrxAddr(_exData.exchangeAddr)) {
            (success, ) = _exData.exchangeAddr.call{value: _ethAmount}(_exData.callData);
        } else {
            success = false;
        }

        uint256 tokensSwaped = 0;
        uint256 tokensLeft = _exData.srcAmount;

        if (success) {
            // check to see if any _src tokens are left over after exchange
            tokensLeft = getBalance(_exData.srcAddr);

            // convert weth -> eth if needed
            if (_exData.destAddr == KYBER_ETH_ADDRESS) {
                TokenInterface(WETH_ADDRESS).withdraw(
                    TokenInterface(WETH_ADDRESS).balanceOf(address(this))
                );
            }

            // get the current balance of the swaped tokens
            tokensSwaped = getBalance(_exData.destAddr) - tokensBefore;
        }

        return (success, tokensSwaped, tokensLeft);
    }

    /// @notice Calls wraper contract for exchage to preform an on-chain swap
    /// @param _exData Exchange data struct
    /// @param _type Type of action SELL|BUY
    /// @return swapedTokens For Sell that the destAmount, for Buy thats the srcAmount
    function saverSwap(ExchangeData memory _exData, ActionType _type) internal returns (uint swapedTokens) {
        require(SaverExchangeRegistry(SAVER_EXCHANGE_REGISTRY).isWrapper(_exData.wrapper), "Wrapper is not valid");

        uint ethValue = 0;

        ERC20(_exData.srcAddr).safeTransfer(_exData.wrapper, _exData.srcAmount);

        if (_type == ActionType.SELL) {
            swapedTokens = ExchangeInterfaceV2(_exData.wrapper).
                    sell{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.srcAmount);
        } else {
            swapedTokens = ExchangeInterfaceV2(_exData.wrapper).
                    buy{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.destAmount);
        }
    }

    function writeUint256(bytes memory _b, uint256 _index, uint _input) internal pure {
        if (_b.length < _index + 32) {
            revert("Incorrent lengt while writting bytes32");
        }

        bytes32 input = bytes32(_input);

        _index += 32;

        // Read the bytes32 from array memory
        assembly {
            mstore(add(_b, _index), input)
        }
    }

    /// @notice Converts Kybers Eth address -> Weth
    /// @param _src Input address
    function ethToWethAddr(address _src) internal pure returns (address) {
        return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src;
    }

    /// @notice Calculates protocol fee
    /// @param _srcAddr selling token address (if eth should be WETH)
    /// @param _srcAmount amount we are selling
    function getProtocolFee(address _srcAddr, uint256 _srcAmount) internal view returns(uint256) {
        // if we are not selling ETH msg value is always the protocol fee
        if (_srcAddr != WETH_ADDRESS) return address(this).balance;

        // if msg value is larger than srcAmount, that means that msg value is protocol fee + srcAmount, so we subsctract srcAmount from msg value
        // we have an edge case here when protocol fee is higher than selling amount
        if (address(this).balance > _srcAmount) return address(this).balance - _srcAmount;

        // if msg value is lower than src amount, that means that srcAmount isn't included in msg value, so we return msg value
        return address(this).balance;
    }

    function packExchangeData(ExchangeData memory _exData) public pure returns(bytes memory) {
        // splitting in two different bytes and encoding all because of stack too deep in decoding part

        bytes memory part1 = abi.encode(
            _exData.srcAddr,
            _exData.destAddr,
            _exData.srcAmount,
            _exData.destAmount
        );

        bytes memory part2 = abi.encode(
            _exData.minPrice,
            _exData.wrapper,
            _exData.exchangeAddr,
            _exData.callData,
            _exData.price0x
        );


        return abi.encode(part1, part2);
    }

    function unpackExchangeData(bytes memory _data) public pure returns(ExchangeData memory _exData) {
        (
            bytes memory part1,
            bytes memory part2
        ) = abi.decode(_data, (bytes,bytes));

        (
            _exData.srcAddr,
            _exData.destAddr,
            _exData.srcAmount,
            _exData.destAmount
        ) = abi.decode(part1, (address,address,uint256,uint256));

        (
            _exData.minPrice,
            _exData.wrapper,
            _exData.exchangeAddr,
            _exData.callData,
            _exData.price0x
        )
        = abi.decode(part2, (uint256,address,address,bytes,uint256));
    }

    // solhint-disable-next-line no-empty-blocks
    receive() external virtual payable {}
}     












/// @title Contract implements logic of calling boost/repay in the automatic system
contract CompoundMonitor is AdminAuth, DSMath, CompoundSafetyRatio, GasBurner {

    using SafeERC20 for ERC20;

    enum Method { Boost, Repay }

    uint public REPAY_GAS_TOKEN = 20;
    uint public BOOST_GAS_TOKEN = 20;

    uint constant public MAX_GAS_PRICE = 500000000000; // 500 gwei

    uint public REPAY_GAS_COST = 2000000;
    uint public BOOST_GAS_COST = 2000000;

    address public constant GAS_TOKEN_INTERFACE_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
    address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
    address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;

    CompoundMonitorProxy public compoundMonitorProxy;
    CompoundSubscriptions public subscriptionsContract;
    address public compoundFlashLoanTakerAddress;

    DefisaverLogger public logger = DefisaverLogger(DEFISAVER_LOGGER);

    modifier onlyApproved() {
        require(BotRegistry(BOT_REGISTRY_ADDRESS).botList(msg.sender), "Not auth bot");
        _;
    }

    /// @param _compoundMonitorProxy Proxy contracts that actually is authorized to call DSProxy
    /// @param _subscriptions Subscriptions contract for Compound positions
    /// @param _compoundFlashLoanTaker Contract that actually performs Repay/Boost
    constructor(address _compoundMonitorProxy, address _subscriptions, address _compoundFlashLoanTaker) public {
        compoundMonitorProxy = CompoundMonitorProxy(_compoundMonitorProxy);
        subscriptionsContract = CompoundSubscriptions(_subscriptions);
        compoundFlashLoanTakerAddress = _compoundFlashLoanTaker;
    }

    /// @notice Bots call this method to repay for user when conditions are met
    /// @dev If the contract ownes gas token it will try and use it for gas price reduction
    /// @param _exData Exchange data
    /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress]
    /// @param _user The actual address that owns the Compound position
    function repayFor(
        SaverExchangeCore.ExchangeData memory _exData,
        address[2] memory _cAddresses, // cCollAddress, cBorrowAddress
        address _user
    ) public payable onlyApproved burnGas(REPAY_GAS_TOKEN) {

        (bool isAllowed, uint ratioBefore) = canCall(Method.Repay, _user);
        require(isAllowed); // check if conditions are met

        uint256 gasCost = calcGasCost(REPAY_GAS_COST);

        compoundMonitorProxy.callExecute{value: msg.value}(
            _user,
            compoundFlashLoanTakerAddress,
            abi.encodeWithSignature(
                "repayWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)",
                _exData,
                _cAddresses,
                gasCost
            )
        );

        (bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Repay, _user);
        require(isGoodRatio); // check if the after result of the actions is good

        returnEth();

        logger.Log(address(this), _user, "AutomaticCompoundRepay", abi.encode(ratioBefore, ratioAfter));
    }

    /// @notice Bots call this method to boost for user when conditions are met
    /// @dev If the contract ownes gas token it will try and use it for gas price reduction
    /// @param _exData Exchange data
    /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress]
    /// @param _user The actual address that owns the Compound position
    function boostFor(
        SaverExchangeCore.ExchangeData memory _exData,
        address[2] memory _cAddresses, // cCollAddress, cBorrowAddress
        address _user
    ) public payable onlyApproved burnGas(BOOST_GAS_TOKEN) {

        (bool isAllowed, uint ratioBefore) = canCall(Method.Boost, _user);
        require(isAllowed); // check if conditions are met

        uint256 gasCost = calcGasCost(BOOST_GAS_COST);

        compoundMonitorProxy.callExecute{value: msg.value}(
            _user,
            compoundFlashLoanTakerAddress,
            abi.encodeWithSignature(
                "boostWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)",
                _exData,
                _cAddresses,
                gasCost
            )
        );


        (bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Boost, _user);
        require(isGoodRatio);  // check if the after result of the actions is good

        returnEth();

        logger.Log(address(this), _user, "AutomaticCompoundBoost", abi.encode(ratioBefore, ratioAfter));
    }

/******************* INTERNAL METHODS ********************************/
    function returnEth() internal {
        // return if some eth left
        if (address(this).balance > 0) {
            msg.sender.transfer(address(this).balance);
        }
    }

/******************* STATIC METHODS ********************************/

    /// @notice Checks if Boost/Repay could be triggered for the CDP
    /// @dev Called by MCDMonitor to enforce the min/max check
    /// @param _method Type of action to be called
    /// @param _user The actual address that owns the Compound position
    /// @return Boolean if it can be called and the ratio
    function canCall(Method _method, address _user) public view returns(bool, uint) {
        bool subscribed = subscriptionsContract.isSubscribed(_user);
        CompoundSubscriptions.CompoundHolder memory holder = subscriptionsContract.getHolder(_user);

        // check if cdp is subscribed
        if (!subscribed) return (false, 0);

        // check if boost and boost allowed
        if (_method == Method.Boost && !holder.boostEnabled) return (false, 0);

        uint currRatio = getSafetyRatio(_user);

        if (_method == Method.Repay) {
            return (currRatio < holder.minRatio, currRatio);
        } else if (_method == Method.Boost) {
            return (currRatio > holder.maxRatio, currRatio);
        }
    }

    /// @dev After the Boost/Repay check if the ratio doesn't trigger another call
    /// @param _method Type of action to be called
    /// @param _user The actual address that owns the Compound position
    /// @return Boolean if the recent action preformed correctly and the ratio
    function ratioGoodAfter(Method _method, address _user) public view returns(bool, uint) {
        CompoundSubscriptions.CompoundHolder memory holder;

        holder= subscriptionsContract.getHolder(_user);

        uint currRatio = getSafetyRatio(_user);

        if (_method == Method.Repay) {
            return (currRatio < holder.maxRatio, currRatio);
        } else if (_method == Method.Boost) {
            return (currRatio > holder.minRatio, currRatio);
        }
    }

    /// @notice Calculates gas cost (in Eth) of tx
    /// @dev Gas price is limited to MAX_GAS_PRICE to prevent attack of draining user CDP
    /// @param _gasAmount Amount of gas used for the tx
    function calcGasCost(uint _gasAmount) public view returns (uint) {
        uint gasPrice = tx.gasprice <= MAX_GAS_PRICE ? tx.gasprice : MAX_GAS_PRICE;

        return mul(gasPrice, _gasAmount);
    }

/******************* OWNER ONLY OPERATIONS ********************************/

    /// @notice As the code is new, have a emergancy admin saver proxy change
    function changeCompoundFlashLoanTaker(address _newCompoundFlashLoanTakerAddress) public onlyAdmin {
        compoundFlashLoanTakerAddress = _newCompoundFlashLoanTakerAddress;
    }

    /// @notice Allows owner to change gas cost for boost operation, but only up to 3 millions
    /// @param _gasCost New gas cost for boost method
    function changeBoostGasCost(uint _gasCost) public onlyOwner {
        require(_gasCost < 3000000);

        BOOST_GAS_COST = _gasCost;
    }

    /// @notice Allows owner to change gas cost for repay operation, but only up to 3 millions
    /// @param _gasCost New gas cost for repay method
    function changeRepayGasCost(uint _gasCost) public onlyOwner {
        require(_gasCost < 3000000);

        REPAY_GAS_COST = _gasCost;
    }

    /// @notice If any tokens gets stuck in the contract owner can withdraw it
    /// @param _tokenAddress Address of the ERC20 token
    /// @param _to Address of the receiver
    /// @param _amount The amount to be sent
    function transferERC20(address _tokenAddress, address _to, uint _amount) public onlyOwner {
        ERC20(_tokenAddress).safeTransfer(_to, _amount);
    }

    /// @notice If any Eth gets stuck in the contract owner can withdraw it
    /// @param _to Address of the receiver
    /// @param _amount The amount to be sent
    function transferEth(address payable _to, uint _amount) public onlyOwner {
        _to.transfer(_amount);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_compoundMonitorProxy","type":"address"},{"internalType":"address","name":"_subscriptions","type":"address"},{"internalType":"address","name":"_compoundFlashLoanTaker","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BOOST_GAS_COST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOOST_GAS_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOT_REGISTRY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFISAVER_LOGGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAS_TOKEN_INTERFACE_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GAS_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPAY_GAS_COST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPAY_GAS_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"},{"internalType":"address[2]","name":"_cAddresses","type":"address[2]"},{"internalType":"address","name":"_user","type":"address"}],"name":"boostFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasAmount","type":"uint256"}],"name":"calcGasCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum CompoundMonitor.Method","name":"_method","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"canCall","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCost","type":"uint256"}],"name":"changeBoostGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCompoundFlashLoanTakerAddress","type":"address"}],"name":"changeCompoundFlashLoanTaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCost","type":"uint256"}],"name":"changeRepayGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comp","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundFlashLoanTakerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundMonitorProxy","outputs":[{"internalType":"contract CompoundMonitorProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasToken","outputs":[{"internalType":"contract GasTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getSafetyRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum CompoundMonitor.Method","name":"_method","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"ratioGoodAfter","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"},{"internalType":"address[2]","name":"_cAddresses","type":"address[2]"},{"internalType":"address","name":"_user","type":"address"}],"name":"repayFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwnerByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subscriptionsContract","outputs":[{"internalType":"contract CompoundSubscriptions","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260146002819055600355621e84806004819055600555600980546001600160a01b031916735c55b921f590a89c1ebe84df170e655a82b621261790553480156200004d57600080fd5b5060405162002528380380620025288339810160408190526200007091620000dc565b600080546001600160a01b031990811633179091556001805482167325efa336886c74ea8e282ac466bdcd0199f85bb9179055600680546001600160a01b0395861690831617905560078054938516938216939093179092556008805491909316911617905562000148565b600080600060608486031215620000f1578283fd5b8351620000fe816200012f565b602085015190935062000111816200012f565b604085015190925062000124816200012f565b809150509250925092565b6001600160a01b03811681146200014557600080fd5b50565b6123d080620001586000396000f3fe6080604052600436106101e35760003560e01c80638da5cb5b11610102578063c91d59fe11610095578063e9bb84c211610064578063e9bb84c2146104d2578063ec23ef27146104f2578063f24ccbfe14610507578063f851a4401461051c576101e3565b8063c91d59fe146102cd578063d98bb5b11461047d578063deca5f881461049d578063e3bbb4f1146104bd576101e3565b8063a56f9718116100d1578063a56f971814610408578063a7304bf71461041d578063a8c903231461043d578063bfc361721461045d576101e3565b80638da5cb5b146103a057806398a3f265146103b55780639da6136b146103c85780639db5dbe4146103e8576101e3565b806336fc603f1161017a5780634d3f199e116101495780634d3f199e14610341578063526d646114610361578063696806c01461037657806379521f021461038b576101e3565b806336fc603f146102e257806339df1878146102f75780633a1283221461030c57806341c0e1b51461032c576101e3565b80631e48907b116101b65780631e48907b1461027857806329ad0f36146102985780632a56f602146102ad57806332ac5cd2146102cd576101e3565b806306d5e37e146101e8578063109d0af81461021f578063139198941461024157806318bf60e114610256575b600080fd5b3480156101f457600080fd5b50610208610203366004611da5565b610531565b604051610216929190612175565b60405180910390f35b34801561022b57600080fd5b506102346106fd565b604051610216919061205f565b61025461024f366004611e6e565b610715565b005b34801561026257600080fd5b5061026b610a6a565b60405161021691906122f8565b34801561028457600080fd5b50610254610293366004611bf1565b610a70565b3480156102a457600080fd5b50610234610aa9565b3480156102b957600080fd5b5061026b6102c8366004611f73565b610ab8565b3480156102d957600080fd5b50610234610aea565b3480156102ee57600080fd5b5061026b610afd565b34801561030357600080fd5b50610234610b03565b34801561031857600080fd5b50610254610327366004611c9b565b610b1b565b34801561033857600080fd5b50610254610bb4565b34801561034d57600080fd5b5061025461035c366004611f73565b610bd9565b34801561036d57600080fd5b50610234610c04565b34801561038257600080fd5b5061026b610c1c565b34801561039757600080fd5b50610234610c22565b3480156103ac57600080fd5b50610234610c31565b6102546103c3366004611e6e565b610c40565b3480156103d457600080fd5b506102546103e3366004611bf1565b610f4f565b3480156103f457600080fd5b50610254610403366004611c5b565b610f88565b34801561041457600080fd5b5061026b610fb8565b34801561042957600080fd5b50610254610438366004611bf1565b610fbe565b34801561044957600080fd5b50610254610458366004611f73565b610ff7565b34801561046957600080fd5b50610208610478366004611da5565b611022565b34801561048957600080fd5b5061026b610498366004611bf1565b611121565b3480156104a957600080fd5b506102546104b8366004611bf1565b6114e7565b3480156104c957600080fd5b5061026b611514565b3480156104de57600080fd5b506102546104ed366004611c30565b61151d565b3480156104fe57600080fd5b5061023461156a565b34801561051357600080fd5b50610234611579565b34801561052857600080fd5b50610234611588565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c9061056690879060040161205f565b60206040518083038186803b15801561057e57600080fd5b505afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b69190611d58565b90506105c0611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105f090889060040161205f565b60c06040518083038186803b15801561060857600080fd5b505afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190611de0565b905081610655576000809350935050506106f6565b600086600181111561066357fe5b14801561067257508060a00151155b15610685576000809350935050506106f6565b600061069086611121565b905060018760018111156106a057fe5b14156106c2576020909101516001600160801b03168110935091506106f69050565b60008760018111156106d057fe5b14156106f2576040909101516001600160801b03168111935091506106f69050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061074c90339060040161205f565b60206040518083038186803b15801561076457600080fd5b505afa158015610778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079c9190611d58565b6107c15760405162461bcd60e51b81526004016107b8906121cf565b60405180910390fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a08231906107f890309060040161205f565b60206040518083038186803b15801561081057600080fd5b505afa158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190611f8b565b106108d35760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f39061087f9084906004016122f8565b602060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d19190611d58565b505b6000806108e1600085610531565b91509150816108ef57600080fd5b60006108fc600554610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610933908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b031916815261097e93929190600401612073565b6000604051808303818588803b15801561099757600080fd5b505af11580156109ab573d6000803e3d6000fd5b50505050506000806109be600088611022565b91509150816109cc57600080fd5b6109d4611597565b6009546040516001600160a01b039091169063d061ce509030908a90610a009089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d93929190612102565b600060405180830381600087803b158015610a4757600080fd5b505af1158015610a5b573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b03163314610a8757600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610ad35764746a528800610ad5565b3a5b9050610ae181846115cd565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610b3257600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610b9657600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610b90573d6000803e3d6000fd5b50610bb0565b600054610bb0906001600160a01b038481169116836115f7565b5050565b6000546001600160a01b03163314610bcb57600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610bf057600080fd5b622dc6c08110610bff57600080fd5b600455565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60035481565b6007546001600160a01b031681565b6000546001600160a01b031681565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da90610c7790339060040161205f565b60206040518083038186803b158015610c8f57600080fd5b505afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc79190611d58565b610ce35760405162461bcd60e51b81526004016107b8906121cf565b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610d1a90309060040161205f565b60206040518083038186803b158015610d3257600080fd5b505afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a9190611f8b565b10610df55760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610da19084906004016122f8565b602060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df39190611d58565b505b600080610e03600185610531565b9150915081610e1157600080fd5b6000610e1e600454610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610e55908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610ea093929190600401612073565b6000604051808303818588803b158015610eb957600080fd5b505af1158015610ecd573d6000803e3d6000fd5b5050505050600080610ee0600188611022565b9150915081610eee57600080fd5b610ef6611597565b6009546040516001600160a01b039091169063d061ce509030908a90610f229089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d939291906120a8565b6001546001600160a01b03163314610f6657600080fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f9f57600080fd5b610fb36001600160a01b03841683836115f7565b505050565b60025481565b6001546001600160a01b03163314610fd557600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461100e57600080fd5b622dc6c0811061101d57600080fd5b600555565b60008061102d611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d49061105d90879060040161205f565b60c06040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190611de0565b905060006110ba85611121565b905060018660018111156110ca57fe5b14156110ea576040909101516001600160801b03168110925090506106f6565b60008660018111156110f857fe5b1415611118576020909101516001600160801b03168111925090506106f6565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061115e90869060040161205f565b60006040518083038186803b15801561117657600080fd5b505afa15801561118a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b29190810190611cad565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190611c14565b905060008060005b845181101561149e57600085828151811061125a57fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b8152600401611295919061205f565b60806040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e59190611fa3565b935093509350506112f4611afc565b8315158061130157508215155b1561138f5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df61133a896024850161205f565b60206040518083038186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190611f8b565b905290505b831561147857604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b906113cf90899060040161205f565b604080518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190611d74565b915050611429611afc565b506040805160208101909152818152611440611afc565b506040805160208101909152848152611457611afc565b61146283838761164d565b91505061147081898e6116a6565b9c5050505050505b821561148d576114898184896116a6565b9750505b505060019093019250611243915050565b50806114b257600019945050505050610ae5565b60008282670de0b6b3a764000002816114c757fe5b0490506114dc670de0b6b3a7640000826116f3565b979650505050505050565b6000546001600160a01b031633146114fe57600080fd5b6001546001600160a01b031615610fd557600080fd5b64746a52880081565b6000546001600160a01b0316331461153457600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fb3573d6000803e3d6000fd5b6006546001600160a01b031681565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156115cb5760405133904780156108fc02916000818181858888f193505050501580156115c9573d6000803e3d6000fd5b505b565b60008115806115e8575050808202828282816115e557fe5b04145b6115f157600080fd5b92915050565b610fb38363a9059cbb60e01b848460405160240161161692919061215c565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611723565b6000611657611afc565b6000611661611afc565b61166b87876117b2565b9092509050600082600381111561167e57fe5b1461168d57909250905061169e565b61169781866117b2565b9350935050505b935093915050565b60008060006116b3611afc565b6116bd878761189c565b909250905060008260038111156116d057fe5b146116e1575091506000905061169e565b6116976116ed82611904565b86611913565b60008161171461170b85670de0b6b3a76400006115cd565b60028504611939565b8161171b57fe5b049392505050565b6060611778826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119499092919063ffffffff16565b805190915015610fb357808060200190518101906117969190611d58565b610fb35760405162461bcd60e51b81526004016107b8906121f5565b60006117bc611afc565b6000806117d186600001518660000151611960565b909250905060008260038111156117e457fe5b14611803575060408051602081019091526000815290925090506106f6565b6000806118186706f05b59d3b2000084611913565b9092509050600082600381111561182b57fe5b1461184e57816040518060200160405280600081525095509550505050506106f6565b60008061186383670de0b6b3a764000061199f565b9092509050600082600381111561187657fe5b1461187d57fe5b604080516020810190915290815260009a909950975050505050505050565b60006118a6611afc565b6000806118b7866000015186611960565b909250905060008260038111156118ca57fe5b146118e9575060408051602081019091526000815290925090506106f6565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b60008083830184811061192b576000925090506106f6565b6002600092509250506106f6565b808201828110156115f157600080fd5b606061195884846000856119ca565b949350505050565b60008083611973575060009050806106f6565b8383028385828161198057fe5b0414611994576002600092509250506106f6565b6000925090506106f6565b600080826119b357506001905060006106f6565b60008385816119be57fe5b04915091509250929050565b60606119d585611a8e565b6119f15760405162461bcd60e51b81526004016107b890612198565b60006060866001600160a01b03168587604051611a0e9190612043565b60006040518083038185875af1925050503d8060008114611a4b576040519150601f19603f3d011682016040523d82523d6000602084013e611a50565b606091505b50915091508115611a645791506119589050565b805115611a745780518082602001fd5b8360405162461bcd60e51b81526004016107b89190612185565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611958575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b80356115f181612362565b80516115f181612362565b600082601f830112611b35578081fd5b611b3f604061230f565b9050808284604085011115611b5357600080fd5b60005b6002811015611b7f578135611b6a81612362565b83526020928301929190910190600101611b56565b50505092915050565b600082601f830112611b98578081fd5b813567ffffffffffffffff811115611bae578182fd5b611bc1601f8201601f191660200161230f565b9150808252836020828501011115611bd857600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215611c02578081fd5b8135611c0d81612362565b9392505050565b600060208284031215611c25578081fd5b8151611c0d81612362565b60008060408385031215611c42578081fd5b8235611c4d81612362565b946020939093013593505050565b600080600060608486031215611c6f578081fd5b8335611c7a81612362565b92506020840135611c8a81612362565b929592945050506040919091013590565b60008060408385031215611c42578182fd5b60006020808385031215611cbf578182fd5b825167ffffffffffffffff80821115611cd6578384fd5b818501915085601f830112611ce9578384fd5b815181811115611cf7578485fd5b8381029150611d0784830161230f565b8181528481019084860184860187018a1015611d21578788fd5b8795505b83861015611d4b57611d378a82611b1a565b835260019590950194918601918601611d25565b5098975050505050505050565b600060208284031215611d69578081fd5b8151611c0d81612377565b60008060408385031215611d86578182fd5b82518015158114611d95578283fd5b6020939093015192949293505050565b60008060408385031215611db7578182fd5b823560028110611dc5578283fd5b91506020830135611dd581612362565b809150509250929050565b600060c08284031215611df1578081fd5b611dfb60c061230f565b8251611e0681612362565b81526020830151611e1681612385565b60208201526040830151611e2981612385565b60408201526060830151611e3c81612385565b60608201526080830151611e4f81612385565b608082015260a0830151611e6281612377565b60a08201529392505050565b600080600060808486031215611e82578081fd5b833567ffffffffffffffff80821115611e99578283fd5b8186019150610120808389031215611eaf578384fd5b611eb88161230f565b9050611ec48884611b0f565b8152611ed38860208501611b0f565b6020820152604083013560408201526060830135606082015260808301356080820152611f038860a08501611b0f565b60a0820152611f158860c08501611b0f565b60c082015260e083013582811115611f2b578485fd5b611f3789828601611b88565b60e0830152506101009283013592810192909252509250611f5b8560208601611b25565b9150611f6a8560608601611b0f565b90509250925092565b600060208284031215611f84578081fd5b5035919050565b600060208284031215611f9c578081fd5b5051919050565b60008060008060808587031215611fb8578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b60028110156120115781516001600160a01b0316845260209384019390910190600101611fe9565b50505050565b6000815180845261202f816020860160208601612336565b601f01601f19169290920160200192915050565b60008251612055818460208701612336565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0384811682528316602082015260606040820181905260009061209f90830184612017565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b03929092168252602082015260400190565b9115158252602082015260400190565b600060208252611c0d6020830184612017565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600c908201526b139bdd08185d5d1a08189bdd60a21b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060808252612253608083018651611fd8565b602085015161226560a0840182611fd8565b50604085015160c0830152606085015160e08301526080850151610100818185015260a0870151915061012061229d81860184611fd8565b60c088015192506122b2610140860184611fd8565b60e0880151925080610160860152506122cf6101a0850183612017565b9087015161018085015291506122ea90506020830185611fe5565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561232e57600080fd5b604052919050565b60005b83811015612351578181015183820152602001612339565b838111156120115750506000910152565b6001600160a01b03811681146115c957600080fd5b80151581146115c957600080fd5b6001600160801b03811681146115c957600080fdfea264697066735822122031c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a64736f6c634300060c0033000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b

Deployed Bytecode

0x6080604052600436106101e35760003560e01c80638da5cb5b11610102578063c91d59fe11610095578063e9bb84c211610064578063e9bb84c2146104d2578063ec23ef27146104f2578063f24ccbfe14610507578063f851a4401461051c576101e3565b8063c91d59fe146102cd578063d98bb5b11461047d578063deca5f881461049d578063e3bbb4f1146104bd576101e3565b8063a56f9718116100d1578063a56f971814610408578063a7304bf71461041d578063a8c903231461043d578063bfc361721461045d576101e3565b80638da5cb5b146103a057806398a3f265146103b55780639da6136b146103c85780639db5dbe4146103e8576101e3565b806336fc603f1161017a5780634d3f199e116101495780634d3f199e14610341578063526d646114610361578063696806c01461037657806379521f021461038b576101e3565b806336fc603f146102e257806339df1878146102f75780633a1283221461030c57806341c0e1b51461032c576101e3565b80631e48907b116101b65780631e48907b1461027857806329ad0f36146102985780632a56f602146102ad57806332ac5cd2146102cd576101e3565b806306d5e37e146101e8578063109d0af81461021f578063139198941461024157806318bf60e114610256575b600080fd5b3480156101f457600080fd5b50610208610203366004611da5565b610531565b604051610216929190612175565b60405180910390f35b34801561022b57600080fd5b506102346106fd565b604051610216919061205f565b61025461024f366004611e6e565b610715565b005b34801561026257600080fd5b5061026b610a6a565b60405161021691906122f8565b34801561028457600080fd5b50610254610293366004611bf1565b610a70565b3480156102a457600080fd5b50610234610aa9565b3480156102b957600080fd5b5061026b6102c8366004611f73565b610ab8565b3480156102d957600080fd5b50610234610aea565b3480156102ee57600080fd5b5061026b610afd565b34801561030357600080fd5b50610234610b03565b34801561031857600080fd5b50610254610327366004611c9b565b610b1b565b34801561033857600080fd5b50610254610bb4565b34801561034d57600080fd5b5061025461035c366004611f73565b610bd9565b34801561036d57600080fd5b50610234610c04565b34801561038257600080fd5b5061026b610c1c565b34801561039757600080fd5b50610234610c22565b3480156103ac57600080fd5b50610234610c31565b6102546103c3366004611e6e565b610c40565b3480156103d457600080fd5b506102546103e3366004611bf1565b610f4f565b3480156103f457600080fd5b50610254610403366004611c5b565b610f88565b34801561041457600080fd5b5061026b610fb8565b34801561042957600080fd5b50610254610438366004611bf1565b610fbe565b34801561044957600080fd5b50610254610458366004611f73565b610ff7565b34801561046957600080fd5b50610208610478366004611da5565b611022565b34801561048957600080fd5b5061026b610498366004611bf1565b611121565b3480156104a957600080fd5b506102546104b8366004611bf1565b6114e7565b3480156104c957600080fd5b5061026b611514565b3480156104de57600080fd5b506102546104ed366004611c30565b61151d565b3480156104fe57600080fd5b5061023461156a565b34801561051357600080fd5b50610234611579565b34801561052857600080fd5b50610234611588565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c9061056690879060040161205f565b60206040518083038186803b15801561057e57600080fd5b505afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b69190611d58565b90506105c0611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105f090889060040161205f565b60c06040518083038186803b15801561060857600080fd5b505afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190611de0565b905081610655576000809350935050506106f6565b600086600181111561066357fe5b14801561067257508060a00151155b15610685576000809350935050506106f6565b600061069086611121565b905060018760018111156106a057fe5b14156106c2576020909101516001600160801b03168110935091506106f69050565b60008760018111156106d057fe5b14156106f2576040909101516001600160801b03168111935091506106f69050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061074c90339060040161205f565b60206040518083038186803b15801561076457600080fd5b505afa158015610778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079c9190611d58565b6107c15760405162461bcd60e51b81526004016107b8906121cf565b60405180910390fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a08231906107f890309060040161205f565b60206040518083038186803b15801561081057600080fd5b505afa158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190611f8b565b106108d35760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f39061087f9084906004016122f8565b602060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d19190611d58565b505b6000806108e1600085610531565b91509150816108ef57600080fd5b60006108fc600554610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610933908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b031916815261097e93929190600401612073565b6000604051808303818588803b15801561099757600080fd5b505af11580156109ab573d6000803e3d6000fd5b50505050506000806109be600088611022565b91509150816109cc57600080fd5b6109d4611597565b6009546040516001600160a01b039091169063d061ce509030908a90610a009089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d93929190612102565b600060405180830381600087803b158015610a4757600080fd5b505af1158015610a5b573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b03163314610a8757600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610ad35764746a528800610ad5565b3a5b9050610ae181846115cd565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610b3257600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610b9657600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610b90573d6000803e3d6000fd5b50610bb0565b600054610bb0906001600160a01b038481169116836115f7565b5050565b6000546001600160a01b03163314610bcb57600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610bf057600080fd5b622dc6c08110610bff57600080fd5b600455565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60035481565b6007546001600160a01b031681565b6000546001600160a01b031681565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da90610c7790339060040161205f565b60206040518083038186803b158015610c8f57600080fd5b505afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc79190611d58565b610ce35760405162461bcd60e51b81526004016107b8906121cf565b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610d1a90309060040161205f565b60206040518083038186803b158015610d3257600080fd5b505afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a9190611f8b565b10610df55760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610da19084906004016122f8565b602060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df39190611d58565b505b600080610e03600185610531565b9150915081610e1157600080fd5b6000610e1e600454610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610e55908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610ea093929190600401612073565b6000604051808303818588803b158015610eb957600080fd5b505af1158015610ecd573d6000803e3d6000fd5b5050505050600080610ee0600188611022565b9150915081610eee57600080fd5b610ef6611597565b6009546040516001600160a01b039091169063d061ce509030908a90610f229089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d939291906120a8565b6001546001600160a01b03163314610f6657600080fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f9f57600080fd5b610fb36001600160a01b03841683836115f7565b505050565b60025481565b6001546001600160a01b03163314610fd557600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461100e57600080fd5b622dc6c0811061101d57600080fd5b600555565b60008061102d611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d49061105d90879060040161205f565b60c06040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190611de0565b905060006110ba85611121565b905060018660018111156110ca57fe5b14156110ea576040909101516001600160801b03168110925090506106f6565b60008660018111156110f857fe5b1415611118576020909101516001600160801b03168111925090506106f6565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061115e90869060040161205f565b60006040518083038186803b15801561117657600080fd5b505afa15801561118a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b29190810190611cad565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190611c14565b905060008060005b845181101561149e57600085828151811061125a57fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b8152600401611295919061205f565b60806040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e59190611fa3565b935093509350506112f4611afc565b8315158061130157508215155b1561138f5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df61133a896024850161205f565b60206040518083038186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190611f8b565b905290505b831561147857604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b906113cf90899060040161205f565b604080518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190611d74565b915050611429611afc565b506040805160208101909152818152611440611afc565b506040805160208101909152848152611457611afc565b61146283838761164d565b91505061147081898e6116a6565b9c5050505050505b821561148d576114898184896116a6565b9750505b505060019093019250611243915050565b50806114b257600019945050505050610ae5565b60008282670de0b6b3a764000002816114c757fe5b0490506114dc670de0b6b3a7640000826116f3565b979650505050505050565b6000546001600160a01b031633146114fe57600080fd5b6001546001600160a01b031615610fd557600080fd5b64746a52880081565b6000546001600160a01b0316331461153457600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fb3573d6000803e3d6000fd5b6006546001600160a01b031681565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156115cb5760405133904780156108fc02916000818181858888f193505050501580156115c9573d6000803e3d6000fd5b505b565b60008115806115e8575050808202828282816115e557fe5b04145b6115f157600080fd5b92915050565b610fb38363a9059cbb60e01b848460405160240161161692919061215c565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611723565b6000611657611afc565b6000611661611afc565b61166b87876117b2565b9092509050600082600381111561167e57fe5b1461168d57909250905061169e565b61169781866117b2565b9350935050505b935093915050565b60008060006116b3611afc565b6116bd878761189c565b909250905060008260038111156116d057fe5b146116e1575091506000905061169e565b6116976116ed82611904565b86611913565b60008161171461170b85670de0b6b3a76400006115cd565b60028504611939565b8161171b57fe5b049392505050565b6060611778826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119499092919063ffffffff16565b805190915015610fb357808060200190518101906117969190611d58565b610fb35760405162461bcd60e51b81526004016107b8906121f5565b60006117bc611afc565b6000806117d186600001518660000151611960565b909250905060008260038111156117e457fe5b14611803575060408051602081019091526000815290925090506106f6565b6000806118186706f05b59d3b2000084611913565b9092509050600082600381111561182b57fe5b1461184e57816040518060200160405280600081525095509550505050506106f6565b60008061186383670de0b6b3a764000061199f565b9092509050600082600381111561187657fe5b1461187d57fe5b604080516020810190915290815260009a909950975050505050505050565b60006118a6611afc565b6000806118b7866000015186611960565b909250905060008260038111156118ca57fe5b146118e9575060408051602081019091526000815290925090506106f6565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b60008083830184811061192b576000925090506106f6565b6002600092509250506106f6565b808201828110156115f157600080fd5b606061195884846000856119ca565b949350505050565b60008083611973575060009050806106f6565b8383028385828161198057fe5b0414611994576002600092509250506106f6565b6000925090506106f6565b600080826119b357506001905060006106f6565b60008385816119be57fe5b04915091509250929050565b60606119d585611a8e565b6119f15760405162461bcd60e51b81526004016107b890612198565b60006060866001600160a01b03168587604051611a0e9190612043565b60006040518083038185875af1925050503d8060008114611a4b576040519150601f19603f3d011682016040523d82523d6000602084013e611a50565b606091505b50915091508115611a645791506119589050565b805115611a745780518082602001fd5b8360405162461bcd60e51b81526004016107b89190612185565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611958575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b80356115f181612362565b80516115f181612362565b600082601f830112611b35578081fd5b611b3f604061230f565b9050808284604085011115611b5357600080fd5b60005b6002811015611b7f578135611b6a81612362565b83526020928301929190910190600101611b56565b50505092915050565b600082601f830112611b98578081fd5b813567ffffffffffffffff811115611bae578182fd5b611bc1601f8201601f191660200161230f565b9150808252836020828501011115611bd857600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215611c02578081fd5b8135611c0d81612362565b9392505050565b600060208284031215611c25578081fd5b8151611c0d81612362565b60008060408385031215611c42578081fd5b8235611c4d81612362565b946020939093013593505050565b600080600060608486031215611c6f578081fd5b8335611c7a81612362565b92506020840135611c8a81612362565b929592945050506040919091013590565b60008060408385031215611c42578182fd5b60006020808385031215611cbf578182fd5b825167ffffffffffffffff80821115611cd6578384fd5b818501915085601f830112611ce9578384fd5b815181811115611cf7578485fd5b8381029150611d0784830161230f565b8181528481019084860184860187018a1015611d21578788fd5b8795505b83861015611d4b57611d378a82611b1a565b835260019590950194918601918601611d25565b5098975050505050505050565b600060208284031215611d69578081fd5b8151611c0d81612377565b60008060408385031215611d86578182fd5b82518015158114611d95578283fd5b6020939093015192949293505050565b60008060408385031215611db7578182fd5b823560028110611dc5578283fd5b91506020830135611dd581612362565b809150509250929050565b600060c08284031215611df1578081fd5b611dfb60c061230f565b8251611e0681612362565b81526020830151611e1681612385565b60208201526040830151611e2981612385565b60408201526060830151611e3c81612385565b60608201526080830151611e4f81612385565b608082015260a0830151611e6281612377565b60a08201529392505050565b600080600060808486031215611e82578081fd5b833567ffffffffffffffff80821115611e99578283fd5b8186019150610120808389031215611eaf578384fd5b611eb88161230f565b9050611ec48884611b0f565b8152611ed38860208501611b0f565b6020820152604083013560408201526060830135606082015260808301356080820152611f038860a08501611b0f565b60a0820152611f158860c08501611b0f565b60c082015260e083013582811115611f2b578485fd5b611f3789828601611b88565b60e0830152506101009283013592810192909252509250611f5b8560208601611b25565b9150611f6a8560608601611b0f565b90509250925092565b600060208284031215611f84578081fd5b5035919050565b600060208284031215611f9c578081fd5b5051919050565b60008060008060808587031215611fb8578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b60028110156120115781516001600160a01b0316845260209384019390910190600101611fe9565b50505050565b6000815180845261202f816020860160208601612336565b601f01601f19169290920160200192915050565b60008251612055818460208701612336565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0384811682528316602082015260606040820181905260009061209f90830184612017565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b03929092168252602082015260400190565b9115158252602082015260400190565b600060208252611c0d6020830184612017565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600c908201526b139bdd08185d5d1a08189bdd60a21b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060808252612253608083018651611fd8565b602085015161226560a0840182611fd8565b50604085015160c0830152606085015160e08301526080850151610100818185015260a0870151915061012061229d81860184611fd8565b60c088015192506122b2610140860184611fd8565b60e0880151925080610160860152506122cf6101a0850183612017565b9087015161018085015291506122ea90506020830185611fe5565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561232e57600080fd5b604052919050565b60005b83811015612351578181015183820152602001612339565b838111156120115750506000910152565b6001600160a01b03811681146115c957600080fd5b80151581146115c957600080fd5b6001600160801b03811681146115c957600080fdfea264697066735822122031c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a64736f6c634300060c0033

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

000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b

-----Decoded View---------------
Arg [0] : _compoundMonitorProxy (address): 0xB1cF8DE8e791E4Ed1Bd86c03E2fc1f14389Cb10a
Arg [1] : _subscriptions (address): 0x52015EFFD577E08f498a0CCc11905925D58D6207
Arg [2] : _compoundFlashLoanTaker (address): 0x533c8844bA1922b88d892aCA090df0cC0c292F1b

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a
Arg [1] : 00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207
Arg [2] : 000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b


Deployed Bytecode Sourcemap

60500:8974:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65890:749;;;;;;;;;;-1:-1:-1;65890:749:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;42601:108;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;64089:1137::-;;;;;;:::i;:::-;;:::i;:::-;;60850:36;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;8640:122::-;;;;;;;;;;-1:-1:-1;8640:122:0;;;;;:::i;:::-;;:::i;61300:44::-;;;;;;;;;;;;;:::i;67634:203::-;;;;;;;;;;-1:-1:-1;67634:203:0;;;;;:::i;:::-;;:::i;60895:96::-;;;;;;;;;;;;;:::i;60807:36::-;;;;;;;;;;;;;:::i;60998:85::-;;;;;;;;;;;;;:::i;8935:285::-;;;;;;;;;;-1:-1:-1;8935:285:0;;;;;:::i;:::-;;:::i;8808:80::-;;;;;;;;;;;;;:::i;68648:144::-;;;;;;;;;;-1:-1:-1;68648:144:0;;;;;:::i;:::-;;:::i;61090:89::-;;;;;;;;;;;;;:::i;60696:32::-;;;;;;;;;;;;;:::i;61243:50::-;;;;;;;;;;;;;:::i;7598:20::-;;;;;;;;;;;;;:::i;62556:1134::-;;;;;;:::i;:::-;;:::i;68004:182::-;;;;;;;;;;-1:-1:-1;68004:182:0;;;;;:::i;:::-;;:::i;69027:156::-;;;;;;;;;;-1:-1:-1;69027:156:0;;;;;:::i;:::-;;:::i;60657:32::-;;;;;;;;;;;;;:::i;8419:122::-;;;;;;;;;;-1:-1:-1;8419:122:0;;;;;:::i;:::-;;:::i;68345:144::-;;;;;;;;;;-1:-1:-1;68345:144:0;;;;;:::i;:::-;;:::i;66936:490::-;;;;;;;;;;-1:-1:-1;66936:490:0;;;;;:::i;:::-;;:::i;42828:1709::-;;;;;;;;;;-1:-1:-1;42828:1709:0;;;;;:::i;:::-;;:::i;8136:161::-;;;;;;;;;;-1:-1:-1;8136:161:0;;;;;:::i;:::-;;:::i;60737:49::-;;;;;;;;;;;;;:::i;69358:113::-;;;;;;;;;;-1:-1:-1;69358:113:0;;;;;:::i;:::-;;:::i;61188:48::-;;;;;;;;;;;;;:::i;61353:65::-;;;;;;;;;;;;;:::i;7625:20::-;;;;;;;;;;;;;:::i;65890:749::-;65999:21;;:41;;-1:-1:-1;;;65999:41:0;;65958:4;;;;;;-1:-1:-1;;;;;65999:21:0;;:34;;:41;;66034:5;;65999:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65981:59;;66051:50;;:::i;:::-;66104:21;;:38;;-1:-1:-1;;;66104:38:0;;-1:-1:-1;;;;;66104:21:0;;;;:31;;:38;;66136:5;;66104:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66051:91;;66199:10;66194:34;;66219:5;66226:1;66211:17;;;;;;;;66194:34;66301:12;66290:7;:23;;;;;;;;;:47;;;;;66318:6;:19;;;66317:20;66290:47;66286:70;;;66347:5;66354:1;66339:17;;;;;;;;66286:70;66369:14;66386:21;66401:5;66386:14;:21::i;:::-;66369:38;-1:-1:-1;66435:12:0;66424:7;:23;;;;;;;;;66420:212;;;66484:15;;;;;-1:-1:-1;;;;;66472:27:0;;;;-1:-1:-1;66472:9:0;-1:-1:-1;66464:47:0;;-1:-1:-1;66464:47:0;66420:212;66544:12;66533:7;:23;;;;;;;;;66529:103;;;66593:15;;;;;-1:-1:-1;;;;;66581:27:0;;;;-1:-1:-1;66581:9:0;-1:-1:-1;66573:47:0;;-1:-1:-1;66573:47:0;66529:103;65890:749;;;;;;;;;:::o;42601:108::-;42666:42;42601:108;:::o;64089:1137::-;61470:53;;-1:-1:-1;;;61470:53:0;;61137:42;;61470:41;;:53;;61512:10;;61470:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;61462:78;;;;-1:-1:-1;;;61462:78:0;;;;;;;:::i;:::-;;;;;;;;;64302:15:::1;::::0;10454:33:::1;::::0;-1:-1:-1;;;10454:33:0;;64302:15;;10356:42:::1;::::0;10454:18:::1;::::0;:33:::1;::::0;10481:4:::1;::::0;10454:33:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;10450:99;;10515:22;::::0;-1:-1:-1;;;10515:22:0;;10356:42:::1;::::0;10515:13:::1;::::0;:22:::1;::::0;10529:7;;10515:22:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10450:99;64333:14:::2;64349:16:::0;64369:28:::2;64377:12;64391:5;64369:7;:28::i;:::-;64332:65;;;;64416:9;64408:18;;;::::0;::::2;;64470:15;64488:27;64500:14;;64488:11;:27::i;:::-;64528:20;::::0;64613:29:::2;::::0;64657:246:::2;::::0;64470:45;;-1:-1:-1;;;;;;64528:20:0;;::::2;::::0;:32:::2;::::0;64568:9:::2;::::0;64593:5;;64613:29;::::2;::::0;64657:246:::2;::::0;64825:7;;64851:11;;64470:45;;64657:246:::2;;;:::i;:::-;;::::0;;-1:-1:-1;;64657:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;64657:246:0::2;-1:-1:-1::0;;;64657:246:0::2;::::0;;64528:386;::::2;::::0;;;-1:-1:-1;;;;;;64528:386:0;;;::::2;::::0;;;64657:246;64528:386:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;64930:16;64948:15:::0;64967:35:::2;64982:12;64996:5;64967:14;:35::i;:::-;64929:73;;;;65021:11;65013:20;;;::::0;::::2;;65099:11;:9;:11::i;:::-;65123:6;::::0;65182:35:::2;::::0;-1:-1:-1;;;;;65123:6:0;;::::2;::::0;:10:::2;::::0;65142:4:::2;::::0;65149:5;;65182:35:::2;::::0;65193:11;;65206:10;;65182:35:::2;;;:::i;:::-;;;;;;;;;;;;;65123:95;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;10561:1;;;;;61551::::1;64089:1137:::0;;;:::o;60850:36::-;;;;:::o;8640:122::-;8721:5;;-1:-1:-1;;;;;8721:5:0;8707:10;:19;8699:28;;;;;;8740:5;:14;;-1:-1:-1;;;;;;8740:14:0;-1:-1:-1;;;;;8740:14:0;;;;;;;;;;8640:122::o;61300:44::-;;;-1:-1:-1;;;;;61300:44:0;;:::o;67634:203::-;67693:4;67710:13;60774:12;67726:11;:28;;:58;;60774:12;67726:58;;;67757:11;67726:58;67710:74;;67804:25;67808:8;67818:10;67804:3;:25::i;:::-;67797:32;;;67634:203;;;;:::o;60895:96::-;60949:42;60895:96;:::o;60807:36::-;;;;:::o;60998:85::-;61041:42;60998:85;:::o;8935:285::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;9035:42:::1;-1:-1:-1::0;;;;;9025:52:0;::::1;;9021:192;;;9102:5;::::0;;9094:32:::1;::::0;-1:-1:-1;;;;;9102:5:0;;::::1;::::0;9094:32;::::1;;;::::0;9118:7;;9094:32;9102:5;9094:32;9118:7;9102:5;9094:32;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;9021:192;;;9186:5;::::0;9159:42:::1;::::0;-1:-1:-1;;;;;9159:26:0;;::::1;::::0;9186:5:::1;9193:7:::0;9159:26:::1;:42::i;:::-;8935:285:::0;;:::o;8808:80::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;8873:5:::1;::::0;-1:-1:-1;;;;;8873:5:0::1;8852:28;68648:144:::0;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;68738:7:::1;68727:8;:18;68719:27;;;::::0;::::1;;68759:14;:25:::0;68648:144::o;61090:89::-;61137:42;61090:89;:::o;60696:32::-;;;;:::o;61243:50::-;;;-1:-1:-1;;;;;61243:50:0;;:::o;7598:20::-;;;-1:-1:-1;;;;;7598:20:0;;:::o;62556:1134::-;61470:53;;-1:-1:-1;;;61470:53:0;;61137:42;;61470:41;;:53;;61512:10;;61470:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;61462:78;;;;-1:-1:-1;;;61462:78:0;;;;;;;:::i;:::-;62769:15:::1;::::0;10454:33:::1;::::0;-1:-1:-1;;;10454:33:0;;62769:15;;10356:42:::1;::::0;10454:18:::1;::::0;:33:::1;::::0;10481:4:::1;::::0;10454:33:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;10450:99;;10515:22;::::0;-1:-1:-1;;;10515:22:0;;10356:42:::1;::::0;10515:13:::1;::::0;:22:::1;::::0;10529:7;;10515:22:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10450:99;62800:14:::2;62816:16:::0;62836:28:::2;62844:12;62858:5;62836:7;:28::i;:::-;62799:65;;;;62883:9;62875:18;;;::::0;::::2;;62937:15;62955:27;62967:14;;62955:11;:27::i;:::-;62995:20;::::0;63080:29:::2;::::0;63124:246:::2;::::0;62937:45;;-1:-1:-1;;;;;;62995:20:0;;::::2;::::0;:32:::2;::::0;63035:9:::2;::::0;63060:5;;63080:29;::::2;::::0;63124:246:::2;::::0;63292:7;;63318:11;;62937:45;;63124:246:::2;;;:::i;:::-;;::::0;;-1:-1:-1;;63124:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;63124:246:0::2;-1:-1:-1::0;;;63124:246:0::2;::::0;;62995:386;::::2;::::0;;;-1:-1:-1;;;;;;62995:386:0;;;::::2;::::0;;;63124:246;62995:386:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;63395:16;63413:15:::0;63432:35:::2;63447:12;63461:5;63432:14;:35::i;:::-;63394:73;;;;63486:11;63478:20;;;::::0;::::2;;63563:11;:9;:11::i;:::-;63587:6;::::0;63646:35:::2;::::0;-1:-1:-1;;;;;63587:6:0;;::::2;::::0;:10:::2;::::0;63606:4:::2;::::0;63613:5;;63646:35:::2;::::0;63657:11;;63670:10;;63646:35:::2;;;:::i;:::-;;;;;;;;;;;;;63587:95;;;;;;;;;;;;;;;;;:::i;68004:182::-:0;7782:5;;-1:-1:-1;;;;;7782:5:0;7791:10;7782:19;7774:28;;;;;;68113:29:::1;:65:::0;;-1:-1:-1;;;;;;68113:65:0::1;-1:-1:-1::0;;;;;68113:65:0;;;::::1;::::0;;;::::1;::::0;;68004:182::o;69027:156::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;69128:47:::1;-1:-1:-1::0;;;;;69128:33:0;::::1;69162:3:::0;69167:7;69128:33:::1;:47::i;:::-;69027:156:::0;;;:::o;60657:32::-;;;;:::o;8419:122::-;8500:5;;-1:-1:-1;;;;;8500:5:0;8486:10;:19;8478:28;;;;;;8519:5;:14;;-1:-1:-1;;;;;;8519:14:0;-1:-1:-1;;;;;8519:14:0;;;;;;;;;;8419:122::o;68345:144::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;68435:7:::1;68424:8;:18;68416:27;;;::::0;::::1;;68456:14;:25:::0;68345:144::o;66936:490::-;67011:4;67017;67034:50;;:::i;:::-;67105:21;;:38;;-1:-1:-1;;;67105:38:0;;-1:-1:-1;;;;;67105:21:0;;;;:31;;:38;;67137:5;;67105:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67097:46;;67156:14;67173:21;67188:5;67173:14;:21::i;:::-;67156:38;-1:-1:-1;67222:12:0;67211:7;:23;;;;;;;;;67207:212;;;67271:15;;;;;-1:-1:-1;;;;;67259:27:0;;;;-1:-1:-1;67259:9:0;-1:-1:-1;67251:47:0;;67207:212;67331:12;67320:7;:23;;;;;;;;;67316:103;;;67380:15;;;;;-1:-1:-1;;;;;67368:27:0;;;;-1:-1:-1;67368:9:0;-1:-1:-1;67360:47:0;;67316:103;66936:490;;;;;;;:::o;42828:1709::-;42976:23;;-1:-1:-1;;;42976:23:0;;42888:4;;42950:23;;42666:42;;42976:16;;:23;;42993:5;;42976:23;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;42976:23:0;;;;;;;;;;;;:::i;:::-;42950:49;;43010:18;42666:42;-1:-1:-1;;;;;43031:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43010:34;;43059:18;43092:14;43128:6;43123:1242;43144:6;:13;43140:1;:17;43123:1242;;;43179:13;43195:6;43202:1;43195:9;;;;;;;;;;;;;;43179:25;;43224:18;43244;43264:25;43350:5;-1:-1:-1;;;;;43334:41:0;;43376:5;43334:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43221:161;;;;;;;43399:22;;:::i;:::-;43442:18;;;;:40;;-1:-1:-1;43464:18:0;;;43442:40;43438:173;;;43517:78;;;;;;;;;;-1:-1:-1;;;43532:61:0;;;43517:78;-1:-1:-1;;;;;43532:54:0;;;:61;43587:5;43532:61;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43517:78;;43503:92;-1:-1:-1;43438:173:0;43672:18;;43668:497;;43743:28;;-1:-1:-1;;;43743:28:0;;43716:23;;42666:42;;43743:12;;:28;;43764:5;;43743:28;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43713:58;;;43792:27;;:::i;:::-;-1:-1:-1;43822:35:0;;;;;;;;;;;;43876:23;;:::i;:::-;-1:-1:-1;43902:37:0;;;;;;;;;;;;43963:22;;:::i;:::-;43989:52;43997:16;44015:12;44029:11;43989:7;:52::i;:::-;43960:81;;;44082:67;44107:11;44120:13;44135;44082:24;:67::i;:::-;44062:87;-1:-1:-1;;;;;;43668:497:0;44220:18;;44216:138;;44275:63;44300:11;44313:13;44328:9;44275:24;:63::i;:::-;44259:79;-1:-1:-1;;44216:138:0;-1:-1:-1;;43159:3:0;;;;;-1:-1:-1;43123:1242:0;;-1:-1:-1;;43123:1242:0;;-1:-1:-1;44381:14:0;44377:35;;-1:-1:-1;;44397:15:0;;;;;;;;44377:35;44425:20;44471:13;44449:9;44461:6;44449:18;44448:36;;;;;;44425:59;;44502:27;44507:4;44513:15;44502:4;:27::i;:::-;44495:34;42828:1709;-1:-1:-1;;;;;;;42828:1709:0:o;8136:161::-;8217:5;;-1:-1:-1;;;;;8217:5:0;8203:10;:19;8195:28;;;;;;8242:5;;-1:-1:-1;;;;;8242:5:0;:19;8234:28;;;;;60737:49;60774:12;60737:49;:::o;69358:113::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;69442:21:::1;::::0;-1:-1:-1;;;;;69442:12:0;::::1;::::0;:21;::::1;;;::::0;69455:7;;69442:21:::1;::::0;;;69455:7;69442:12;:21;::::1;;;;;;;;;;;;;::::0;::::1;;;;61188:48:::0;;;-1:-1:-1;;;;;61188:48:0;;:::o;61353:65::-;;;-1:-1:-1;;;;;61353:65:0;;:::o;7625:20::-;;;-1:-1:-1;;;;;7625:20:0;;:::o;65307:184::-;65388:21;:25;65384:100;;65430:42;;:10;;65450:21;65430:42;;;;;;;;;65450:21;65430:10;:42;;;;;;;;;;;;;;;;;;;;;65384:100;65307:184::o;22452:127::-;22510:9;22540:6;;;:30;;-1:-1:-1;;22555:5:0;;;22569:1;22564;22555:5;22564:1;22550:15;;;;;:20;22540:30;22532:39;;;;;;22452:127;;;;:::o;5643:176::-;5725:86;5745:5;5775:23;;;5800:2;5804:5;5752:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;5752:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;5752:58:0;-1:-1:-1;;;;;;5752:58:0;;;;;;;;;;5725:19;:86::i;36840:284::-;36922:9;36933:10;;:::i;:::-;36957:13;36972;;:::i;:::-;36989:12;36996:1;36999;36989:6;:12::i;:::-;36956:45;;-1:-1:-1;36956:45:0;-1:-1:-1;37023:18:0;37016:3;:25;;;;;;;;;37012:74;;37066:3;;-1:-1:-1;37071:2:0;-1:-1:-1;37058:16:0;;37012:74;37103:13;37110:2;37114:1;37103:6;:13::i;:::-;37096:20;;;;;;36840:284;;;;;;;:::o;33312:328::-;33409:9;33420:4;33438:13;33453:18;;:::i;:::-;33475:20;33485:1;33488:6;33475:9;:20::i;:::-;33437:58;;-1:-1:-1;33437:58:0;-1:-1:-1;33517:18:0;33510:3;:25;;;;;;;;;33506:73;;-1:-1:-1;33560:3:0;-1:-1:-1;33565:1:0;;-1:-1:-1;33552:15:0;;33506:73;33598:34;33606:17;33615:7;33606:8;:17::i;:::-;33625:6;33598:7;:34::i;23493:120::-;23552:9;23604:1;23578:23;23582:11;23586:1;23182:6;23582:3;:11::i;:::-;23599:1;23595;:5;23578:3;:23::i;:::-;:27;;;;;;;23493:120;-1:-1:-1;;;23493:120:0:o;7112:419::-;7194:23;7220:69;7248:4;7220:69;;;;;;;;;;;;;;;;;7228:5;-1:-1:-1;;;;;7220:27:0;;;:69;;;;;:::i;:::-;7304:17;;7194:95;;-1:-1:-1;7304:21:0;7300:224;;7446:10;7435:30;;;;;;;;;;;;:::i;:::-;7427:85;;;;-1:-1:-1;;;7427:85:0;;;;;;;:::i;35336:1136::-;35403:9;35414:10;;:::i;:::-;35440:14;35456:24;35484:31;35492:1;:10;;;35504:1;:10;;;35484:7;:31::i;:::-;35439:76;;-1:-1:-1;35439:76:0;-1:-1:-1;35538:18:0;35530:4;:26;;;;;;;;;35526:92;;-1:-1:-1;35587:18:0;;;;;;;;;-1:-1:-1;35587:18:0;;35581:4;;-1:-1:-1;35587:18:0;-1:-1:-1;35573:33:0;;35526:92;35935:14;;35992:42;30779:10;36014:19;35992:7;:42::i;:::-;35934:100;;-1:-1:-1;35934:100:0;-1:-1:-1;36057:18:0;36049:4;:26;;;;;;;;;36045:92;;36100:4;36106:18;;;;;;;;36121:1;36106:18;;;36092:33;;;;;;;;;;36045:92;36150:14;36166:12;36182:51;36190:32;30700:4;36182:7;:51::i;:::-;36149:84;;-1:-1:-1;36149:84:0;-1:-1:-1;36379:18:0;36371:4;:26;;;;;;;;;36364:34;;;;36439:24;;;;;;;;;;;;-1:-1:-1;;36439:24:0;;-1:-1:-1;35336:1136:0;-1:-1:-1;;;;;;;;35336:1136:0:o;32388:353::-;32457:9;32468:10;;:::i;:::-;32492:14;32508:19;32531:27;32539:1;:10;;;32551:6;32531:7;:27::i;:::-;32491:67;;-1:-1:-1;32491:67:0;-1:-1:-1;32581:18:0;32573:4;:26;;;;;;;;;32569:92;;-1:-1:-1;32630:18:0;;;;;;;;;-1:-1:-1;32630:18:0;;32624:4;;-1:-1:-1;32630:18:0;-1:-1:-1;32616:33:0;;32569:92;32701:31;;;;;;;;;;;;-1:-1:-1;;32701:31:0;;-1:-1:-1;32388:353:0;-1:-1:-1;;;;32388:353:0:o;37667:213::-;37849:12;30700:4;37849:23;;;37667:213::o;30029:258::-;30085:9;;30122:5;;;30144:6;;;30140:140;;30175:18;;-1:-1:-1;30195:1:0;-1:-1:-1;30167:30:0;;30140:140;30238:26;30266:1;30230:38;;;;;;;22210:113;22303:5;;;22298:16;;;;22290:25;;;;;2034:196;2137:12;2169:53;2192:6;2200:4;2206:1;2209:12;2169:22;:53::i;:::-;2162:60;2034:196;-1:-1:-1;;;;2034:196:0:o;28920:343::-;28976:9;;29008:6;29004:69;;-1:-1:-1;29039:18:0;;-1:-1:-1;29039:18:0;29031:30;;29004:69;29094:5;;;29098:1;29094;:5;:1;29116:5;;;;;:10;29112:144;;29151:26;29179:1;29143:38;;;;;;;29112:144;29222:18;;-1:-1:-1;29242:1:0;-1:-1:-1;29214:30:0;;29358:215;29414:9;;29446:6;29442:77;;-1:-1:-1;29477:26:0;;-1:-1:-1;29505:1:0;29469:38;;29442:77;29539:18;29563:1;29559;:5;;;;;;29531:34;;;;29358:215;;;;;:::o;2796:979::-;2926:12;2959:18;2970:6;2959:10;:18::i;:::-;2951:60;;;;-1:-1:-1;;;2951:60:0;;;;;;;:::i;:::-;3085:12;3099:23;3126:6;-1:-1:-1;;;;;3126:11:0;3146:8;3157:4;3126:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3084:78;;;;3177:7;3173:595;;;3208:10;-1:-1:-1;3201:17:0;;-1:-1:-1;3201:17:0;3173:595;3322:17;;:21;3318:439;;3585:10;3579:17;3646:15;3633:10;3629:2;3625:19;3618:44;3533:148;3728:12;3721:20;;-1:-1:-1;;;3721:20:0;;;;;;;;:::i;821:619::-;881:4;1349:20;;1192:66;1389:23;;;;;;:42;;-1:-1:-1;;1416:15:0;;;1381:51;-1:-1:-1;;821:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;:::i;142:134::-;220:13;;238:33;220:13;238:33;:::i;455:616::-;;570:3;563:4;555:6;551:17;547:27;537:2;;-1:-1;;578:12;537:2;631:78;27191:17;631:78;:::i;:::-;622:87;;715:16;774:17;832:3;27191:17;807:3;803:27;800:36;797:2;;;849:1;;839:12;797:2;874:1;859:206;612:4;881:1;878:13;859:206;;;85:6;72:20;97:33;124:5;97:33;:::i;:::-;952:50;;27203:4;1016:14;;;;1044;;;;;906:1;899:9;859:206;;;863:14;;;530:541;;;;:::o;1963:440::-;;2064:3;2057:4;2049:6;2045:17;2041:27;2031:2;;-1:-1;;2072:12;2031:2;2119:6;2106:20;27684:18;27676:6;27673:30;27670:2;;;-1:-1;;27706:12;27670:2;2141:64;27779:9;27760:17;;-1:-1;;27756:33;27847:4;27837:15;2141:64;:::i;:::-;2132:73;;2225:6;2218:5;2211:21;2329:3;27847:4;2320:6;2253;2311:16;;2308:25;2305:2;;;2346:1;;2336:12;2305:2;31974:6;27847:4;2253:6;2249:17;27847:4;2287:5;2283:16;31951:30;32030:1;32012:16;;;27847:4;32012:16;32005:27;2287:5;2024:379;-1:-1;;2024:379::o;5891:241::-;;5995:2;5983:9;5974:7;5970:23;5966:32;5963:2;;;-1:-1;;6001:12;5963:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6053:63;5957:175;-1:-1;;;5957:175::o;6139:263::-;;6254:2;6242:9;6233:7;6229:23;6225:32;6222:2;;;-1:-1;;6260:12;6222:2;226:6;220:13;238:33;265:5;238:33;:::i;6409:382::-;;;6538:2;6526:9;6517:7;6513:23;6509:32;6506:2;;;-1:-1;;6544:12;6506:2;371:6;358:20;383:41;418:5;383:41;:::i;:::-;6596:71;6704:2;6743:22;;;;5680:20;;-1:-1;;;6500:291::o;6798:491::-;;;;6936:2;6924:9;6915:7;6911:23;6907:32;6904:2;;;-1:-1;;6942:12;6904:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6994:63;-1:-1;7094:2;7133:22;;72:20;97:33;72:20;97:33;:::i;:::-;6898:391;;7102:63;;-1:-1;;;7202:2;7241:22;;;;5680:20;;6898:391::o;7296:366::-;;;7417:2;7405:9;7396:7;7392:23;7388:32;7385:2;;;-1:-1;;7423:12;7669:392;;7809:2;;7797:9;7788:7;7784:23;7780:32;7777:2;;;-1:-1;;7815:12;7777:2;7866:17;7860:24;7904:18;;7896:6;7893:30;7890:2;;;-1:-1;;7926:12;7890:2;8028:6;8017:9;8013:22;;;1225:3;1218:4;1210:6;1206:17;1202:27;1192:2;;-1:-1;;1233:12;1192:2;1273:6;1267:13;7904:18;27381:6;27378:30;27375:2;;;-1:-1;;27411:12;27375:2;7809;27448:6;27444:17;;;1295:80;7809:2;27444:17;27509:15;1295:80;:::i;:::-;1403:21;;;1460:14;;;;1435:17;;;1540:27;;;;;1537:36;-1:-1;1534:2;;;-1:-1;;1576:12;1534:2;-1:-1;1602:10;;1596:217;1621:6;1618:1;1615:13;1596:217;;;1701:48;1745:3;1733:10;1701:48;:::i;:::-;1689:61;;1643:1;1636:9;;;;;1764:14;;;;1792;;1596:217;;;-1:-1;7946:99;7771:290;-1:-1;;;;;;;;7771:290::o;8068:257::-;;8180:2;8168:9;8159:7;8155:23;8151:32;8148:2;;;-1:-1;;8186:12;8148:2;1908:6;1902:13;1920:30;1944:5;1920:30;:::i;8332:393::-;;;8461:2;8449:9;8440:7;8436:23;8432:32;8429:2;;;-1:-1;;8467:12;8429:2;1908:6;1902:13;32773:5;29534:13;29527:21;32751:5;32748:32;32738:2;;-1:-1;;32784:12;32738:2;8627;8677:22;;;;5828:13;8519:71;;5828:13;;-1:-1;;;8423:302::o;8732:388::-;;;8864:2;8852:9;8843:7;8839:23;8835:32;8832:2;;;-1:-1;;8870:12;8832:2;2502:6;2489:20;32890:1;32883:5;32880:12;32870:2;;-1:-1;;32896:12;32870:2;8922:74;-1:-1;9033:2;9072:22;;72:20;97:33;72:20;97:33;:::i;:::-;9041:63;;;;8826:294;;;;;:::o;9127:328::-;;9274:3;9262:9;9253:7;9249:23;9245:33;9242:2;;;-1:-1;;9281:12;9242:2;2788:20;9274:3;2788:20;:::i;:::-;226:6;220:13;238:33;265:5;238:33;:::i;:::-;2865:86;;3016:2;3081:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3016:2;3031:16;;3024:86;3175:2;3240:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3175:2;3190:16;;3183:86;3343:2;3408:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3343:2;3358:16;;3351:86;3511:3;3577:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3511:3;3527:16;;3520:86;3675:3;3738:22;;1902:13;1920:30;1902:13;1920:30;:::i;:::-;3675:3;3691:16;;3684:83;3695:5;9236:219;-1:-1;;;9236:219::o;9462:684::-;;;;9653:3;9641:9;9632:7;9628:23;9624:33;9621:2;;;-1:-1;;9660:12;9621:2;9718:17;9705:31;9756:18;;9748:6;9745:30;9742:2;;;-1:-1;;9778:12;9742:2;9874:6;9863:9;9859:22;;;3958:6;;3946:9;3941:3;3937:19;3933:32;3930:2;;;-1:-1;;3968:12;3930:2;3996:22;3958:6;3996:22;:::i;:::-;3987:31;;4103:49;4148:3;4124:22;4103:49;:::i;:::-;4085:16;4078:75;4251:49;4296:3;4218:2;4276:9;4272:22;4251:49;:::i;:::-;4218:2;4237:5;4233:16;4226:75;4367:2;4425:9;4421:22;5680:20;4367:2;4386:5;4382:16;4375:75;4517:2;4575:9;4571:22;5680:20;4517:2;4536:5;4532:16;4525:75;9653:3;4724:9;4720:22;5680:20;9653:3;4685:5;4681:16;4674:75;4847:49;4892:3;4813;4872:9;4868:22;4847:49;:::i;:::-;4813:3;4833:5;4829:16;4822:75;5000:49;5045:3;4966;5025:9;5021:22;5000:49;:::i;:::-;4966:3;4986:5;4982:16;4975:75;5143:3;5132:9;5128:19;5115:33;9756:18;5160:6;5157:30;5154:2;;;-1:-1;;5190:12;5154:2;5235:58;5289:3;5280:6;5269:9;5265:22;5235:58;:::i;:::-;5143:3;5217:16;;5210:84;-1:-1;5358:3;5415:22;;;5680:20;5374:18;;;5367:77;;;;-1:-1;5221:5;-1:-1;9946:76;10014:7;4218:2;9990:22;;9946:76;:::i;:::-;9936:86;;10077:53;10122:7;4517:2;10102:9;10098:22;10077:53;:::i;:::-;10067:63;;9615:531;;;;;:::o;10153:241::-;;10257:2;10245:9;10236:7;10232:23;10228:32;10225:2;;;-1:-1;;10263:12;10225:2;-1:-1;5680:20;;10219:175;-1:-1;10219:175::o;10401:263::-;;10516:2;10504:9;10495:7;10491:23;10487:32;10484:2;;;-1:-1;;10522:12;10484:2;-1:-1;5828:13;;10478:186;-1:-1;10478:186::o;10671:672::-;;;;;10837:3;10825:9;10816:7;10812:23;10808:33;10805:2;;;-1:-1;;10844:12;10805:2;-1:-1;;5828:13;;11007:2;11057:22;;5828:13;11126:2;11176:22;;5828:13;11245:2;11295:22;;;5828:13;;;;;-1:-1;5828:13;;-1:-1;10799:544;-1:-1;10799:544::o;11681:103::-;-1:-1;;;;;29742:54;11742:37;;11736:48::o;11944:660::-;12307:21;12349:1;12334:258;28067:4;12356:1;12353:13;12334:258;;;12420:13;;-1:-1;;;;;29742:54;11742:37;;11513:4;11504:14;;;;28432;;;;27684:18;12374:9;12334:258;;;12338:14;;12056:548;;:::o;12723:323::-;;12855:5;28175:12;28712:6;28707:3;28700:19;12938:52;12983:6;28749:4;28744:3;28740:14;28749:4;12964:5;12960:16;12938:52;:::i;:::-;27779:9;32391:14;-1:-1;;32387:28;13002:39;;;;28749:4;13002:39;;12803:243;-1:-1;;12803:243::o;18793:271::-;;13563:5;28175:12;13674:52;13719:6;13714:3;13707:4;13700:5;13696:16;13674:52;:::i;:::-;13738:16;;;;;18927:137;-1:-1;;18927:137::o;19071:222::-;-1:-1;;;;;29742:54;;;;11742:37;;19198:2;19183:18;;19169:124::o;19545:528::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;19910:2;19895:18;;11742:37;19746:2;19947;19932:18;;19925:48;;;19545:528;;19987:76;;19731:18;;20049:6;19987:76;:::i;:::-;19979:84;19717:356;-1:-1;;;;;19717:356::o;20080:834::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;20547:2;20532:18;;11742:37;20382:3;20584:2;20569:18;;20562:48;;;15284:2;20367:19;;;28700;-1:-1;;;29753:42;28740:14;;15300:45;15364:12;20788:2;20773:18;;20766:48;;;20080:834;;20828:76;;15364:12;;20890:6;20828:76;:::i;20921:834::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;21388:2;21373:18;;11742:37;21223:3;21425:2;21410:18;;21403:48;;;15615:2;21208:19;;;28700;-1:-1;;;29753:42;28740:14;;15631:45;15695:12;21629:2;21614:18;;21607:48;;;20921:834;;21669:76;;15695:12;;21731:6;21669:76;:::i;21762:333::-;-1:-1;;;;;29742:54;;;;11742:37;;22081:2;22066:18;;18624:37;21917:2;21902:18;;21888:207::o;22102:321::-;29534:13;;29527:21;12677:34;;22409:2;22394:18;;18624:37;22251:2;22236:18;;22222:201::o;23849:310::-;;23996:2;24017:17;24010:47;24071:78;23996:2;23985:9;23981:18;24135:6;24071:78;:::i;24166:416::-;24366:2;24380:47;;;15946:2;24351:18;;;28700:19;15982:31;28740:14;;;15962:52;16033:12;;;24337:245::o;24589:416::-;24789:2;24803:47;;;16284:2;24774:18;;;28700:19;-1:-1;;;28740:14;;;16300:35;16354:12;;;24760:245::o;25012:416::-;25212:2;25226:47;;;16605:2;25197:18;;;28700:19;16641:34;28740:14;;;16621:55;-1:-1;;;16696:12;;;16689:34;16742:12;;;25183:245::o;25435:705::-;;25724:3;25746:17;25739:47;17114:63;25724:3;25713:9;25709:19;17091:16;17085:23;17114:63;:::i;:::-;17260:4;17253:5;17249:16;17243:23;17272:63;17320:14;25713:9;17320:14;17306:12;17272:63;:::i;:::-;;17419:4;17412:5;17408:16;17402:23;17479:14;25713:9;17479:14;18624:37;17579:4;17572:5;17568:16;17562:23;17639:14;25713:9;17639:14;18624:37;25724:3;17730:5;17726:16;17720:23;17797:14;17720:23;17797:14;25713:9;17797:14;18624:37;17320:14;17887:5;17883:16;17877:23;17857:43;;17014:6;17906:63;17014:6;25713:9;17954:14;17940:12;17906:63;:::i;:::-;17479:14;18049:5;18045:16;18039:23;18019:43;;18068:63;18116:14;25713:9;18116:14;18102:12;18068:63;:::i;:::-;17639:14;18207:5;18203:16;18197:23;18177:43;;17014:6;18240:14;25713:9;18240:14;18233:38;;18286:71;17005:16;25713:9;17005:16;18338:12;18286:71;:::i;:::-;18434:18;;;18428:25;18507:16;;;18624:37;18278:79;-1:-1;25929:118;;-1:-1;17260:4;26028:18;;26019:6;25929:118;:::i;:::-;18654:5;17579:4;26115:9;26111:18;18624:37;25695:445;;;;;;:::o;26147:222::-;18624:37;;;26274:2;26259:18;;26245:124::o;26376:333::-;18624:37;;;26695:2;26680:18;;18624:37;26531:2;26516:18;;26502:207::o;26716:256::-;26778:2;26772:9;26804:17;;;26879:18;26864:34;;26900:22;;;26861:62;26858:2;;;26936:1;;26926:12;26858:2;26778;26945:22;26756:216;;-1:-1;26756:216::o;32047:268::-;32112:1;32119:101;32133:6;32130:1;32127:13;32119:101;;;32200:11;;;32194:18;32181:11;;;32174:39;32155:2;32148:10;32119:101;;;32235:6;32232:1;32229:13;32226:2;;;-1:-1;;32112:1;32282:16;;32275:27;32096:219::o;32428:117::-;-1:-1;;;;;29742:54;;32487:35;;32477:2;;32536:1;;32526:12;32692:111;32773:5;29534:13;29527:21;32751:5;32748:32;32738:2;;32794:1;;32784:12;32922:117;-1:-1;;;;;33009:5;29622:46;32984:5;32981:35;32971:2;;33030:1;;33020:12

Swarm Source

ipfs://31c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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