Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 73 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Stuck F... | 10839461 | 1615 days ago | IN | 0 ETH | 0.00485918 | ||||
Repay For | 10823729 | 1618 days ago | IN | 0.00553 ETH | 0.10298621 | ||||
Repay For | 10814534 | 1619 days ago | IN | 0.00756 ETH | 0.15098097 | ||||
Repay For | 10811449 | 1620 days ago | IN | 0 ETH | 0.15297889 | ||||
Boost For | 10810627 | 1620 days ago | IN | 0.00623 ETH | 0.1325242 | ||||
Boost For | 10806893 | 1620 days ago | IN | 0.021 ETH | 0.1789464 | ||||
Repay For | 10803374 | 1621 days ago | IN | 0.02842 ETH | 0.7203662 | ||||
Repay For | 10803239 | 1621 days ago | IN | 0.0441 ETH | 0.8222217 | ||||
Repay For | 10803238 | 1621 days ago | IN | 0.02205 ETH | 0.73249025 | ||||
Repay For | 10803238 | 1621 days ago | IN | 0.02205 ETH | 1.09477052 | ||||
Repay For | 10803238 | 1621 days ago | IN | 0.02205 ETH | 0.93572924 | ||||
Repay For | 10803238 | 1621 days ago | IN | 0.02205 ETH | 0.99572377 | ||||
Repay For | 10803232 | 1621 days ago | IN | 0.02205 ETH | 0.70878844 | ||||
Repay For | 10803097 | 1621 days ago | IN | 0.0441 ETH | 0.33675862 | ||||
Repay For | 10803047 | 1621 days ago | IN | 0.04466 ETH | 0.48180803 | ||||
Repay For | 10802998 | 1621 days ago | IN | 0.04466 ETH | 0.59306055 | ||||
Repay For | 10802859 | 1621 days ago | IN | 0.04102 ETH | 0.10040216 | ||||
Repay For | 10801614 | 1621 days ago | IN | 0.05964 ETH | 0.14785798 | ||||
Repay For | 10801546 | 1621 days ago | IN | 0.028 ETH | 0.4660504 | ||||
Repay For | 10801513 | 1621 days ago | IN | 0.0539 ETH | 0.75013326 | ||||
Repay For | 10801513 | 1621 days ago | IN | 0.0504 ETH | 0.72767154 | ||||
Repay For | 10801493 | 1621 days ago | IN | 0.02408 ETH | 0.94000061 | ||||
Repay For | 10801493 | 1621 days ago | IN | 0.02408 ETH | 0.79934063 | ||||
Repay For | 10801483 | 1621 days ago | IN | 0.0238 ETH | 0.79674356 | ||||
Repay For | 10801261 | 1621 days ago | IN | 0.04382 ETH | 0.75397292 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
10823729 | 1618 days ago | 0.00553 ETH | ||||
10814534 | 1619 days ago | 0.00756 ETH | ||||
10810627 | 1620 days ago | 0.00623 ETH | ||||
10806893 | 1620 days ago | 0.021 ETH | ||||
10803374 | 1621 days ago | 0.02842 ETH | ||||
10803239 | 1621 days ago | 0.0441 ETH | ||||
10803238 | 1621 days ago | 0.02205 ETH | ||||
10803238 | 1621 days ago | 0.02205 ETH | ||||
10803238 | 1621 days ago | 0.02205 ETH | ||||
10803238 | 1621 days ago | 0.02205 ETH | ||||
10803232 | 1621 days ago | 0.02205 ETH | ||||
10803097 | 1621 days ago | 0.0441 ETH | ||||
10803047 | 1621 days ago | 0.04466 ETH | ||||
10802998 | 1621 days ago | 0.04466 ETH | ||||
10801546 | 1621 days ago | 0.028 ETH | ||||
10801513 | 1621 days ago | 0.0539 ETH | ||||
10801513 | 1621 days ago | 0.0504 ETH | ||||
10801493 | 1621 days ago | 0.02408 ETH | ||||
10801493 | 1621 days ago | 0.02408 ETH | ||||
10801483 | 1621 days ago | 0.0238 ETH | ||||
10801261 | 1621 days ago | 0.04382 ETH | ||||
10801133 | 1621 days ago | 0.04284 ETH | ||||
10801113 | 1621 days ago | 0.04032 ETH | ||||
10795948 | 1622 days ago | 0.0434 ETH | ||||
10795621 | 1622 days ago | 0.0392 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
CompoundMonitor
Compiler Version
v0.6.10+commit.00c0fcaf
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-08-27 */ /** *Submitted for verification at Etherscan.io on 2020-08-18 */ 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); } 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); } 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, 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); _; } constructor() public { owner = msg.sender; } /// @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); } } } /// @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 { 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 claimComp(address holder) virtual public; 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 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 halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { 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; } } 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; function setAllowlistAddr(address _zrxAddr, bool _state) public onlyOwner { zrxAllowlist[_zrxAddr] = _state; } function isZrxAddr(address _zrxAddr) public view returns (bool) { return zrxAllowlist[_zrxAddr]; } } 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 = 0x019739e288973F92bDD3c1d87178E206E51fd911; 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); (success, swapedTokens, tokensLeft) = takeOrder(exData, address(this).balance, 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); (success, swapedTokens,) = takeOrder(exData, address(this).balance, 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).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); } 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; } 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; CompoundMonitorProxy public compoundMonitorProxy; CompoundSubscriptions public subscriptionsContract; address public compoundFlashLoanTakerAddress; DefisaverLogger public logger = DefisaverLogger(DEFISAVER_LOGGER); /// @dev Addresses that are able to call methods for repay and boost mapping(address => bool) public approvedCallers; modifier onlyApproved() { require(approvedCallers[msg.sender]); _; } /// @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 { approvedCallers[msg.sender] = true; approvedCallers[0x776B4a13093e30B05781F97F6A4565B6aa8BE330] = true; 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 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 Adds a new bot address which will be able to call repay/boost /// @param _caller Bot address function addCaller(address _caller) public onlyOwner { approvedCallers[_caller] = true; } /// @notice Removes a bot address so it can't call repay/boost /// @param _caller Bot address function removeCaller(address _caller) public onlyOwner { approvedCallers[_caller] = false; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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":"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":[{"internalType":"address","name":"_caller","type":"address"}],"name":"addCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedCallers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"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":[{"internalType":"address","name":"_caller","type":"address"}],"name":"removeCaller","outputs":[],"stateMutability":"nonpayable","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":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405260146002819055600355621e84806004819055600555600980546001600160a01b031916735c55b921f590a89c1ebe84df170e655a82b621261790553480156200004d57600080fd5b506040516200239d3803806200239d83398101604081905262000070916200011b565b60008054336001600160a01b0319918216811783558252600a60205260408220805460ff19908116600190811790925573776b4a13093e30b05781f97f6a4565b6aa8be3309093527f48759b72d37a678826f270ac477a0f7ab04900700868789bbb8817abe75bc7598054909316179091556006805482166001600160a01b039586161790556007805482169385169390931790925560088054909216921691909117905562000187565b60008060006060848603121562000130578283fd5b83516200013d816200016e565b602085015190935062000150816200016e565b604085015190925062000163816200016e565b809150509250925092565b6001600160a01b03811681146200018457600080fd5b50565b61220680620001976000396000f3fe6080604052600436106101d85760003560e01c806379521f0211610102578063c91d59fe11610095578063ec23ef2711610064578063ec23ef27146104bf578063eef21cd2146104d4578063f24ccbfe146104f4578063f851a44014610509576101d8565b8063c91d59fe146102c2578063d98bb5b11461046a578063deca5f881461048a578063e3bbb4f1146104aa576101d8565b8063a71975af116100d1578063a71975af146103dd578063a7304bf71461040a578063a8c903231461042a578063bfc361721461044a576101d8565b806379521f021461038b5780638da5cb5b146103a057806398a3f265146103b5578063a56f9718146103c8576101d8565b806332ac5cd21161017a57806341c0e1b51161014957806341c0e1b5146103215780634d3f199e14610336578063696806c014610356578063747293fb1461036b576101d8565b806332ac5cd2146102c257806336fc603f146102d757806339df1878146102ec5780633a12832214610301576101d8565b806318bf60e1116101b657806318bf60e11461024b5780631e48907b1461026d57806329ad0f361461028d5780632a56f602146102a2576101d8565b806306d5e37e146101dd578063109d0af8146102145780631391989414610236575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004611c1e565b61051e565b60405161020b929190611ff4565b60405180910390f35b34801561022057600080fd5b506102296106ec565b60405161020b9190611ed3565b610249610244366004611ce2565b610704565b005b34801561025757600080fd5b506102606109c9565b60405161020b9190612151565b34801561027957600080fd5b50610249610288366004611abd565b6109cf565b34801561029957600080fd5b50610229610a08565b3480156102ae57600080fd5b506102606102bd366004611de7565b610a17565b3480156102ce57600080fd5b50610229610a49565b3480156102e357600080fd5b50610260610a5c565b3480156102f857600080fd5b50610229610a62565b34801561030d57600080fd5b5061024961031c366004611afc565b610a7a565b34801561032d57600080fd5b50610249610b19565b34801561034257600080fd5b50610249610351366004611de7565b610b3e565b34801561036257600080fd5b50610260610b69565b34801561037757600080fd5b50610249610386366004611abd565b610b6f565b34801561039757600080fd5b50610229610baa565b3480156103ac57600080fd5b50610229610bb9565b6102496103c3366004611ce2565b610bc8565b3480156103d457600080fd5b50610260610e50565b3480156103e957600080fd5b506103fd6103f8366004611abd565b610e56565b60405161020b9190611fe9565b34801561041657600080fd5b50610249610425366004611abd565b610e6b565b34801561043657600080fd5b50610249610445366004611de7565b610ea4565b34801561045657600080fd5b506101fd610465366004611c1e565b610ecf565b34801561047657600080fd5b50610260610485366004611abd565b610fce565b34801561049657600080fd5b506102496104a5366004611abd565b611393565b3480156104b657600080fd5b506102606113c0565b3480156104cb57600080fd5b506102296113c9565b3480156104e057600080fd5b506102496104ef366004611abd565b6113d8565b34801561050057600080fd5b50610229611410565b34801561051557600080fd5b5061022961141f565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c90610553908790600401611ed3565b60206040518083038186803b15801561056b57600080fd5b505afa15801561057f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a39190611bd2565b90506105ad61196c565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105dd908890600401611ed3565b60c06040518083038186803b1580156105f557600080fd5b505afa158015610609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062d9190611c59565b9050816106435750600092508291506106e59050565b600086600181111561065157fe5b14801561066057508060a00151155b156106745750600092508291506106e59050565b600061067f86610fce565b9050600187600181111561068f57fe5b14156106b1576020909101516001600160801b03168110935091506106e59050565b60008760018111156106bf57fe5b14156106e1576040909101516001600160801b03168111935091506106e59050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b336000908152600a602052604090205460ff1661072057600080fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610757903090600401611ed3565b60206040518083038186803b15801561076f57600080fd5b505afa158015610783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a79190611dff565b106108325760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f3906107de908490600401612151565b602060405180830381600087803b1580156107f857600080fd5b505af115801561080c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108309190611bd2565b505b60008061084060008561051e565b915091508161084e57600080fd5b600061085b600554610a17565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610892908d908d908990602401612098565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b03191681526108dd93929190600401611ee7565b6000604051808303818588803b1580156108f657600080fd5b505af115801561090a573d6000803e3d6000fd5b505050505060008061091d600088610ecf565b915091508161092b57600080fd5b61093361142e565b6009546040516001600160a01b039091169063d061ce509030908a9061095f908990879060200161215a565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161098c93929190611f76565b600060405180830381600087803b1580156109a657600080fd5b505af11580156109ba573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b031633146109e657600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610a325764746a528800610a34565b3a5b9050610a408184611464565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610a9157600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610af557600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610aef573d6000803e3d6000fd5b50610b15565b600054610b15906001600160a01b0384811691168363ffffffff61148e16565b5050565b6000546001600160a01b03163314610b3057600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610b5557600080fd5b622dc6c08110610b6457600080fd5b600455565b60035481565b6000546001600160a01b03163314610b8657600080fd5b6001600160a01b03166000908152600a60205260409020805460ff19166001179055565b6007546001600160a01b031681565b6000546001600160a01b031681565b336000908152600a602052604090205460ff16610be457600080fd5b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610c1b903090600401611ed3565b60206040518083038186803b158015610c3357600080fd5b505afa158015610c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6b9190611dff565b10610cf65760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610ca2908490600401612151565b602060405180830381600087803b158015610cbc57600080fd5b505af1158015610cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf49190611bd2565b505b600080610d0460018561051e565b9150915081610d1257600080fd5b6000610d1f600454610a17565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610d56908d908d908990602401612098565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610da193929190600401611ee7565b6000604051808303818588803b158015610dba57600080fd5b505af1158015610dce573d6000803e3d6000fd5b5050505050600080610de1600188610ecf565b9150915081610def57600080fd5b610df761142e565b6009546040516001600160a01b039091169063d061ce509030908a90610e23908990879060200161215a565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161098c93929190611f1c565b60025481565b600a6020526000908152604090205460ff1681565b6001546001600160a01b03163314610e8257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610ebb57600080fd5b622dc6c08110610eca57600080fd5b600555565b600080610eda61196c565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d490610f0a908790600401611ed3565b60c06040518083038186803b158015610f2257600080fd5b505afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190611c59565b90506000610f6785610fce565b90506001866001811115610f7757fe5b1415610f97576040909101516001600160801b03168110925090506106e5565b6000866001811115610fa557fe5b1415610fc5576020909101516001600160801b03168111925090506106e5565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061100b908690600401611ed3565b60006040518083038186803b15801561102357600080fd5b505afa158015611037573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261105f9190810190611b27565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156110b057600080fd5b505afa1580156110c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e89190611ae0565b9050600080805b845181101561134a57600085828151811061110657fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b81526004016111419190611ed3565b60806040518083038186803b15801561115957600080fd5b505afa15801561116d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111919190611e17565b935093509350506111a06119a1565b831515806111ad57508215155b1561123b5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df6111e68960248501611ed3565b60206040518083038186803b1580156111fe57600080fd5b505afa158015611212573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112369190611dff565b905290505b831561132457604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9061127b908990600401611ed3565b604080518083038186803b15801561129257600080fd5b505afa1580156112a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ca9190611bf2565b9150506112d56119a1565b5060408051602081019091528181526112ec6119a1565b5060408051602081019091528481526113036119a1565b61130e8383876114e9565b91505061131c81898e611542565b9c5050505050505b821561133957611335818489611542565b9750505b5050600190930192506110ef915050565b508061135e57600019945050505050610a44565b60008282670de0b6b3a7640000028161137357fe5b049050611388670de0b6b3a76400008261158f565b979650505050505050565b6000546001600160a01b031633146113aa57600080fd5b6001546001600160a01b031615610e8257600080fd5b64746a52880081565b6006546001600160a01b031681565b6000546001600160a01b031633146113ef57600080fd5b6001600160a01b03166000908152600a60205260409020805460ff19169055565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156114625760405133904780156108fc02916000818181858888f19350505050158015611460573d6000803e3d6000fd5b505b565b600081158061147f5750508082028282828161147c57fe5b04145b61148857600080fd5b92915050565b6114e48363a9059cbb60e01b84846040516024016114ad929190611fd0565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526115bf565b505050565b60006114f36119a1565b60006114fd6119a1565b6115078787611657565b9092509050600082600381111561151a57fe5b1461152957909250905061153a565b6115338186611657565b9350935050505b935093915050565b600080600061154f6119a1565b6115598787611741565b9092509050600082600381111561156c57fe5b1461157d575091506000905061153a565b611533611589826117a9565b866117b8565b6000816115b06115a785670de0b6b3a7640000611464565b600285046117de565b816115b757fe5b049392505050565b6060611614826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117ee9092919063ffffffff16565b8051909150156114e457808060200190518101906116329190611bd2565b6114e45760405162461bcd60e51b815260040161164e9061204e565b60405180910390fd5b60006116616119a1565b60008061167686600001518660000151611805565b9092509050600082600381111561168957fe5b146116a8575060408051602081019091526000815290925090506106e5565b6000806116bd6706f05b59d3b20000846117b8565b909250905060008260038111156116d057fe5b146116f357816040518060200160405280600081525095509550505050506106e5565b60008061170883670de0b6b3a7640000611844565b9092509050600082600381111561171b57fe5b1461172257fe5b604080516020810190915290815260009a909950975050505050505050565b600061174b6119a1565b60008061175c866000015186611805565b9092509050600082600381111561176f57fe5b1461178e575060408051602081019091526000815290925090506106e5565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b6000808383018481106117d0576000925090506106e5565b5060029150600090506106e5565b8082018281101561148857600080fd5b60606117fd848460008561186f565b949350505050565b60008083611818575060009050806106e5565b8383028385828161182557fe5b0414611839575060029150600090506106e5565b6000925090506106e5565b6000808261185857506001905060006106e5565b600083858161186357fe5b04915091509250929050565b606061187a85611933565b6118965760405162461bcd60e51b815260040161164e90612017565b60006060866001600160a01b031685876040516118b39190611eb7565b60006040518083038185875af1925050503d80600081146118f0576040519150601f19603f3d011682016040523d82523d6000602084013e6118f5565b606091505b509150915081156119095791506117fd9050565b8051156119195780518082602001fd5b8360405162461bcd60e51b815260040161164e9190612004565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906117fd575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b8035611488816121bb565b8051611488816121bb565b600082601f8301126119da578081fd5b6119e46040612168565b90508082846040850111156119f857600080fd5b60005b6002811015611a24578135611a0f816121bb565b835260209283019291909101906001016119fb565b50505092915050565b8051801515811461148857600080fd5b600082601f830112611a4d578081fd5b813567ffffffffffffffff811115611a63578182fd5b611a76601f8201601f1916602001612168565b9150808252836020828501011115611a8d57600080fd5b8060208401602084013760009082016020015292915050565b80516001600160801b038116811461148857600080fd5b600060208284031215611ace578081fd5b8135611ad9816121bb565b9392505050565b600060208284031215611af1578081fd5b8151611ad9816121bb565b60008060408385031215611b0e578081fd5b8235611b19816121bb565b946020939093013593505050565b60006020808385031215611b39578182fd5b825167ffffffffffffffff80821115611b50578384fd5b81850186601f820112611b61578485fd5b8051925081831115611b71578485fd5b8383029150611b81848301612168565b8381528481019082860184840187018a1015611b9b578788fd5b8794505b85851015611bc557611bb18a826119bf565b835260019490940193918601918601611b9f565b5098975050505050505050565b600060208284031215611be3578081fd5b81518015158114611ad9578182fd5b60008060408385031215611c04578182fd5b611c0e8484611a2d565b9150602083015190509250929050565b60008060408385031215611c30578182fd5b823560028110611c3e578283fd5b91506020830135611c4e816121bb565b809150509250929050565b600060c08284031215611c6a578081fd5b611c7460c0612168565b8251611c7f816121bb565b8152611c8e8460208501611aa6565b6020820152611ca08460408501611aa6565b6040820152611cb28460608501611aa6565b6060820152611cc48460808501611aa6565b6080820152611cd68460a08501611a2d565b60a08201529392505050565b600080600060808486031215611cf6578081fd5b833567ffffffffffffffff80821115611d0d578283fd5b610120918601808803831315611d21578384fd5b611d2a83612168565b611d3489836119b4565b8152611d4389602084016119b4565b6020820152604082013560408201526060820135606082015260808201356080820152611d738960a084016119b4565b60a0820152611d858960c084016119b4565b60c082015260e0820135935082841115611d9d578485fd5b611da989858401611a3d565b60e08201526101009350838201358482015280965050505050611dcf85602086016119ca565b9150611dde85606086016119b4565b90509250925092565b600060208284031215611df8578081fd5b5035919050565b600060208284031215611e10578081fd5b5051919050565b60008060008060808587031215611e2c578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b6002811015611e855781516001600160a01b0316845260209384019390910190600101611e5d565b50505050565b60008151808452611ea381602086016020860161218f565b601f01601f19169290920160200192915050565b60008251611ec981846020870161218f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03848116825283166020820152606060408201819052600090611f1390830184611e8b565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c060608201819052600090611f1390830184611e8b565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c060608201819052600090611f1390830184611e8b565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b9115158252602082015260400190565b600060208252611ad96020830184611e8b565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6000608082526120ac608083018651611e4c565b60208501516120be60a0840182611e4c565b50604085015160c0830152606085015160e08301526080850151610100818185015260a087015191506101206120f681860184611e4c565b60c0880151925061210b610140860184611e4c565b60e0880151925080610160860152506121286101a0850183611e8b565b90870151610180850152915061214390506020830185611e59565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561218757600080fd5b604052919050565b60005b838110156121aa578181015183820152602001612192565b83811115611e855750506000910152565b6001600160a01b038116811461146057600080fdfea2646970667358221220ee38c0ddb1aa646452ad377130f15c76115575c8cbbf7a1dc02030d52cf71f4164736f6c634300060a0033000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000decdc15131ae4f829df6624c34a7c55e03d095e5
Deployed Bytecode
0x6080604052600436106101d85760003560e01c806379521f0211610102578063c91d59fe11610095578063ec23ef2711610064578063ec23ef27146104bf578063eef21cd2146104d4578063f24ccbfe146104f4578063f851a44014610509576101d8565b8063c91d59fe146102c2578063d98bb5b11461046a578063deca5f881461048a578063e3bbb4f1146104aa576101d8565b8063a71975af116100d1578063a71975af146103dd578063a7304bf71461040a578063a8c903231461042a578063bfc361721461044a576101d8565b806379521f021461038b5780638da5cb5b146103a057806398a3f265146103b5578063a56f9718146103c8576101d8565b806332ac5cd21161017a57806341c0e1b51161014957806341c0e1b5146103215780634d3f199e14610336578063696806c014610356578063747293fb1461036b576101d8565b806332ac5cd2146102c257806336fc603f146102d757806339df1878146102ec5780633a12832214610301576101d8565b806318bf60e1116101b657806318bf60e11461024b5780631e48907b1461026d57806329ad0f361461028d5780632a56f602146102a2576101d8565b806306d5e37e146101dd578063109d0af8146102145780631391989414610236575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004611c1e565b61051e565b60405161020b929190611ff4565b60405180910390f35b34801561022057600080fd5b506102296106ec565b60405161020b9190611ed3565b610249610244366004611ce2565b610704565b005b34801561025757600080fd5b506102606109c9565b60405161020b9190612151565b34801561027957600080fd5b50610249610288366004611abd565b6109cf565b34801561029957600080fd5b50610229610a08565b3480156102ae57600080fd5b506102606102bd366004611de7565b610a17565b3480156102ce57600080fd5b50610229610a49565b3480156102e357600080fd5b50610260610a5c565b3480156102f857600080fd5b50610229610a62565b34801561030d57600080fd5b5061024961031c366004611afc565b610a7a565b34801561032d57600080fd5b50610249610b19565b34801561034257600080fd5b50610249610351366004611de7565b610b3e565b34801561036257600080fd5b50610260610b69565b34801561037757600080fd5b50610249610386366004611abd565b610b6f565b34801561039757600080fd5b50610229610baa565b3480156103ac57600080fd5b50610229610bb9565b6102496103c3366004611ce2565b610bc8565b3480156103d457600080fd5b50610260610e50565b3480156103e957600080fd5b506103fd6103f8366004611abd565b610e56565b60405161020b9190611fe9565b34801561041657600080fd5b50610249610425366004611abd565b610e6b565b34801561043657600080fd5b50610249610445366004611de7565b610ea4565b34801561045657600080fd5b506101fd610465366004611c1e565b610ecf565b34801561047657600080fd5b50610260610485366004611abd565b610fce565b34801561049657600080fd5b506102496104a5366004611abd565b611393565b3480156104b657600080fd5b506102606113c0565b3480156104cb57600080fd5b506102296113c9565b3480156104e057600080fd5b506102496104ef366004611abd565b6113d8565b34801561050057600080fd5b50610229611410565b34801561051557600080fd5b5061022961141f565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c90610553908790600401611ed3565b60206040518083038186803b15801561056b57600080fd5b505afa15801561057f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a39190611bd2565b90506105ad61196c565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105dd908890600401611ed3565b60c06040518083038186803b1580156105f557600080fd5b505afa158015610609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062d9190611c59565b9050816106435750600092508291506106e59050565b600086600181111561065157fe5b14801561066057508060a00151155b156106745750600092508291506106e59050565b600061067f86610fce565b9050600187600181111561068f57fe5b14156106b1576020909101516001600160801b03168110935091506106e59050565b60008760018111156106bf57fe5b14156106e1576040909101516001600160801b03168111935091506106e59050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b336000908152600a602052604090205460ff1661072057600080fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610757903090600401611ed3565b60206040518083038186803b15801561076f57600080fd5b505afa158015610783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a79190611dff565b106108325760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f3906107de908490600401612151565b602060405180830381600087803b1580156107f857600080fd5b505af115801561080c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108309190611bd2565b505b60008061084060008561051e565b915091508161084e57600080fd5b600061085b600554610a17565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610892908d908d908990602401612098565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b03191681526108dd93929190600401611ee7565b6000604051808303818588803b1580156108f657600080fd5b505af115801561090a573d6000803e3d6000fd5b505050505060008061091d600088610ecf565b915091508161092b57600080fd5b61093361142e565b6009546040516001600160a01b039091169063d061ce509030908a9061095f908990879060200161215a565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161098c93929190611f76565b600060405180830381600087803b1580156109a657600080fd5b505af11580156109ba573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b031633146109e657600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610a325764746a528800610a34565b3a5b9050610a408184611464565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610a9157600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610af557600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610aef573d6000803e3d6000fd5b50610b15565b600054610b15906001600160a01b0384811691168363ffffffff61148e16565b5050565b6000546001600160a01b03163314610b3057600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610b5557600080fd5b622dc6c08110610b6457600080fd5b600455565b60035481565b6000546001600160a01b03163314610b8657600080fd5b6001600160a01b03166000908152600a60205260409020805460ff19166001179055565b6007546001600160a01b031681565b6000546001600160a01b031681565b336000908152600a602052604090205460ff16610be457600080fd5b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610c1b903090600401611ed3565b60206040518083038186803b158015610c3357600080fd5b505afa158015610c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6b9190611dff565b10610cf65760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610ca2908490600401612151565b602060405180830381600087803b158015610cbc57600080fd5b505af1158015610cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf49190611bd2565b505b600080610d0460018561051e565b9150915081610d1257600080fd5b6000610d1f600454610a17565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610d56908d908d908990602401612098565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610da193929190600401611ee7565b6000604051808303818588803b158015610dba57600080fd5b505af1158015610dce573d6000803e3d6000fd5b5050505050600080610de1600188610ecf565b9150915081610def57600080fd5b610df761142e565b6009546040516001600160a01b039091169063d061ce509030908a90610e23908990879060200161215a565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161098c93929190611f1c565b60025481565b600a6020526000908152604090205460ff1681565b6001546001600160a01b03163314610e8257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610ebb57600080fd5b622dc6c08110610eca57600080fd5b600555565b600080610eda61196c565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d490610f0a908790600401611ed3565b60c06040518083038186803b158015610f2257600080fd5b505afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190611c59565b90506000610f6785610fce565b90506001866001811115610f7757fe5b1415610f97576040909101516001600160801b03168110925090506106e5565b6000866001811115610fa557fe5b1415610fc5576020909101516001600160801b03168111925090506106e5565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061100b908690600401611ed3565b60006040518083038186803b15801561102357600080fd5b505afa158015611037573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261105f9190810190611b27565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156110b057600080fd5b505afa1580156110c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e89190611ae0565b9050600080805b845181101561134a57600085828151811061110657fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b81526004016111419190611ed3565b60806040518083038186803b15801561115957600080fd5b505afa15801561116d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111919190611e17565b935093509350506111a06119a1565b831515806111ad57508215155b1561123b5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df6111e68960248501611ed3565b60206040518083038186803b1580156111fe57600080fd5b505afa158015611212573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112369190611dff565b905290505b831561132457604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9061127b908990600401611ed3565b604080518083038186803b15801561129257600080fd5b505afa1580156112a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ca9190611bf2565b9150506112d56119a1565b5060408051602081019091528181526112ec6119a1565b5060408051602081019091528481526113036119a1565b61130e8383876114e9565b91505061131c81898e611542565b9c5050505050505b821561133957611335818489611542565b9750505b5050600190930192506110ef915050565b508061135e57600019945050505050610a44565b60008282670de0b6b3a7640000028161137357fe5b049050611388670de0b6b3a76400008261158f565b979650505050505050565b6000546001600160a01b031633146113aa57600080fd5b6001546001600160a01b031615610e8257600080fd5b64746a52880081565b6006546001600160a01b031681565b6000546001600160a01b031633146113ef57600080fd5b6001600160a01b03166000908152600a60205260409020805460ff19169055565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156114625760405133904780156108fc02916000818181858888f19350505050158015611460573d6000803e3d6000fd5b505b565b600081158061147f5750508082028282828161147c57fe5b04145b61148857600080fd5b92915050565b6114e48363a9059cbb60e01b84846040516024016114ad929190611fd0565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526115bf565b505050565b60006114f36119a1565b60006114fd6119a1565b6115078787611657565b9092509050600082600381111561151a57fe5b1461152957909250905061153a565b6115338186611657565b9350935050505b935093915050565b600080600061154f6119a1565b6115598787611741565b9092509050600082600381111561156c57fe5b1461157d575091506000905061153a565b611533611589826117a9565b866117b8565b6000816115b06115a785670de0b6b3a7640000611464565b600285046117de565b816115b757fe5b049392505050565b6060611614826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117ee9092919063ffffffff16565b8051909150156114e457808060200190518101906116329190611bd2565b6114e45760405162461bcd60e51b815260040161164e9061204e565b60405180910390fd5b60006116616119a1565b60008061167686600001518660000151611805565b9092509050600082600381111561168957fe5b146116a8575060408051602081019091526000815290925090506106e5565b6000806116bd6706f05b59d3b20000846117b8565b909250905060008260038111156116d057fe5b146116f357816040518060200160405280600081525095509550505050506106e5565b60008061170883670de0b6b3a7640000611844565b9092509050600082600381111561171b57fe5b1461172257fe5b604080516020810190915290815260009a909950975050505050505050565b600061174b6119a1565b60008061175c866000015186611805565b9092509050600082600381111561176f57fe5b1461178e575060408051602081019091526000815290925090506106e5565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b6000808383018481106117d0576000925090506106e5565b5060029150600090506106e5565b8082018281101561148857600080fd5b60606117fd848460008561186f565b949350505050565b60008083611818575060009050806106e5565b8383028385828161182557fe5b0414611839575060029150600090506106e5565b6000925090506106e5565b6000808261185857506001905060006106e5565b600083858161186357fe5b04915091509250929050565b606061187a85611933565b6118965760405162461bcd60e51b815260040161164e90612017565b60006060866001600160a01b031685876040516118b39190611eb7565b60006040518083038185875af1925050503d80600081146118f0576040519150601f19603f3d011682016040523d82523d6000602084013e6118f5565b606091505b509150915081156119095791506117fd9050565b8051156119195780518082602001fd5b8360405162461bcd60e51b815260040161164e9190612004565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906117fd575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b8035611488816121bb565b8051611488816121bb565b600082601f8301126119da578081fd5b6119e46040612168565b90508082846040850111156119f857600080fd5b60005b6002811015611a24578135611a0f816121bb565b835260209283019291909101906001016119fb565b50505092915050565b8051801515811461148857600080fd5b600082601f830112611a4d578081fd5b813567ffffffffffffffff811115611a63578182fd5b611a76601f8201601f1916602001612168565b9150808252836020828501011115611a8d57600080fd5b8060208401602084013760009082016020015292915050565b80516001600160801b038116811461148857600080fd5b600060208284031215611ace578081fd5b8135611ad9816121bb565b9392505050565b600060208284031215611af1578081fd5b8151611ad9816121bb565b60008060408385031215611b0e578081fd5b8235611b19816121bb565b946020939093013593505050565b60006020808385031215611b39578182fd5b825167ffffffffffffffff80821115611b50578384fd5b81850186601f820112611b61578485fd5b8051925081831115611b71578485fd5b8383029150611b81848301612168565b8381528481019082860184840187018a1015611b9b578788fd5b8794505b85851015611bc557611bb18a826119bf565b835260019490940193918601918601611b9f565b5098975050505050505050565b600060208284031215611be3578081fd5b81518015158114611ad9578182fd5b60008060408385031215611c04578182fd5b611c0e8484611a2d565b9150602083015190509250929050565b60008060408385031215611c30578182fd5b823560028110611c3e578283fd5b91506020830135611c4e816121bb565b809150509250929050565b600060c08284031215611c6a578081fd5b611c7460c0612168565b8251611c7f816121bb565b8152611c8e8460208501611aa6565b6020820152611ca08460408501611aa6565b6040820152611cb28460608501611aa6565b6060820152611cc48460808501611aa6565b6080820152611cd68460a08501611a2d565b60a08201529392505050565b600080600060808486031215611cf6578081fd5b833567ffffffffffffffff80821115611d0d578283fd5b610120918601808803831315611d21578384fd5b611d2a83612168565b611d3489836119b4565b8152611d4389602084016119b4565b6020820152604082013560408201526060820135606082015260808201356080820152611d738960a084016119b4565b60a0820152611d858960c084016119b4565b60c082015260e0820135935082841115611d9d578485fd5b611da989858401611a3d565b60e08201526101009350838201358482015280965050505050611dcf85602086016119ca565b9150611dde85606086016119b4565b90509250925092565b600060208284031215611df8578081fd5b5035919050565b600060208284031215611e10578081fd5b5051919050565b60008060008060808587031215611e2c578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b6002811015611e855781516001600160a01b0316845260209384019390910190600101611e5d565b50505050565b60008151808452611ea381602086016020860161218f565b601f01601f19169290920160200192915050565b60008251611ec981846020870161218f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03848116825283166020820152606060408201819052600090611f1390830184611e8b565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c060608201819052600090611f1390830184611e8b565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c060608201819052600090611f1390830184611e8b565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b9115158252602082015260400190565b600060208252611ad96020830184611e8b565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6000608082526120ac608083018651611e4c565b60208501516120be60a0840182611e4c565b50604085015160c0830152606085015160e08301526080850151610100818185015260a087015191506101206120f681860184611e4c565b60c0880151925061210b610140860184611e4c565b60e0880151925080610160860152506121286101a0850183611e8b565b90870151610180850152915061214390506020830185611e59565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561218757600080fd5b604052919050565b60005b838110156121aa578181015183820152602001612192565b83811115611e855750506000910152565b6001600160a01b038116811461146057600080fdfea2646970667358221220ee38c0ddb1aa646452ad377130f15c76115575c8cbbf7a1dc02030d52cf71f4164736f6c634300060a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000decdc15131ae4f829df6624c34a7c55e03d095e5
-----Decoded View---------------
Arg [0] : _compoundMonitorProxy (address): 0xB1cF8DE8e791E4Ed1Bd86c03E2fc1f14389Cb10a
Arg [1] : _subscriptions (address): 0x52015EFFD577E08f498a0CCc11905925D58D6207
Arg [2] : _compoundFlashLoanTaker (address): 0xdEcDC15131Ae4F829df6624c34a7c55e03D095e5
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a
Arg [1] : 00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207
Arg [2] : 000000000000000000000000decdc15131ae4f829df6624c34a7c55e03d095e5
Deployed Bytecode Sourcemap
52945:8589:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58451:749;;;;;;;;;;-1:-1:-1;58451:749:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;37116:108;;;;;;;;;;;;;:::i;:::-;;;;;;;;56650:1137;;;;;;;;;:::i;:::-;;53295:36;;;;;;;;;;;;;:::i;:::-;;;;;;;;9730:122;;;;;;;;;;-1:-1:-1;9730:122:0;;;;;;;;:::i;53649:44::-;;;;;;;;;;;;;:::i;60195:203::-;;;;;;;;;;-1:-1:-1;60195:203:0;;;;;;;;:::i;53340:96::-;;;;;;;;;;;;;:::i;53252:36::-;;;;;;;;;;;;;:::i;53443:85::-;;;;;;;;;;;;;:::i;10025:285::-;;;;;;;;;;-1:-1:-1;10025:285:0;;;;;;;;:::i;9898:80::-;;;;;;;;;;;;;:::i;60940:144::-;;;;;;;;;;-1:-1:-1;60940:144:0;;;;;;;;:::i;53141:32::-;;;;;;;;;;;;;:::i;61207:103::-;;;;;;;;;;-1:-1:-1;61207:103:0;;;;;;;;:::i;53592:50::-;;;;;;;;;;;;;:::i;8837:20::-;;;;;;;;;;;;;:::i;55117:1134::-;;;;;;;;;:::i;53102:32::-;;;;;;;;;;;;;:::i;53850:47::-;;;;;;;;;;-1:-1:-1;53850:47:0;;;;;;;;:::i;:::-;;;;;;;;9509:122;;;;;;;;;;-1:-1:-1;9509:122:0;;;;;;;;:::i;60637:144::-;;;;;;;;;;-1:-1:-1;60637:144:0;;;;;;;;:::i;59497:490::-;;;;;;;;;;-1:-1:-1;59497:490:0;;;;;;;;:::i;37343:1709::-;;;;;;;;;;-1:-1:-1;37343:1709:0;;;;;;;;:::i;9226:161::-;;;;;;;;;;-1:-1:-1;9226:161:0;;;;;;;;:::i;53182:49::-;;;;;;;;;;;;;:::i;53537:48::-;;;;;;;;;;;;;:::i;61422:107::-;;;;;;;;;;-1:-1:-1;61422:107:0;;;;;;;;:::i;53702:65::-;;;;;;;;;;;;;:::i;8864:20::-;;;;;;;;;;;;;:::i;58451:749::-;58560:21;;:41;;-1:-1:-1;;;58560:41:0;;58519:4;;;;;;-1:-1:-1;;;;;58560:21:0;;:34;;:41;;58595:5;;58560:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58542:59;;58612:50;;:::i;:::-;58665:21;;:38;;-1:-1:-1;;;58665:38:0;;-1:-1:-1;;;;;58665:21:0;;;;:31;;:38;;58697:5;;58665:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58612:91;;58760:10;58755:34;;-1:-1:-1;58780:5:0;;-1:-1:-1;58780:5:0;;-1:-1:-1;58772:17:0;;-1:-1:-1;58772:17:0;58755:34;58862:12;58851:7;:23;;;;;;;;;:47;;;;;58879:6;:19;;;58878:20;58851:47;58847:70;;;-1:-1:-1;58908:5:0;;-1:-1:-1;58908:5:0;;-1:-1:-1;58900:17:0;;-1:-1:-1;58900:17:0;58847:70;58930:14;58947:21;58962:5;58947:14;:21::i;:::-;58930:38;-1:-1:-1;58996:12:0;58985:7;:23;;;;;;;;;58981:212;;;59045:15;;;;;-1:-1:-1;;;;;59033:27:0;;;;-1:-1:-1;59033:9:0;-1:-1:-1;59025:47:0;;-1:-1:-1;59025:47:0;58981:212;59105:12;59094:7;:23;;;;;;;;;59090:103;;;59154:15;;;;;-1:-1:-1;;;;;59142:27:0;;;;-1:-1:-1;59142:9:0;-1:-1:-1;59134:47:0;;-1:-1:-1;59134:47:0;59090:103;58451:749;;;;;;;;;:::o;37116:108::-;37181:42;37116:108;:::o;56650:1137::-;53965:10;53949:27;;;;:15;:27;;;;;;;;53941:36;;;;;;56863:15:::1;::::0;1502:33:::1;::::0;-1:-1:-1;;;1502:33:0;;56863:15;;1404:42:::1;::::0;1502:18:::1;::::0;:33:::1;::::0;1529:4:::1;::::0;1502:33:::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;1498:99;;1563:22;::::0;-1:-1:-1;;;1563:22:0;;1404:42:::1;::::0;1563:13:::1;::::0;:22:::1;::::0;1577:7;;1563:22:::1;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1498:99;56894:14:::2;56910:16:::0;56930:28:::2;56938:12;56952:5;56930:7;:28::i;:::-;56893:65;;;;56977:9;56969:18;;;::::0;::::2;;57031:15;57049:27;57061:14;;57049:11;:27::i;:::-;57089:20;::::0;57174:29:::2;::::0;57218:246:::2;::::0;57031:45;;-1:-1:-1;;;;;;57089:20:0;;::::2;::::0;:32:::2;::::0;57129:9:::2;::::0;57154:5;;57174:29;::::2;::::0;57218:246:::2;::::0;57386:7;;57412:11;;57031:45;;57218:246:::2;;;;;;::::0;;-1:-1:-1;;57218:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;57218:246:0::2;-1:-1:-1::0;;;57218:246:0::2;::::0;;57089:386;::::2;::::0;;;-1:-1:-1;;;;;;57089:386:0;;;::::2;::::0;;;57218:246;57089:386:::2;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;57491:16;57509:15:::0;57528:35:::2;57543:12;57557:5;57528:14;:35::i;:::-;57490:73;;;;57582:11;57574:20;;;::::0;::::2;;57660:11;:9;:11::i;:::-;57684:6;::::0;57743:35:::2;::::0;-1:-1:-1;;;;;57684:6:0;;::::2;::::0;:10:::2;::::0;57703:4:::2;::::0;57710:5;;57743:35:::2;::::0;57754:11;;57767:10;;57743:35:::2;;;;;;;;;;;;;;;;;57684:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;1609:1;;;;;53988::::1;56650:1137:::0;;;:::o;53295:36::-;;;;:::o;9730:122::-;9811:5;;-1:-1:-1;;;;;9811:5:0;9797:10;:19;9789:28;;;;;;9830:5;:14;;-1:-1:-1;;;;;;9830:14:0;-1:-1:-1;;;;;9830:14:0;;;;;;;;;;9730:122::o;53649:44::-;;;-1:-1:-1;;;;;53649:44:0;;:::o;60195:203::-;60254:4;60271:13;53219:12;60287:11;:28;;:58;;53219:12;60287:58;;;60318:11;60287:58;60271:74;;60365:25;60369:8;60379:10;60365:3;:25::i;:::-;60358:32;;;60195:203;;;;:::o;53340:96::-;53394:42;53340:96;:::o;53252:36::-;;;;:::o;53443:85::-;53486:42;53443:85;:::o;10025:285::-;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;10125:42:::1;-1:-1:-1::0;;;;;10115:52:0;::::1;;10111:192;;;10192:5;::::0;;10184:32:::1;::::0;-1:-1:-1;;;;;10192:5:0;;::::1;::::0;10184:32;::::1;;;::::0;10208:7;;10184:32;10192:5;10184:32;10208:7;10192:5;10184:32;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;10111:192;;;10276:5;::::0;10249:42:::1;::::0;-1:-1:-1;;;;;10249:26:0;;::::1;::::0;10276:5:::1;10283:7:::0;10249:42:::1;:26;:42;:::i;:::-;10025:285:::0;;:::o;9898:80::-;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;9963:5:::1;::::0;-1:-1:-1;;;;;9963:5:0::1;9942:28;60940:144:::0;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;61030:7:::1;61019:8;:18;61011:27;;;::::0;::::1;;61051:14;:25:::0;60940:144::o;53141:32::-;;;;:::o;61207:103::-;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;-1:-1:-1;;;;;61271:24:0::1;;::::0;;;:15:::1;:24;::::0;;;;:31;;-1:-1:-1;;61271:31:0::1;61298:4;61271:31;::::0;;61207:103::o;53592:50::-;;;-1:-1:-1;;;;;53592:50:0;;:::o;8837:20::-;;;-1:-1:-1;;;;;8837:20:0;;:::o;55117:1134::-;53965:10;53949:27;;;;:15;:27;;;;;;;;53941:36;;;;;;55330:15:::1;::::0;1502:33:::1;::::0;-1:-1:-1;;;1502:33:0;;55330:15;;1404:42:::1;::::0;1502:18:::1;::::0;:33:::1;::::0;1529:4:::1;::::0;1502:33:::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;1498:99;;1563:22;::::0;-1:-1:-1;;;1563:22:0;;1404:42:::1;::::0;1563:13:::1;::::0;:22:::1;::::0;1577:7;;1563:22:::1;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1498:99;55361:14:::2;55377:16:::0;55397:28:::2;55405:12;55419:5;55397:7;:28::i;:::-;55360:65;;;;55444:9;55436:18;;;::::0;::::2;;55498:15;55516:27;55528:14;;55516:11;:27::i;:::-;55556:20;::::0;55641:29:::2;::::0;55685:246:::2;::::0;55498:45;;-1:-1:-1;;;;;;55556:20:0;;::::2;::::0;:32:::2;::::0;55596:9:::2;::::0;55621:5;;55641:29;::::2;::::0;55685:246:::2;::::0;55853:7;;55879:11;;55498:45;;55685:246:::2;;;;;;::::0;;-1:-1:-1;;55685:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;55685:246:0::2;-1:-1:-1::0;;;55685:246:0::2;::::0;;55556:386;::::2;::::0;;;-1:-1:-1;;;;;;55556:386:0;;;::::2;::::0;;;55685:246;55556:386:::2;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;55956:16;55974:15:::0;55993:35:::2;56008:12;56022:5;55993:14;:35::i;:::-;55955:73;;;;56047:11;56039:20;;;::::0;::::2;;56124:11;:9;:11::i;:::-;56148:6;::::0;56207:35:::2;::::0;-1:-1:-1;;;;;56148:6:0;;::::2;::::0;:10:::2;::::0;56167:4:::2;::::0;56174:5;;56207:35:::2;::::0;56218:11;;56231:10;;56207:35:::2;;;;;;;;;;;;;;;;;56148:95;;;;;;;;;;;;;;;;;;53102:32:::0;;;;:::o;53850:47::-;;;;;;;;;;;;;;;:::o;9509:122::-;9590:5;;-1:-1:-1;;;;;9590:5:0;9576:10;:19;9568:28;;;;;;9609:5;:14;;-1:-1:-1;;;;;;9609:14:0;-1:-1:-1;;;;;9609:14:0;;;;;;;;;;9509:122::o;60637:144::-;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;60727:7:::1;60716:8;:18;60708:27;;;::::0;::::1;;60748:14;:25:::0;60637:144::o;59497:490::-;59572:4;59578;59595:50;;:::i;:::-;59666:21;;:38;;-1:-1:-1;;;59666:38:0;;-1:-1:-1;;;;;59666:21:0;;;;:31;;:38;;59698:5;;59666:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59658:46;;59717:14;59734:21;59749:5;59734:14;:21::i;:::-;59717:38;-1:-1:-1;59783:12:0;59772:7;:23;;;;;;;;;59768:212;;;59832:15;;;;;-1:-1:-1;;;;;59820:27:0;;;;-1:-1:-1;59820:9:0;-1:-1:-1;59812:47:0;;59768:212;59892:12;59881:7;:23;;;;;;;;;59877:103;;;59941:15;;;;;-1:-1:-1;;;;;59929:27:0;;;;-1:-1:-1;59929:9:0;-1:-1:-1;59921:47:0;;59877:103;59497:490;;;;;;;:::o;37343:1709::-;37491:23;;-1:-1:-1;;;37491:23:0;;37403:4;;37465:23;;37181:42;;37491:16;;:23;;37508:5;;37491:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;37491:23:0;;;;;;;;;;;;;;37465:49;;37525:18;37181:42;-1:-1:-1;;;;;37546:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37525:34;-1:-1:-1;37574:18:0;;;37638:1242;37659:6;:13;37655:1;:17;37638:1242;;;37694:13;37710:6;37717:1;37710:9;;;;;;;;;;;;;;37694:25;;37739:18;37759;37779:25;37865:5;-1:-1:-1;;;;;37849:41:0;;37891:5;37849:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37736:161;;;;;;;37914:22;;:::i;:::-;37957:18;;;;:40;;-1:-1:-1;37979:18:0;;;37957:40;37953:173;;;38032:78;;;;;;;;;;-1:-1:-1;;;38047:61:0;;;38032:78;-1:-1:-1;;;;;38047:54:0;;;:61;38102:5;38047:61;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38032:78;;38018:92;-1:-1:-1;37953:173:0;38187:18;;38183:497;;38258:28;;-1:-1:-1;;;38258:28:0;;38231:23;;37181:42;;38258:12;;:28;;38279:5;;38258:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38228:58;;;38307:27;;:::i;:::-;-1:-1:-1;38337:35:0;;;;;;;;;;;;38391:23;;:::i;:::-;-1:-1:-1;38417:37:0;;;;;;;;;;;;38478:22;;:::i;:::-;38504:52;38512:16;38530:12;38544:11;38504:7;:52::i;:::-;38475:81;;;38597:67;38622:11;38635:13;38650;38597:24;:67::i;:::-;38577:87;-1:-1:-1;;;;;;38183:497:0;38735:18;;38731:138;;38790:63;38815:11;38828:13;38843:9;38790:24;:63::i;:::-;38774:79;-1:-1:-1;;38731:138:0;-1:-1:-1;;37674:3:0;;;;;-1:-1:-1;37638:1242:0;;-1:-1:-1;;37638:1242:0;;-1:-1:-1;38896:14:0;38892:35;;-1:-1:-1;;38912:15:0;;;;;;;;38892:35;38940:20;38986:13;38964:9;38976:6;38964:18;38963:36;;;;;;38940:59;;39017:27;39022:4;39028:15;39017:4;:27::i;:::-;39010:34;37343:1709;-1:-1:-1;;;;;;;37343:1709:0:o;9226:161::-;9307:5;;-1:-1:-1;;;;;9307:5:0;9293:10;:19;9285:28;;;;;;9332:5;;-1:-1:-1;;;;;9332:5:0;:19;9324:28;;;;;53182:49;53219:12;53182:49;:::o;53537:48::-;;;-1:-1:-1;;;;;53537:48:0;;:::o;61422:107::-;8933:5;;-1:-1:-1;;;;;8933:5:0;8942:10;8933:19;8925:28;;;;;;-1:-1:-1;;;;;61489:24:0::1;61516:5;61489:24:::0;;;:15:::1;:24;::::0;;;;:32;;-1:-1:-1;;61489:32:0::1;::::0;;61422:107::o;53702:65::-;;;-1:-1:-1;;;;;53702:65:0;;:::o;8864:20::-;;;-1:-1:-1;;;;;8864:20:0;;:::o;57868:184::-;57949:21;:25;57945:100;;57991:42;;:10;;58011:21;57991:42;;;;;;;;;58011:21;57991:10;:42;;;;;;;;;;;;;;;;;;;;;57945:100;57868:184::o;21694:127::-;21752:9;21782:6;;;:30;;-1:-1:-1;;21797:5:0;;;21811:1;21806;21797:5;21806:1;21792:15;;;;;:20;21782:30;21774:39;;;;;;21694:127;;;;:::o;6980:176::-;7062:86;7082:5;7112:23;;;7137:2;7141:5;7089:58;;;;;;;;;;;;;;-1:-1:-1;;7089:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;7089:58:0;-1:-1:-1;;;;;;7089:58:0;;;;;;;;;;7062:19;:86::i;:::-;6980:176;;;:::o;35111:284::-;35193:9;35204:10;;:::i;:::-;35228:13;35243;;:::i;:::-;35260:12;35267:1;35270;35260:6;:12::i;:::-;35227:45;;-1:-1:-1;35227:45:0;-1:-1:-1;35294:18:0;35287:3;:25;;;;;;;;;35283:74;;35337:3;;-1:-1:-1;35342:2:0;-1:-1:-1;35329:16:0;;35283:74;35374:13;35381:2;35385:1;35374:6;:13::i;:::-;35367:20;;;;;;35111:284;;;;;;;:::o;31583:328::-;31680:9;31691:4;31709:13;31724:18;;:::i;:::-;31746:20;31756:1;31759:6;31746:9;:20::i;:::-;31708:58;;-1:-1:-1;31708:58:0;-1:-1:-1;31788:18:0;31781:3;:25;;;;;;;;;31777:73;;-1:-1:-1;31831:3:0;-1:-1:-1;31836:1:0;;-1:-1:-1;31823:15:0;;31777:73;31869:34;31877:17;31886:7;31877:8;:17::i;:::-;31896:6;31869:7;:34::i;22735:120::-;22794:9;22846:1;22820:23;22824:11;22828:1;22424:6;22824:3;:11::i;:::-;22841:1;22837;:5;22820:3;:23::i;:::-;:27;;;;;;;22735:120;-1:-1:-1;;;22735:120:0:o;8352:419::-;8434:23;8460:69;8488:4;8460:69;;;;;;;;;;;;;;;;;8468:5;-1:-1:-1;;;;;8460:27:0;;;:69;;;;;:::i;:::-;8544:17;;8434:95;;-1:-1:-1;8544:21:0;8540:224;;8686:10;8675:30;;;;;;;;;;;;;;8667:85;;;;-1:-1:-1;;;8667:85:0;;;;;;;;;;;;;;;;33607:1136;33674:9;33685:10;;:::i;:::-;33711:14;33727:24;33755:31;33763:1;:10;;;33775:1;:10;;;33755:7;:31::i;:::-;33710:76;;-1:-1:-1;33710:76:0;-1:-1:-1;33809:18:0;33801:4;:26;;;;;;;;;33797:92;;-1:-1:-1;33858:18:0;;;;;;;;;-1:-1:-1;33858:18:0;;33852:4;;-1:-1:-1;33858:18:0;-1:-1:-1;33844:33:0;;33797:92;34206:14;;34263:42;29104:10;34285:19;34263:7;:42::i;:::-;34205:100;;-1:-1:-1;34205:100:0;-1:-1:-1;34328:18:0;34320:4;:26;;;;;;;;;34316:92;;34371:4;34377:18;;;;;;;;34392:1;34377:18;;;34363:33;;;;;;;;;;34316:92;34421:14;34437:12;34453:51;34461:32;29064:4;34453:7;:51::i;:::-;34420:84;;-1:-1:-1;34420:84:0;-1:-1:-1;34650:18:0;34642:4;:26;;;;;;;;;34635:34;;;;34710:24;;;;;;;;;;;;-1:-1:-1;;34710:24:0;;-1:-1:-1;33607:1136:0;-1:-1:-1;;;;;;;;33607:1136:0:o;30659:353::-;30728:9;30739:10;;:::i;:::-;30763:14;30779:19;30802:27;30810:1;:10;;;30822:6;30802:7;:27::i;:::-;30762:67;;-1:-1:-1;30762:67:0;-1:-1:-1;30852:18:0;30844:4;:26;;;;;;;;;30840:92;;-1:-1:-1;30901:18:0;;;;;;;;;-1:-1:-1;30901:18:0;;30895:4;;-1:-1:-1;30901:18:0;-1:-1:-1;30887:33:0;;30840:92;30972:31;;;;;;;;;;;;-1:-1:-1;;30972:31:0;;-1:-1:-1;30659:353:0;-1:-1:-1;;;;30659:353:0:o;35938:213::-;36120:12;29064:4;36120:23;;;35938:213::o;28394:258::-;28450:9;;28487:5;;;28509:6;;;28505:140;;28540:18;;-1:-1:-1;28560:1:0;-1:-1:-1;28532:30:0;;28505:140;-1:-1:-1;28603:26:0;;-1:-1:-1;28631:1:0;;-1:-1:-1;28595:38:0;;21452:113;21545:5;;;21540:16;;;;21532:25;;;;;3351:196;3454:12;3486:53;3509:6;3517:4;3523:1;3526:12;3486:22;:53::i;:::-;3479:60;3351:196;-1:-1:-1;;;;3351:196:0:o;27285:343::-;27341:9;;27373:6;27369:69;;-1:-1:-1;27404:18:0;;-1:-1:-1;27404:18:0;27396:30;;27369:69;27459:5;;;27463:1;27459;:5;:1;27481:5;;;;;:10;27477:144;;-1:-1:-1;27516:26:0;;-1:-1:-1;27544:1:0;;-1:-1:-1;27508:38:0;;27477:144;27587:18;;-1:-1:-1;27607:1:0;-1:-1:-1;27579:30:0;;27723:215;27779:9;;27811:6;27807:77;;-1:-1:-1;27842:26:0;;-1:-1:-1;27870:1:0;27834:38;;27807:77;27904:18;27928:1;27924;:5;;;;;;27896:34;;;;27723:215;;;;;:::o;4113:979::-;4243:12;4276:18;4287:6;4276:10;:18::i;:::-;4268:60;;;;-1:-1:-1;;;4268:60:0;;;;;;;;;4402:12;4416:23;4443:6;-1:-1:-1;;;;;4443:11:0;4463:8;4474:4;4443:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4401:78;;;;4494:7;4490:595;;;4525:10;-1:-1:-1;4518:17:0;;-1:-1:-1;4518:17:0;4490:595;4639:17;;:21;4635:439;;4902:10;4896:17;4963:15;4950:10;4946:2;4942:19;4935:44;4850:148;5045:12;5038:20;;-1:-1:-1;;;5038:20:0;;;;;;;;;2138:619;2198:4;2666:20;;2509:66;2706:23;;;;;;:42;;-1:-1:-1;;2733:15:0;;;2698:51;-1:-1:-1;;2138:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;;142:134;220:13;;238:33;220:13;238:33;;302:616;;417:3;410:4;402:6;398:17;394:27;384:2;;-1:-1;;425:12;384:2;478:78;25230:17;478:78;;;469:87;;562:16;621:17;679:3;25230:17;654:3;650:27;647:36;644:2;;;696:1;;686:12;644:2;721:1;706:206;459:4;728:1;725:13;706:206;;;85:6;72:20;97:33;124:5;97:33;;;799:50;;25242:4;863:14;;;;891;;;;;753:1;746:9;706:206;;;710:14;;;377:541;;;;;1674:128;1749:13;;27467;;27460:21;30162:32;;30152:2;;30208:1;;30198:12;1810:440;;1911:3;1904:4;1896:6;1892:17;1888:27;1878:2;;-1:-1;;1919:12;1878:2;1966:6;1953:20;25723:18;25715:6;25712:30;25709:2;;;-1:-1;;25745:12;25709:2;1988:64;25818:9;25799:17;;-1:-1;;25795:33;25886:4;25876:15;1988:64;;;1979:73;;2072:6;2065:5;2058:21;2176:3;25886:4;2167:6;2100;2158:16;;2155:25;2152:2;;;2193:1;;2183:12;2152:2;29528:6;25886:4;2100:6;2096:17;25886:4;2134:5;2130:16;29505:30;29584:1;29566:16;;;25886:4;29566:16;29559:27;2134:5;1871:379;-1:-1;;1871:379;5319:134;5397:13;;-1:-1;;;;;27555:46;;30395:35;;30385:2;;30444:1;;30434:12;5738:241;;5842:2;5830:9;5821:7;5817:23;5813:32;5810:2;;;-1:-1;;5848:12;5810:2;85:6;72:20;97:33;124:5;97:33;;;5900:63;5804:175;-1:-1;;;5804:175;5986:263;;6101:2;6089:9;6080:7;6076:23;6072:32;6069:2;;;-1:-1;;6107:12;6069:2;226:6;220:13;238:33;265:5;238:33;;6256:366;;;6377:2;6365:9;6356:7;6352:23;6348:32;6345:2;;;-1:-1;;6383:12;6345:2;85:6;72:20;97:33;124:5;97:33;;;6435:63;6535:2;6574:22;;;;5527:20;;-1:-1;;;6339:283;6629:392;;6769:2;;6757:9;6748:7;6744:23;6740:32;6737:2;;;-1:-1;;6775:12;6737:2;6826:17;6820:24;6864:18;;6856:6;6853:30;6850:2;;;-1:-1;;6886:12;6850:2;6988:6;6977:9;6973:22;1072:3;1065:4;1057:6;1053:17;1049:27;1039:2;;-1:-1;;1080:12;1039:2;1120:6;1114:13;1100:27;;6864:18;25420:6;25417:30;25414:2;;;-1:-1;;25450:12;25414:2;6769;25487:6;25483:17;;;1142:80;6769:2;25483:17;25548:15;1142:80;;;1250:21;;;1307:14;;;;1282:17;;;1387:27;;;;;1384:36;-1:-1;1381:2;;;-1:-1;;1423:12;1381:2;-1:-1;1449:10;;1443:217;1468:6;1465:1;1462:13;1443:217;;;1548:48;1592:3;1580:10;1548:48;;;1536:61;;1490:1;1483:9;;;;;1611:14;;;;1639;;1443:217;;;-1:-1;6906:99;6731:290;-1:-1;;;;;;;;6731:290;7028:257;;7140:2;7128:9;7119:7;7115:23;7111:32;7108:2;;;-1:-1;;7146:12;7108:2;1755:6;1749:13;30187:5;27467:13;27460:21;30165:5;30162:32;30152:2;;-1:-1;;30198:12;7292:393;;;7421:2;7409:9;7400:7;7396:23;7392:32;7389:2;;;-1:-1;;7427:12;7389:2;7489:61;7542:7;7518:22;7489:61;;;7479:71;;7587:2;7641:9;7637:22;5675:13;7595:74;;7383:302;;;;;;7692:388;;;7824:2;7812:9;7803:7;7799:23;7795:32;7792:2;;;-1:-1;;7830:12;7792:2;2349:6;2336:20;30304:1;30297:5;30294:12;30284:2;;-1:-1;;30310:12;30284:2;7882:74;-1:-1;7993:2;8032:22;;72:20;97:33;72:20;97:33;;;8001:63;;;;7786:294;;;;;;8087:328;;8234:3;8222:9;8213:7;8209:23;8205:33;8202:2;;;-1:-1;;8241:12;8202:2;2635:20;8234:3;2635:20;;;226:6;220:13;238:33;265:5;238:33;;;2712:86;;2896:60;2952:3;2863:2;2928:22;;2896:60;;;2863:2;2882:5;2878:16;2871:86;3055:60;3111:3;3022:2;3091:9;3087:22;3055:60;;;3022:2;3041:5;3037:16;3030:86;3223:60;3279:3;3190:2;3259:9;3255:22;3223:60;;;3190:2;3209:5;3205:16;3198:86;3392:60;3448:3;3358;3428:9;3424:22;3392:60;;;3358:3;3378:5;3374:16;3367:86;3556:57;3609:3;3522;3589:9;3585:22;3556:57;;;3522:3;3538:16;;3531:83;3542:5;8196:219;-1:-1;;;8196:219;8422:684;;;;8613:3;8601:9;8592:7;8588:23;8584:33;8581:2;;;-1:-1;;8620:12;8581:2;8678:17;8665:31;8716:18;;8708:6;8705:30;8702:2;;;-1:-1;;8738:12;8702:2;3805:6;;8819:22;;3784:19;;;3780:32;-1:-1;3777:2;;;-1:-1;;3815:12;3777:2;3843:22;3805:6;3843:22;;;3950:49;3995:3;3971:22;3950:49;;;3932:16;3925:75;4098:49;4143:3;4065:2;4123:9;4119:22;4098:49;;;4065:2;4084:5;4080:16;4073:75;4214:2;4272:9;4268:22;5527:20;4214:2;4233:5;4229:16;4222:75;4364:2;4422:9;4418:22;5527:20;4364:2;4383:5;4379:16;4372:75;8613:3;4571:9;4567:22;5527:20;8613:3;4532:5;4528:16;4521:75;4694:49;4739:3;4660;4719:9;4715:22;4694:49;;;4660:3;4680:5;4676:16;4669:75;4847:49;4892:3;4813;4872:9;4868:22;4847:49;;;4813:3;4833:5;4829:16;4822:75;4990:3;4979:9;4975:19;4962:33;4948:47;;8716:18;5007:6;5004:30;5001:2;;;-1:-1;;5037:12;5001:2;5082:58;5136:3;5127:6;5116:9;5112:22;5082:58;;;4990:3;5068:5;5064:16;5057:84;5205:3;;;;5266:9;5262:22;5527:20;5205:3;5225:5;5221:18;5214:77;8758:93;;;;;;;8906:76;8974:7;4065:2;8954:9;8950:22;8906:76;;;8896:86;;9037:53;9082:7;4364:2;9062:9;9058:22;9037:53;;;9027:63;;8575:531;;;;;;9113:241;;9217:2;9205:9;9196:7;9192:23;9188:32;9185:2;;;-1:-1;;9223:12;9185:2;-1:-1;5527:20;;9179:175;-1:-1;9179:175;9361:263;;9476:2;9464:9;9455:7;9451:23;9447:32;9444:2;;;-1:-1;;9482:12;9444:2;-1:-1;5675:13;;9438:186;-1:-1;9438:186;9631:672;;;;;9797:3;9785:9;9776:7;9772:23;9768:33;9765:2;;;-1:-1;;9804:12;9765:2;-1:-1;;5675:13;;9967:2;10017:22;;5675:13;10086:2;10136:22;;5675:13;10205:2;10255:22;;;5675:13;;;;;-1:-1;5675:13;;-1:-1;9759:544;-1:-1;9759:544;10492:103;-1:-1;;;;;27675:54;10553:37;;10547:48;10755:660;11118:21;11160:1;11145:258;26106:4;11167:1;11164:13;11145:258;;;11231:13;;-1:-1;;;;;27675:54;10553:37;;10473:4;10464:14;;;;26471;;;;25723:18;11185:9;11145:258;;;11149:14;;10867:548;;;11534:323;;11666:5;26214:12;26751:6;26746:3;26739:19;11749:52;11794:6;26788:4;26783:3;26779:14;26788:4;11775:5;11771:16;11749:52;;;25818:9;29945:14;-1:-1;;29941:28;11813:39;;;;26788:4;11813:39;;11614:243;-1:-1;;11614:243;17283:271;;12374:5;26214:12;12485:52;12530:6;12525:3;12518:4;12511:5;12507:16;12485:52;;;12549:16;;;;;17417:137;-1:-1;;17417:137;17561:222;-1:-1;;;;;27675:54;;;;10553:37;;17688:2;17673:18;;17659:124;17790:528;-1:-1;;;;;27675:54;;;10553:37;;27675:54;;18155:2;18140:18;;10553:37;17991:2;18192;18177:18;;18170:48;;;17790:528;;18232:76;;17976:18;;18294:6;18232:76;;;18224:84;17962:356;-1:-1;;;;;17962:356;18325:834;-1:-1;;;;;27675:54;;;10553:37;;27675:54;;18792:2;18777:18;;10553:37;18627:3;18829:2;18814:18;;18807:48;;;14095:2;18612:19;;;26739;-1:-1;;;27686:42;26779:14;;14111:45;14175:12;19033:2;19018:18;;19011:48;;;18325:834;;19073:76;;14175:12;;19135:6;19073:76;;19166:834;-1:-1;;;;;27675:54;;;10553:37;;27675:54;;19633:2;19618:18;;10553:37;19468:3;19670:2;19655:18;;19648:48;;;14426:2;19453:19;;;26739;-1:-1;;;27686:42;26779:14;;14442:45;14506:12;19874:2;19859:18;;19852:48;;;19166:834;;19914:76;;14506:12;;19976:6;19914:76;;20007:333;-1:-1;;;;;27675:54;;;;10553:37;;20326:2;20311:18;;17114:37;20162:2;20147:18;;20133:207;20347:210;27467:13;;27460:21;11488:34;;20468:2;20453:18;;20439:118;20564:321;27467:13;;27460:21;11488:34;;20871:2;20856:18;;17114:37;20713:2;20698:18;;20684:201;22311:310;;22458:2;22479:17;22472:47;22533:78;22458:2;22447:9;22443:18;22597:6;22533:78;;22628:416;22828:2;22842:47;;;14757:2;22813:18;;;26739:19;14793:31;26779:14;;;14773:52;14844:12;;;22799:245;23051:416;23251:2;23265:47;;;15095:2;23236:18;;;26739:19;15131:34;26779:14;;;15111:55;-1:-1;;;15186:12;;;15179:34;15232:12;;;23222:245;23474:705;;23763:3;23785:17;23778:47;15604:63;23763:3;23752:9;23748:19;15581:16;15575:23;15604:63;;;15750:4;15743:5;15739:16;15733:23;15762:63;15810:14;23752:9;15810:14;15796:12;15762:63;;;;15909:4;15902:5;15898:16;15892:23;15969:14;23752:9;15969:14;17114:37;16069:4;16062:5;16058:16;16052:23;16129:14;23752:9;16129:14;17114:37;23763:3;16220:5;16216:16;16210:23;16287:14;16210:23;16287:14;23752:9;16287:14;17114:37;15810:14;16377:5;16373:16;16367:23;16347:43;;15504:6;16396:63;15504:6;23752:9;16444:14;16430:12;16396:63;;;15969:14;16539:5;16535:16;16529:23;16509:43;;16558:63;16606:14;23752:9;16606:14;16592:12;16558:63;;;16129:14;16697:5;16693:16;16687:23;16667:43;;15504:6;16730:14;23752:9;16730:14;16723:38;;16776:71;15495:16;23752:9;15495:16;16828:12;16776:71;;;16924:18;;;16918:25;16997:16;;;17114:37;23831:126;-1:-1;23968:118;;-1:-1;15750:4;24067:18;;24058:6;23968:118;;;17144:5;16069:4;24154:9;24150:18;17114:37;23734:445;;;;;;;24186:222;17114:37;;;24313:2;24298:18;;24284:124;24415:333;17114:37;;;24734:2;24719:18;;17114:37;24570:2;24555:18;;24541:207;24755:256;24817:2;24811:9;24843:17;;;24918:18;24903:34;;24939:22;;;24900:62;24897:2;;;24975:1;;24965:12;24897:2;24817;24984:22;24795:216;;-1:-1;24795:216;29601:268;29666:1;29673:101;29687:6;29684:1;29681:13;29673:101;;;29754:11;;;29748:18;29735:11;;;29728:39;29709:2;29702:10;29673:101;;;29789:6;29786:1;29783:13;29780:2;;;-1:-1;;29666:1;29836:16;;29829:27;29650:219;29982:117;-1:-1;;;;;27675:54;;30041:35;;30031:2;;30090:1;;30080:12
Swarm Source
ipfs://ee38c0ddb1aa646452ad377130f15c76115575c8cbbf7a1dc02030d52cf71f41
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.