Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,582 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Boost For | 12289771 | 1170 days ago | IN | 0 ETH | 0.08652129 | ||||
Boost For | 12289771 | 1170 days ago | IN | 0 ETH | 0.08672764 | ||||
Boost For | 12289771 | 1170 days ago | IN | 0 ETH | 0.08971889 | ||||
Boost For | 12289771 | 1170 days ago | IN | 0 ETH | 0.09378777 | ||||
Boost For | 12289771 | 1170 days ago | IN | 0 ETH | 0.08981079 | ||||
Repay For | 12289533 | 1170 days ago | IN | 0 ETH | 0.12533073 | ||||
Boost For | 12289336 | 1170 days ago | IN | 0 ETH | 0.09582581 | ||||
Boost For | 12289336 | 1170 days ago | IN | 0 ETH | 0.10355743 | ||||
Boost For | 12288440 | 1170 days ago | IN | 0 ETH | 0.15516091 | ||||
Boost For | 12288440 | 1170 days ago | IN | 0 ETH | 0.14502055 | ||||
Boost For | 12288440 | 1170 days ago | IN | 0 ETH | 0.15531773 | ||||
Repay For | 12286724 | 1171 days ago | IN | 0 ETH | 0.12531029 | ||||
Repay For | 12286415 | 1171 days ago | IN | 0 ETH | 0.00965719 | ||||
Boost For | 12285613 | 1171 days ago | IN | 0 ETH | 0.11350276 | ||||
Boost For | 12285390 | 1171 days ago | IN | 0 ETH | 0.12906174 | ||||
Boost For | 12284845 | 1171 days ago | IN | 0 ETH | 0.19903353 | ||||
Boost For | 12284400 | 1171 days ago | IN | 0 ETH | 0.18026864 | ||||
Boost For | 12284225 | 1171 days ago | IN | 0 ETH | 0.15447734 | ||||
Boost For | 12284000 | 1171 days ago | IN | 0 ETH | 0.13923728 | ||||
Boost For | 12283999 | 1171 days ago | IN | 0 ETH | 0.16024845 | ||||
Boost For | 12283591 | 1171 days ago | IN | 0 ETH | 0.14882095 | ||||
Boost For | 12283591 | 1171 days ago | IN | 0 ETH | 0.1742426 | ||||
Boost For | 12280215 | 1172 days ago | IN | 0 ETH | 0.18735416 | ||||
Boost For | 12280215 | 1172 days ago | IN | 0 ETH | 0.19952136 | ||||
Boost For | 12280214 | 1172 days ago | IN | 0 ETH | 0.18650599 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
12261763 | 1175 days ago | 0.157248 ETH | ||||
12261763 | 1175 days ago | 0.157248 ETH | ||||
12261762 | 1175 days ago | 0.052416 ETH | ||||
12261678 | 1175 days ago | 0.02128 ETH | ||||
12169754 | 1189 days ago | 0.017808 ETH | ||||
12090887 | 1201 days ago | 0.030016 ETH | ||||
11983104 | 1217 days ago | 0.008176 ETH | ||||
11977274 | 1218 days ago | 0.034496 ETH | ||||
11931525 | 1225 days ago | 0.039872 ETH | ||||
11929839 | 1226 days ago | 0.02912 ETH | ||||
11929838 | 1226 days ago | 0.02912 ETH | ||||
11929650 | 1226 days ago | 0.029232 ETH | ||||
11912538 | 1228 days ago | 0.085904 ETH | ||||
11912516 | 1228 days ago | 0.323568 ETH | ||||
11912512 | 1228 days ago | 0.323568 ETH | ||||
11912511 | 1228 days ago | 0.107856 ETH | ||||
11912510 | 1228 days ago | 0.336336 ETH | ||||
11912506 | 1228 days ago | 0.230048 ETH | ||||
11912485 | 1228 days ago | 0.290528 ETH | ||||
11912473 | 1228 days ago | 0.244608 ETH | ||||
11912448 | 1228 days ago | 0.427392 ETH | ||||
11912447 | 1228 days ago | 0.126896 ETH | ||||
11912447 | 1228 days ago | 0.321888 ETH | ||||
11912444 | 1228 days ago | 0.321888 ETH | ||||
11912435 | 1228 days ago | 0.313824 ETH |
Loading...
Loading
Contract Name:
CompoundMonitor
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-12-01 */ pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; interface ERC20 { function totalSupply() external view returns (uint256 supply); function balanceOf(address _owner) external view returns (uint256 balance); function transfer(address _to, uint256 _value) external returns (bool success); function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success); function allowance(address _owner, address _spender) external view returns (uint256 remaining); function decimals() external view returns (uint256 digits); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } library Address { function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(ERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. */ function safeApprove(ERC20 token, address spender, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function _callOptionalReturn(ERC20 token, bytes memory data) private { bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } contract AdminAuth { using SafeERC20 for ERC20; address public owner; address public admin; modifier onlyOwner() { require(owner == msg.sender); _; } modifier onlyAdmin() { require(admin == msg.sender); _; } constructor() public { owner = msg.sender; admin = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; } /// @notice Admin is set by owner first time, after that admin is super role and has permission to change owner /// @param _admin Address of multisig that becomes admin function setAdminByOwner(address _admin) public { require(msg.sender == owner); require(admin == address(0)); admin = _admin; } /// @notice Admin is able to set new admin /// @param _admin Address of multisig that becomes new admin function setAdminByAdmin(address _admin) public { require(msg.sender == admin); admin = _admin; } /// @notice Admin is able to change owner /// @param _owner Address of new owner function setOwnerByAdmin(address _owner) public { require(msg.sender == admin); owner = _owner; } /// @notice Destroy the contract function kill() public onlyOwner { selfdestruct(payable(owner)); } /// @notice withdraw stuck funds function withdrawStuckFunds(address _token, uint _amount) public onlyOwner { if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { payable(owner).transfer(_amount); } else { ERC20(_token).safeTransfer(owner, _amount); } } } contract BotRegistry is AdminAuth { mapping (address => bool) public botList; constructor() public { botList[0x776B4a13093e30B05781F97F6A4565B6aa8BE330] = true; botList[0xAED662abcC4FA3314985E67Ea993CAD064a7F5cF] = true; botList[0xa5d330F6619d6bF892A5B87D80272e1607b3e34D] = true; botList[0x5feB4DeE5150B589a7f567EA7CADa2759794A90A] = true; botList[0x7ca06417c1d6f480d3bB195B80692F95A6B66158] = true; } function setBot(address _botAddr, bool _state) public onlyOwner { botList[_botAddr] = _state; } } abstract contract GasTokenInterface is ERC20 { function free(uint256 value) public virtual returns (bool success); function freeUpTo(uint256 value) public virtual returns (uint256 freed); function freeFrom(address from, uint256 value) public virtual returns (bool success); function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed); } contract GasBurner { // solhint-disable-next-line const-name-snakecase GasTokenInterface public constant gasToken = GasTokenInterface(0x0000000000b3F879cb30FE243b4Dfee438691c04); modifier burnGas(uint _amount) { if (gasToken.balanceOf(address(this)) >= _amount) { gasToken.free(_amount); } _; } } abstract contract DSProxyInterface { /// Truffle wont compile if this isn't commented // function execute(bytes memory _code, bytes memory _data) // public virtual // payable // returns (address, bytes32); function execute(address _target, bytes memory _data) public virtual payable returns (bytes32); function setCache(address _cacheAddr) public virtual payable returns (bool); function owner() public virtual returns (address); } /// @title Contract with the actuall DSProxy permission calls the automation operations contract CompoundMonitorProxy is AdminAuth { using SafeERC20 for ERC20; uint public CHANGE_PERIOD; address public monitor; address public newMonitor; address public lastMonitor; uint public changeRequestedTimestamp; mapping(address => bool) public allowed; event MonitorChangeInitiated(address oldMonitor, address newMonitor); event MonitorChangeCanceled(); event MonitorChangeFinished(address monitor); event MonitorChangeReverted(address monitor); // if someone who is allowed become malicious, owner can't be changed modifier onlyAllowed() { require(allowed[msg.sender] || msg.sender == owner); _; } modifier onlyMonitor() { require (msg.sender == monitor); _; } constructor(uint _changePeriod) public { CHANGE_PERIOD = _changePeriod * 1 days; } /// @notice Only monitor contract is able to call execute on users proxy /// @param _owner Address of cdp owner (users DSProxy address) /// @param _compoundSaverProxy Address of CompoundSaverProxy /// @param _data Data to send to CompoundSaverProxy function callExecute(address _owner, address _compoundSaverProxy, bytes memory _data) public payable onlyMonitor { // execute reverts if calling specific method fails DSProxyInterface(_owner).execute{value: msg.value}(_compoundSaverProxy, _data); // return if anything left if (address(this).balance > 0) { msg.sender.transfer(address(this).balance); } } /// @notice Allowed users are able to set Monitor contract without any waiting period first time /// @param _monitor Address of Monitor contract function setMonitor(address _monitor) public onlyAllowed { require(monitor == address(0)); monitor = _monitor; } /// @notice Allowed users are able to start procedure for changing monitor /// @dev after CHANGE_PERIOD needs to call confirmNewMonitor to actually make a change /// @param _newMonitor address of new monitor function changeMonitor(address _newMonitor) public onlyAllowed { require(changeRequestedTimestamp == 0); changeRequestedTimestamp = now; lastMonitor = monitor; newMonitor = _newMonitor; emit MonitorChangeInitiated(lastMonitor, newMonitor); } /// @notice At any point allowed users are able to cancel monitor change function cancelMonitorChange() public onlyAllowed { require(changeRequestedTimestamp > 0); changeRequestedTimestamp = 0; newMonitor = address(0); emit MonitorChangeCanceled(); } /// @notice Anyone is able to confirm new monitor after CHANGE_PERIOD if process is started function confirmNewMonitor() public onlyAllowed { require((changeRequestedTimestamp + CHANGE_PERIOD) < now); require(changeRequestedTimestamp != 0); require(newMonitor != address(0)); monitor = newMonitor; newMonitor = address(0); changeRequestedTimestamp = 0; emit MonitorChangeFinished(monitor); } /// @notice Its possible to revert monitor to last used monitor function revertMonitor() public onlyAllowed { require(lastMonitor != address(0)); monitor = lastMonitor; emit MonitorChangeReverted(monitor); } /// @notice Allowed users are able to add new allowed user /// @param _user Address of user that will be allowed function addAllowed(address _user) public onlyAllowed { allowed[_user] = true; } /// @notice Allowed users are able to remove allowed user /// @dev owner is always allowed even if someone tries to remove it from allowed mapping /// @param _user Address of allowed user function removeAllowed(address _user) public onlyAllowed { allowed[_user] = false; } function setChangePeriod(uint _periodInDays) public onlyAllowed { require(_periodInDays * 1 days > CHANGE_PERIOD); CHANGE_PERIOD = _periodInDays * 1 days; } /// @notice In case something is left in contract, owner is able to withdraw it /// @param _token address of token to withdraw balance function withdrawToken(address _token) public onlyOwner { uint balance = ERC20(_token).balanceOf(address(this)); ERC20(_token).safeTransfer(msg.sender, balance); } /// @notice In case something is left in contract, owner is able to withdraw it function withdrawEth() public onlyOwner { uint balance = address(this).balance; msg.sender.transfer(balance); } } /// @title Stores subscription information for Compound automatization contract CompoundSubscriptions is AdminAuth { struct CompoundHolder { address user; uint128 minRatio; uint128 maxRatio; uint128 optimalRatioBoost; uint128 optimalRatioRepay; bool boostEnabled; } struct SubPosition { uint arrPos; bool subscribed; } CompoundHolder[] public subscribers; mapping (address => SubPosition) public subscribersPos; uint public changeIndex; event Subscribed(address indexed user); event Unsubscribed(address indexed user); event Updated(address indexed user); event ParamUpdates(address indexed user, uint128, uint128, uint128, uint128, bool); /// @dev Called by the DSProxy contract which owns the Compound position /// @notice Adds the users Compound poistion in the list of subscriptions so it can be monitored /// @param _minRatio Minimum ratio below which repay is triggered /// @param _maxRatio Maximum ratio after which boost is triggered /// @param _optimalBoost Ratio amount which boost should target /// @param _optimalRepay Ratio amount which repay should target /// @param _boostEnabled Boolean determing if boost is enabled function subscribe(uint128 _minRatio, uint128 _maxRatio, uint128 _optimalBoost, uint128 _optimalRepay, bool _boostEnabled) external { // if boost is not enabled, set max ratio to max uint uint128 localMaxRatio = _boostEnabled ? _maxRatio : uint128(-1); require(checkParams(_minRatio, localMaxRatio), "Must be correct params"); SubPosition storage subInfo = subscribersPos[msg.sender]; CompoundHolder memory subscription = CompoundHolder({ minRatio: _minRatio, maxRatio: localMaxRatio, optimalRatioBoost: _optimalBoost, optimalRatioRepay: _optimalRepay, user: msg.sender, boostEnabled: _boostEnabled }); changeIndex++; if (subInfo.subscribed) { subscribers[subInfo.arrPos] = subscription; emit Updated(msg.sender); emit ParamUpdates(msg.sender, _minRatio, localMaxRatio, _optimalBoost, _optimalRepay, _boostEnabled); } else { subscribers.push(subscription); subInfo.arrPos = subscribers.length - 1; subInfo.subscribed = true; emit Subscribed(msg.sender); } } /// @notice Called by the users DSProxy /// @dev Owner who subscribed cancels his subscription function unsubscribe() external { _unsubscribe(msg.sender); } /// @dev Checks limit if minRatio is bigger than max /// @param _minRatio Minimum ratio, bellow which repay can be triggered /// @param _maxRatio Maximum ratio, over which boost can be triggered /// @return Returns bool if the params are correct function checkParams(uint128 _minRatio, uint128 _maxRatio) internal pure returns (bool) { if (_minRatio > _maxRatio) { return false; } return true; } /// @dev Internal method to remove a subscriber from the list /// @param _user The actual address that owns the Compound position function _unsubscribe(address _user) internal { require(subscribers.length > 0, "Must have subscribers in the list"); SubPosition storage subInfo = subscribersPos[_user]; require(subInfo.subscribed, "Must first be subscribed"); address lastOwner = subscribers[subscribers.length - 1].user; SubPosition storage subInfo2 = subscribersPos[lastOwner]; subInfo2.arrPos = subInfo.arrPos; subscribers[subInfo.arrPos] = subscribers[subscribers.length - 1]; subscribers.pop(); // remove last element and reduce arr length changeIndex++; subInfo.subscribed = false; subInfo.arrPos = 0; emit Unsubscribed(msg.sender); } /// @dev Checks if the user is subscribed /// @param _user The actual address that owns the Compound position /// @return If the user is subscribed function isSubscribed(address _user) public view returns (bool) { SubPosition storage subInfo = subscribersPos[_user]; return subInfo.subscribed; } /// @dev Returns subscribtion information about a user /// @param _user The actual address that owns the Compound position /// @return Subscription information about the user if exists function getHolder(address _user) public view returns (CompoundHolder memory) { SubPosition storage subInfo = subscribersPos[_user]; return subscribers[subInfo.arrPos]; } /// @notice Helper method to return all the subscribed CDPs /// @return List of all subscribers function getSubscribers() public view returns (CompoundHolder[] memory) { return subscribers; } /// @notice Helper method for the frontend, returns all the subscribed CDPs paginated /// @param _page What page of subscribers you want /// @param _perPage Number of entries per page /// @return List of all subscribers for that page function getSubscribersByPage(uint _page, uint _perPage) public view returns (CompoundHolder[] memory) { CompoundHolder[] memory holders = new CompoundHolder[](_perPage); uint start = _page * _perPage; uint end = start + _perPage; end = (end > holders.length) ? holders.length : end; uint count = 0; for (uint i = start; i < end; i++) { holders[count] = subscribers[i]; count++; } return holders; } ////////////// ADMIN METHODS /////////////////// /// @notice Admin function to unsubscribe a CDP /// @param _user The actual address that owns the Compound position function unsubscribeByAdmin(address _user) public onlyOwner { SubPosition storage subInfo = subscribersPos[_user]; if (subInfo.subscribed) { _unsubscribe(_user); } } } contract DSMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function div(uint256 x, uint256 y) internal pure returns (uint256 z) { return x / y; } function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x >= y ? x : y; } function imin(int256 x, int256 y) internal pure returns (int256 z) { return x <= y ? x : y; } function imax(int256 x, int256 y) internal pure returns (int256 z) { return x >= y ? x : y; } uint256 constant WAD = 10**18; uint256 constant RAY = 10**27; function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } contract DefisaverLogger { event LogEvent( address indexed contractAddress, address indexed caller, string indexed logName, bytes data ); // solhint-disable-next-line func-name-mixedcase function Log(address _contract, address _caller, string memory _logName, bytes memory _data) public { emit LogEvent(_contract, _caller, _logName, _data); } } abstract contract CompoundOracleInterface { function getUnderlyingPrice(address cToken) external view virtual returns (uint); } abstract contract ComptrollerInterface { struct CompMarketState { uint224 index; uint32 block; } function claimComp(address holder) public virtual; function claimComp(address holder, address[] memory cTokens) public virtual; function claimComp(address[] memory holders, address[] memory cTokens, bool borrowers, bool suppliers) public virtual; function compSupplyState(address) public view virtual returns (CompMarketState memory); function compSupplierIndex(address,address) public view virtual returns (uint); function compAccrued(address) public view virtual returns (uint); function compBorrowState(address) public view virtual returns (CompMarketState memory); function compBorrowerIndex(address,address) public view virtual returns (uint); function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory); function exitMarket(address cToken) external virtual returns (uint256); function getAssetsIn(address account) external virtual view returns (address[] memory); function markets(address account) public virtual view returns (bool, uint256); function getAccountLiquidity(address account) external virtual view returns (uint256, uint256, uint256); function oracle() public virtual view returns (address); } abstract contract CTokenInterface is ERC20 { function mint(uint256 mintAmount) external virtual returns (uint256); // function mint() external virtual payable; function accrueInterest() public virtual returns (uint); function redeem(uint256 redeemTokens) external virtual returns (uint256); function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256); function borrow(uint256 borrowAmount) external virtual returns (uint256); function borrowIndex() public view virtual returns (uint); function borrowBalanceStored(address) public view virtual returns(uint); function repayBorrow(uint256 repayAmount) external virtual returns (uint256); function repayBorrow() external virtual payable; function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256); function repayBorrowBehalf(address borrower) external virtual payable; function liquidateBorrow(address borrower, uint256 repayAmount, address cTokenCollateral) external virtual returns (uint256); function liquidateBorrow(address borrower, address cTokenCollateral) external virtual payable; function exchangeRateCurrent() external virtual returns (uint256); function supplyRatePerBlock() external virtual returns (uint256); function borrowRatePerBlock() external virtual returns (uint256); function totalReserves() external virtual returns (uint256); function reserveFactorMantissa() external virtual returns (uint256); function borrowBalanceCurrent(address account) external virtual returns (uint256); function totalBorrowsCurrent() external virtual returns (uint256); function getCash() external virtual returns (uint256); function balanceOfUnderlying(address owner) external virtual returns (uint256); function underlying() external virtual returns (address); function getAccountSnapshot(address account) external virtual view returns (uint, uint, uint, uint); } contract CarefulMath { /** * @dev Possible error codes that we can return */ enum MathError { NO_ERROR, DIVISION_BY_ZERO, INTEGER_OVERFLOW, INTEGER_UNDERFLOW } /** * @dev Multiplies two numbers, returns an error on overflow. */ function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { if (a == 0) { return (MathError.NO_ERROR, 0); } uint c = a * b; if (c / a != b) { return (MathError.INTEGER_OVERFLOW, 0); } else { return (MathError.NO_ERROR, c); } } /** * @dev Integer division of two numbers, truncating the quotient. */ function divUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b == 0) { return (MathError.DIVISION_BY_ZERO, 0); } return (MathError.NO_ERROR, a / b); } /** * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). */ function subUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b <= a) { return (MathError.NO_ERROR, a - b); } else { return (MathError.INTEGER_UNDERFLOW, 0); } } /** * @dev Adds two numbers, returns an error on overflow. */ function addUInt(uint a, uint b) internal pure returns (MathError, uint) { uint c = a + b; if (c >= a) { return (MathError.NO_ERROR, c); } else { return (MathError.INTEGER_OVERFLOW, 0); } } /** * @dev add a and b and then subtract c */ function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { (MathError err0, uint sum) = addUInt(a, b); if (err0 != MathError.NO_ERROR) { return (err0, 0); } return subUInt(sum, c); } } contract Exponential is CarefulMath { uint constant expScale = 1e18; uint constant doubleScale = 1e36; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } struct Double { uint mantissa; } /** * @dev Creates an exponential from numerator and denominator values. * Note: Returns an error if (`num` * 10e18) > MAX_INT, * or if `denom` is zero. */ function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint rational) = divUInt(scaledNumerator, denom); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: rational})); } /** * @dev Adds two exponentials, returning a new exponential. */ function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Subtracts two exponentials, returning a new exponential. */ function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Multiply an Exp by a scalar, returning a new Exp. */ function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(product)); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return addUInt(truncate(product), addend); } /** * @dev Divide an Exp by a scalar, returning a new Exp. */ function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); } /** * @dev Divide a scalar by an Exp, returning a new Exp. */ function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { /* We are doing this as: getExp(mulUInt(expScale, scalar), divisor.mantissa) How it works: Exp = a / b; Scalar = s; `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` */ (MathError err0, uint numerator) = mulUInt(expScale, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return getExp(numerator, divisor.mantissa); } /** * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. */ function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(fraction)); } /** * @dev Multiplies two exponentials, returning a new exponential. */ function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } // We add half the scale before dividing so that we get rounding instead of truncation. // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. assert(err2 == MathError.NO_ERROR); return (MathError.NO_ERROR, Exp({mantissa: product})); } /** * @dev Multiplies two exponentials given their mantissas, returning a new exponential. */ function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); } /** * @dev Multiplies three exponentials, returning a new exponential. */ function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { (MathError err, Exp memory ab) = mulExp(a, b); if (err != MathError.NO_ERROR) { return (err, ab); } return mulExp(ab, c); } /** * @dev Divides two exponentials, returning a new exponential. * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) */ function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { return getExp(a.mantissa, b.mantissa); } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint a, uint b) pure internal returns (uint) { return sub_(a, b, "subtraction underflow"); } function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b <= a, errorMessage); return a - b; } function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Exp memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Double memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint a, uint b) pure internal returns (uint) { return mul_(a, b, "multiplication overflow"); } function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { if (a == 0 || b == 0) { return 0; } uint c = a * b; require(c / a == b, errorMessage); return c; } function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Exp memory b) pure internal returns (uint) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Double memory b) pure internal returns (uint) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint a, uint b) pure internal returns (uint) { return div_(a, b, "divide by zero"); } function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b > 0, errorMessage); return a / b; } function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint a, uint b) pure internal returns (uint) { return add_(a, b, "addition overflow"); } function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { uint c = a + b; require(c >= a, errorMessage); return c; } } contract CompoundSafetyRatio is Exponential, DSMath { // solhint-disable-next-line const-name-snakecase ComptrollerInterface public constant comp = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); /// @notice Calcualted the ratio of debt / adjusted collateral /// @param _user Address of the user function getSafetyRatio(address _user) public view returns (uint) { // For each asset the account is in address[] memory assets = comp.getAssetsIn(_user); address oracleAddr = comp.oracle(); uint sumCollateral = 0; uint sumBorrow = 0; for (uint i = 0; i < assets.length; i++) { address asset = assets[i]; (, uint cTokenBalance, uint borrowBalance, uint exchangeRateMantissa) = CTokenInterface(asset).getAccountSnapshot(_user); Exp memory oraclePrice; if (cTokenBalance != 0 || borrowBalance != 0) { oraclePrice = Exp({mantissa: CompoundOracleInterface(oracleAddr).getUnderlyingPrice(asset)}); } // Sum up collateral in Usd if (cTokenBalance != 0) { (, uint collFactorMantissa) = comp.markets(address(asset)); Exp memory collateralFactor = Exp({mantissa: collFactorMantissa}); Exp memory exchangeRate = Exp({mantissa: exchangeRateMantissa}); (, Exp memory tokensToUsd) = mulExp3(collateralFactor, exchangeRate, oraclePrice); (, sumCollateral) = mulScalarTruncateAddUInt(tokensToUsd, cTokenBalance, sumCollateral); } // Sum up debt in Usd if (borrowBalance != 0) { (, sumBorrow) = mulScalarTruncateAddUInt(oraclePrice, borrowBalance, sumBorrow); } } if (sumBorrow == 0) return uint(-1); uint borrowPowerUsed = (sumBorrow * 10**18) / sumCollateral; return wdiv(1e18, borrowPowerUsed); } } abstract contract TokenInterface { function allowance(address, address) public virtual returns (uint256); function balanceOf(address) public virtual returns (uint256); function approve(address, uint256) public virtual; function transfer(address, uint256) public virtual returns (bool); function transferFrom(address, address, uint256) public virtual returns (bool); function deposit() public virtual payable; function withdraw(uint256) public virtual; } interface ExchangeInterfaceV2 { function sell(address _srcAddr, address _destAddr, uint _srcAmount) external payable returns (uint); function buy(address _srcAddr, address _destAddr, uint _destAmount) external payable returns(uint); function getSellRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint); function getBuyRate(address _srcAddr, address _destAddr, uint _srcAmount) external view returns (uint); } contract ZrxAllowlist is AdminAuth { mapping (address => bool) public zrxAllowlist; mapping(address => bool) private nonPayableAddrs; constructor() public { zrxAllowlist[0x6958F5e95332D93D21af0D7B9Ca85B8212fEE0A5] = true; zrxAllowlist[0x61935CbDd02287B511119DDb11Aeb42F1593b7Ef] = true; zrxAllowlist[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; zrxAllowlist[0x080bf510FCbF18b91105470639e9561022937712] = true; nonPayableAddrs[0x080bf510FCbF18b91105470639e9561022937712] = true; } function setAllowlistAddr(address _zrxAddr, bool _state) public onlyOwner { zrxAllowlist[_zrxAddr] = _state; } function isZrxAddr(address _zrxAddr) public view returns (bool) { return zrxAllowlist[_zrxAddr]; } function addNonPayableAddr(address _nonPayableAddr) public onlyOwner { nonPayableAddrs[_nonPayableAddr] = true; } function removeNonPayableAddr(address _nonPayableAddr) public onlyOwner { nonPayableAddrs[_nonPayableAddr] = false; } function isNonPayableAddr(address _addr) public view returns(bool) { return nonPayableAddrs[_addr]; } } contract Discount { address public owner; mapping(address => CustomServiceFee) public serviceFees; uint256 constant MAX_SERVICE_FEE = 400; struct CustomServiceFee { bool active; uint256 amount; } constructor() public { owner = msg.sender; } function isCustomFeeSet(address _user) public view returns (bool) { return serviceFees[_user].active; } function getCustomServiceFee(address _user) public view returns (uint256) { return serviceFees[_user].amount; } function setServiceFee(address _user, uint256 _fee) public { require(msg.sender == owner, "Only owner"); require(_fee >= MAX_SERVICE_FEE || _fee == 0); serviceFees[_user] = CustomServiceFee({active: true, amount: _fee}); } function disableServiceFee(address _user) public { require(msg.sender == owner, "Only owner"); serviceFees[_user] = CustomServiceFee({active: false, amount: 0}); } } contract SaverExchangeHelper { using SafeERC20 for ERC20; address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08; address public constant DISCOUNT_ADDRESS = 0x1b14E8D511c9A4395425314f849bD737BAF8208F; address public constant SAVER_EXCHANGE_REGISTRY = 0x25dd3F51e0C3c3Ff164DDC02A8E4D65Bb9cBB12D; address public constant ERC20_PROXY_0X = 0x95E6F48254609A6ee006F7D493c8e5fB97094ceF; address public constant ZRX_ALLOWLIST_ADDR = 0x4BA1f38427b33B8ab7Bb0490200dAE1F1C36823F; function getDecimals(address _token) internal view returns (uint256) { if (_token == KYBER_ETH_ADDRESS) return 18; return ERC20(_token).decimals(); } function getBalance(address _tokenAddr) internal view returns (uint balance) { if (_tokenAddr == KYBER_ETH_ADDRESS) { balance = address(this).balance; } else { balance = ERC20(_tokenAddr).balanceOf(address(this)); } } function approve0xProxy(address _tokenAddr, uint _amount) internal { if (_tokenAddr != KYBER_ETH_ADDRESS) { ERC20(_tokenAddr).safeApprove(address(ERC20_PROXY_0X), _amount); } } function sendLeftover(address _srcAddr, address _destAddr, address payable _to) internal { // send back any leftover ether or tokens if (address(this).balance > 0) { _to.transfer(address(this).balance); } if (getBalance(_srcAddr) > 0) { ERC20(_srcAddr).safeTransfer(_to, getBalance(_srcAddr)); } if (getBalance(_destAddr) > 0) { ERC20(_destAddr).safeTransfer(_to, getBalance(_destAddr)); } } function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) { require(bs.length >= start + 32, "slicing out of range"); uint256 x; assembly { x := mload(add(bs, add(0x20, start))) } return x; } } contract SaverExchangeRegistry is AdminAuth { mapping(address => bool) private wrappers; constructor() public { wrappers[0x880A845A85F843a5c67DB2061623c6Fc3bB4c511] = true; wrappers[0x4c9B55f2083629A1F7aDa257ae984E03096eCD25] = true; wrappers[0x42A9237b872368E1bec4Ca8D26A928D7d39d338C] = true; } function addWrapper(address _wrapper) public onlyOwner { wrappers[_wrapper] = true; } function removeWrapper(address _wrapper) public onlyOwner { wrappers[_wrapper] = false; } function isWrapper(address _wrapper) public view returns(bool) { return wrappers[_wrapper]; } } contract SaverExchangeCore is SaverExchangeHelper, DSMath { // first is empty to keep the legacy order in place enum ExchangeType { _, OASIS, KYBER, UNISWAP, ZEROX } enum ActionType { SELL, BUY } struct ExchangeData { address srcAddr; address destAddr; uint srcAmount; uint destAmount; uint minPrice; address wrapper; address exchangeAddr; bytes callData; uint256 price0x; } /// @notice Internal method that preforms a sell on 0x/on-chain /// @dev Usefull for other DFS contract to integrate for exchanging /// @param exData Exchange data struct /// @return (address, uint) Address of the wrapper used and destAmount function _sell(ExchangeData memory exData) internal returns (address, uint) { address wrapper; uint swapedTokens; bool success; uint tokensLeft = exData.srcAmount; // if selling eth, convert to weth if (exData.srcAddr == KYBER_ETH_ADDRESS) { exData.srcAddr = ethToWethAddr(exData.srcAddr); TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)(); } // Try 0x first and then fallback on specific wrapper if (exData.price0x > 0) { approve0xProxy(exData.srcAddr, exData.srcAmount); uint ethAmount = getProtocolFee(exData.srcAddr, exData.srcAmount); (success, swapedTokens, tokensLeft) = takeOrder(exData, ethAmount, ActionType.SELL); if (success) { wrapper = exData.exchangeAddr; } } // fallback to desired wrapper if 0x failed if (!success) { swapedTokens = saverSwap(exData, ActionType.SELL); wrapper = exData.wrapper; } require(getBalance(exData.destAddr) >= wmul(exData.minPrice, exData.srcAmount), "Final amount isn't correct"); // if anything is left in weth, pull it to user as eth if (getBalance(WETH_ADDRESS) > 0) { TokenInterface(WETH_ADDRESS).withdraw( TokenInterface(WETH_ADDRESS).balanceOf(address(this)) ); } return (wrapper, swapedTokens); } /// @notice Internal method that preforms a buy on 0x/on-chain /// @dev Usefull for other DFS contract to integrate for exchanging /// @param exData Exchange data struct /// @return (address, uint) Address of the wrapper used and srcAmount function _buy(ExchangeData memory exData) internal returns (address, uint) { address wrapper; uint swapedTokens; bool success; require(exData.destAmount != 0, "Dest amount must be specified"); // if selling eth, convert to weth if (exData.srcAddr == KYBER_ETH_ADDRESS) { exData.srcAddr = ethToWethAddr(exData.srcAddr); TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)(); } if (exData.price0x > 0) { approve0xProxy(exData.srcAddr, exData.srcAmount); uint ethAmount = getProtocolFee(exData.srcAddr, exData.srcAmount); (success, swapedTokens,) = takeOrder(exData, ethAmount, ActionType.BUY); if (success) { wrapper = exData.exchangeAddr; } } // fallback to desired wrapper if 0x failed if (!success) { swapedTokens = saverSwap(exData, ActionType.BUY); wrapper = exData.wrapper; } require(getBalance(exData.destAddr) >= exData.destAmount, "Final amount isn't correct"); // if anything is left in weth, pull it to user as eth if (getBalance(WETH_ADDRESS) > 0) { TokenInterface(WETH_ADDRESS).withdraw( TokenInterface(WETH_ADDRESS).balanceOf(address(this)) ); } return (wrapper, getBalance(exData.destAddr)); } /// @notice Takes order from 0x and returns bool indicating if it is successful /// @param _exData Exchange data /// @param _ethAmount Ether fee needed for 0x order function takeOrder( ExchangeData memory _exData, uint256 _ethAmount, ActionType _type ) private returns (bool success, uint256, uint256) { // write in the exact amount we are selling/buing in an order if (_type == ActionType.SELL) { writeUint256(_exData.callData, 36, _exData.srcAmount); } else { writeUint256(_exData.callData, 36, _exData.destAmount); } if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isNonPayableAddr(_exData.exchangeAddr)) { _ethAmount = 0; } uint256 tokensBefore = getBalance(_exData.destAddr); if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isZrxAddr(_exData.exchangeAddr)) { (success, ) = _exData.exchangeAddr.call{value: _ethAmount}(_exData.callData); } else { success = false; } uint256 tokensSwaped = 0; uint256 tokensLeft = _exData.srcAmount; if (success) { // check to see if any _src tokens are left over after exchange tokensLeft = getBalance(_exData.srcAddr); // convert weth -> eth if needed if (_exData.destAddr == KYBER_ETH_ADDRESS) { TokenInterface(WETH_ADDRESS).withdraw( TokenInterface(WETH_ADDRESS).balanceOf(address(this)) ); } // get the current balance of the swaped tokens tokensSwaped = getBalance(_exData.destAddr) - tokensBefore; } return (success, tokensSwaped, tokensLeft); } /// @notice Calls wraper contract for exchage to preform an on-chain swap /// @param _exData Exchange data struct /// @param _type Type of action SELL|BUY /// @return swapedTokens For Sell that the destAmount, for Buy thats the srcAmount function saverSwap(ExchangeData memory _exData, ActionType _type) internal returns (uint swapedTokens) { require(SaverExchangeRegistry(SAVER_EXCHANGE_REGISTRY).isWrapper(_exData.wrapper), "Wrapper is not valid"); uint ethValue = 0; ERC20(_exData.srcAddr).safeTransfer(_exData.wrapper, _exData.srcAmount); if (_type == ActionType.SELL) { swapedTokens = ExchangeInterfaceV2(_exData.wrapper). sell{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.srcAmount); } else { swapedTokens = ExchangeInterfaceV2(_exData.wrapper). buy{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.destAmount); } } function writeUint256(bytes memory _b, uint256 _index, uint _input) internal pure { if (_b.length < _index + 32) { revert("Incorrent lengt while writting bytes32"); } bytes32 input = bytes32(_input); _index += 32; // Read the bytes32 from array memory assembly { mstore(add(_b, _index), input) } } /// @notice Converts Kybers Eth address -> Weth /// @param _src Input address function ethToWethAddr(address _src) internal pure returns (address) { return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src; } /// @notice Calculates protocol fee /// @param _srcAddr selling token address (if eth should be WETH) /// @param _srcAmount amount we are selling function getProtocolFee(address _srcAddr, uint256 _srcAmount) internal view returns(uint256) { // if we are not selling ETH msg value is always the protocol fee if (_srcAddr != WETH_ADDRESS) return address(this).balance; // if msg value is larger than srcAmount, that means that msg value is protocol fee + srcAmount, so we subsctract srcAmount from msg value // we have an edge case here when protocol fee is higher than selling amount if (address(this).balance > _srcAmount) return address(this).balance - _srcAmount; // if msg value is lower than src amount, that means that srcAmount isn't included in msg value, so we return msg value return address(this).balance; } function packExchangeData(ExchangeData memory _exData) public pure returns(bytes memory) { // splitting in two different bytes and encoding all because of stack too deep in decoding part bytes memory part1 = abi.encode( _exData.srcAddr, _exData.destAddr, _exData.srcAmount, _exData.destAmount ); bytes memory part2 = abi.encode( _exData.minPrice, _exData.wrapper, _exData.exchangeAddr, _exData.callData, _exData.price0x ); return abi.encode(part1, part2); } function unpackExchangeData(bytes memory _data) public pure returns(ExchangeData memory _exData) { ( bytes memory part1, bytes memory part2 ) = abi.decode(_data, (bytes,bytes)); ( _exData.srcAddr, _exData.destAddr, _exData.srcAmount, _exData.destAmount ) = abi.decode(part1, (address,address,uint256,uint256)); ( _exData.minPrice, _exData.wrapper, _exData.exchangeAddr, _exData.callData, _exData.price0x ) = abi.decode(part2, (uint256,address,address,bytes,uint256)); } // solhint-disable-next-line no-empty-blocks receive() external virtual payable {} } /// @title Contract implements logic of calling boost/repay in the automatic system contract CompoundMonitor is AdminAuth, DSMath, CompoundSafetyRatio, GasBurner { using SafeERC20 for ERC20; enum Method { Boost, Repay } uint public REPAY_GAS_TOKEN = 20; uint public BOOST_GAS_TOKEN = 20; uint constant public MAX_GAS_PRICE = 500000000000; // 500 gwei uint public REPAY_GAS_COST = 2000000; uint public BOOST_GAS_COST = 2000000; address public constant GAS_TOKEN_INTERFACE_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04; address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126; address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B; CompoundMonitorProxy public compoundMonitorProxy; CompoundSubscriptions public subscriptionsContract; address public compoundFlashLoanTakerAddress; DefisaverLogger public logger = DefisaverLogger(DEFISAVER_LOGGER); modifier onlyApproved() { require(BotRegistry(BOT_REGISTRY_ADDRESS).botList(msg.sender), "Not auth bot"); _; } /// @param _compoundMonitorProxy Proxy contracts that actually is authorized to call DSProxy /// @param _subscriptions Subscriptions contract for Compound positions /// @param _compoundFlashLoanTaker Contract that actually performs Repay/Boost constructor(address _compoundMonitorProxy, address _subscriptions, address _compoundFlashLoanTaker) public { compoundMonitorProxy = CompoundMonitorProxy(_compoundMonitorProxy); subscriptionsContract = CompoundSubscriptions(_subscriptions); compoundFlashLoanTakerAddress = _compoundFlashLoanTaker; } /// @notice Bots call this method to repay for user when conditions are met /// @dev If the contract ownes gas token it will try and use it for gas price reduction /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress] /// @param _user The actual address that owns the Compound position function repayFor( SaverExchangeCore.ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress address _user ) public payable onlyApproved burnGas(REPAY_GAS_TOKEN) { (bool isAllowed, uint ratioBefore) = canCall(Method.Repay, _user); require(isAllowed); // check if conditions are met uint256 gasCost = calcGasCost(REPAY_GAS_COST); compoundMonitorProxy.callExecute{value: msg.value}( _user, compoundFlashLoanTakerAddress, abi.encodeWithSignature( "repayWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)", _exData, _cAddresses, gasCost ) ); (bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Repay, _user); require(isGoodRatio); // check if the after result of the actions is good returnEth(); logger.Log(address(this), _user, "AutomaticCompoundRepay", abi.encode(ratioBefore, ratioAfter)); } /// @notice Bots call this method to boost for user when conditions are met /// @dev If the contract ownes gas token it will try and use it for gas price reduction /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress] /// @param _user The actual address that owns the Compound position function boostFor( SaverExchangeCore.ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress address _user ) public payable onlyApproved burnGas(BOOST_GAS_TOKEN) { (bool isAllowed, uint ratioBefore) = canCall(Method.Boost, _user); require(isAllowed); // check if conditions are met uint256 gasCost = calcGasCost(BOOST_GAS_COST); compoundMonitorProxy.callExecute{value: msg.value}( _user, compoundFlashLoanTakerAddress, abi.encodeWithSignature( "boostWithLoan((address,address,uint256,uint256,uint256,address,address,bytes,uint256),address[2],uint256)", _exData, _cAddresses, gasCost ) ); (bool isGoodRatio, uint ratioAfter) = ratioGoodAfter(Method.Boost, _user); require(isGoodRatio); // check if the after result of the actions is good returnEth(); logger.Log(address(this), _user, "AutomaticCompoundBoost", abi.encode(ratioBefore, ratioAfter)); } /******************* INTERNAL METHODS ********************************/ function returnEth() internal { // return if some eth left if (address(this).balance > 0) { msg.sender.transfer(address(this).balance); } } /******************* STATIC METHODS ********************************/ /// @notice Checks if Boost/Repay could be triggered for the CDP /// @dev Called by MCDMonitor to enforce the min/max check /// @param _method Type of action to be called /// @param _user The actual address that owns the Compound position /// @return Boolean if it can be called and the ratio function canCall(Method _method, address _user) public view returns(bool, uint) { bool subscribed = subscriptionsContract.isSubscribed(_user); CompoundSubscriptions.CompoundHolder memory holder = subscriptionsContract.getHolder(_user); // check if cdp is subscribed if (!subscribed) return (false, 0); // check if boost and boost allowed if (_method == Method.Boost && !holder.boostEnabled) return (false, 0); uint currRatio = getSafetyRatio(_user); if (_method == Method.Repay) { return (currRatio < holder.minRatio, currRatio); } else if (_method == Method.Boost) { return (currRatio > holder.maxRatio, currRatio); } } /// @dev After the Boost/Repay check if the ratio doesn't trigger another call /// @param _method Type of action to be called /// @param _user The actual address that owns the Compound position /// @return Boolean if the recent action preformed correctly and the ratio function ratioGoodAfter(Method _method, address _user) public view returns(bool, uint) { CompoundSubscriptions.CompoundHolder memory holder; holder= subscriptionsContract.getHolder(_user); uint currRatio = getSafetyRatio(_user); if (_method == Method.Repay) { return (currRatio < holder.maxRatio, currRatio); } else if (_method == Method.Boost) { return (currRatio > holder.minRatio, currRatio); } } /// @notice Calculates gas cost (in Eth) of tx /// @dev Gas price is limited to MAX_GAS_PRICE to prevent attack of draining user CDP /// @param _gasAmount Amount of gas used for the tx function calcGasCost(uint _gasAmount) public view returns (uint) { uint gasPrice = tx.gasprice <= MAX_GAS_PRICE ? tx.gasprice : MAX_GAS_PRICE; return mul(gasPrice, _gasAmount); } /******************* OWNER ONLY OPERATIONS ********************************/ /// @notice As the code is new, have a emergancy admin saver proxy change function changeCompoundFlashLoanTaker(address _newCompoundFlashLoanTakerAddress) public onlyAdmin { compoundFlashLoanTakerAddress = _newCompoundFlashLoanTakerAddress; } /// @notice Allows owner to change gas cost for boost operation, but only up to 3 millions /// @param _gasCost New gas cost for boost method function changeBoostGasCost(uint _gasCost) public onlyOwner { require(_gasCost < 3000000); BOOST_GAS_COST = _gasCost; } /// @notice Allows owner to change gas cost for repay operation, but only up to 3 millions /// @param _gasCost New gas cost for repay method function changeRepayGasCost(uint _gasCost) public onlyOwner { require(_gasCost < 3000000); REPAY_GAS_COST = _gasCost; } /// @notice If any tokens gets stuck in the contract owner can withdraw it /// @param _tokenAddress Address of the ERC20 token /// @param _to Address of the receiver /// @param _amount The amount to be sent function transferERC20(address _tokenAddress, address _to, uint _amount) public onlyOwner { ERC20(_tokenAddress).safeTransfer(_to, _amount); } /// @notice If any Eth gets stuck in the contract owner can withdraw it /// @param _to Address of the receiver /// @param _amount The amount to be sent function transferEth(address payable _to, uint _amount) public onlyOwner { _to.transfer(_amount); } }
Contract Security Audit
- 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":"BOT_REGISTRY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFISAVER_LOGGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAS_TOKEN_INTERFACE_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GAS_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPAY_GAS_COST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPAY_GAS_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"},{"internalType":"address[2]","name":"_cAddresses","type":"address[2]"},{"internalType":"address","name":"_user","type":"address"}],"name":"boostFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasAmount","type":"uint256"}],"name":"calcGasCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum CompoundMonitor.Method","name":"_method","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"canCall","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCost","type":"uint256"}],"name":"changeBoostGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCompoundFlashLoanTakerAddress","type":"address"}],"name":"changeCompoundFlashLoanTaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCost","type":"uint256"}],"name":"changeRepayGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comp","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundFlashLoanTakerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundMonitorProxy","outputs":[{"internalType":"contract CompoundMonitorProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasToken","outputs":[{"internalType":"contract GasTokenInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getSafetyRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum CompoundMonitor.Method","name":"_method","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"ratioGoodAfter","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"},{"internalType":"address[2]","name":"_cAddresses","type":"address[2]"},{"internalType":"address","name":"_user","type":"address"}],"name":"repayFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdminByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwnerByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subscriptionsContract","outputs":[{"internalType":"contract CompoundSubscriptions","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405260146002819055600355621e84806004819055600555600980546001600160a01b031916735c55b921f590a89c1ebe84df170e655a82b621261790553480156200004d57600080fd5b5060405162002528380380620025288339810160408190526200007091620000dc565b600080546001600160a01b031990811633179091556001805482167325efa336886c74ea8e282ac466bdcd0199f85bb9179055600680546001600160a01b0395861690831617905560078054938516938216939093179092556008805491909316911617905562000148565b600080600060608486031215620000f1578283fd5b8351620000fe816200012f565b602085015190935062000111816200012f565b604085015190925062000124816200012f565b809150509250925092565b6001600160a01b03811681146200014557600080fd5b50565b6123d080620001586000396000f3fe6080604052600436106101e35760003560e01c80638da5cb5b11610102578063c91d59fe11610095578063e9bb84c211610064578063e9bb84c2146104d2578063ec23ef27146104f2578063f24ccbfe14610507578063f851a4401461051c576101e3565b8063c91d59fe146102cd578063d98bb5b11461047d578063deca5f881461049d578063e3bbb4f1146104bd576101e3565b8063a56f9718116100d1578063a56f971814610408578063a7304bf71461041d578063a8c903231461043d578063bfc361721461045d576101e3565b80638da5cb5b146103a057806398a3f265146103b55780639da6136b146103c85780639db5dbe4146103e8576101e3565b806336fc603f1161017a5780634d3f199e116101495780634d3f199e14610341578063526d646114610361578063696806c01461037657806379521f021461038b576101e3565b806336fc603f146102e257806339df1878146102f75780633a1283221461030c57806341c0e1b51461032c576101e3565b80631e48907b116101b65780631e48907b1461027857806329ad0f36146102985780632a56f602146102ad57806332ac5cd2146102cd576101e3565b806306d5e37e146101e8578063109d0af81461021f578063139198941461024157806318bf60e114610256575b600080fd5b3480156101f457600080fd5b50610208610203366004611da5565b610531565b604051610216929190612175565b60405180910390f35b34801561022b57600080fd5b506102346106fd565b604051610216919061205f565b61025461024f366004611e6e565b610715565b005b34801561026257600080fd5b5061026b610a6a565b60405161021691906122f8565b34801561028457600080fd5b50610254610293366004611bf1565b610a70565b3480156102a457600080fd5b50610234610aa9565b3480156102b957600080fd5b5061026b6102c8366004611f73565b610ab8565b3480156102d957600080fd5b50610234610aea565b3480156102ee57600080fd5b5061026b610afd565b34801561030357600080fd5b50610234610b03565b34801561031857600080fd5b50610254610327366004611c9b565b610b1b565b34801561033857600080fd5b50610254610bb4565b34801561034d57600080fd5b5061025461035c366004611f73565b610bd9565b34801561036d57600080fd5b50610234610c04565b34801561038257600080fd5b5061026b610c1c565b34801561039757600080fd5b50610234610c22565b3480156103ac57600080fd5b50610234610c31565b6102546103c3366004611e6e565b610c40565b3480156103d457600080fd5b506102546103e3366004611bf1565b610f4f565b3480156103f457600080fd5b50610254610403366004611c5b565b610f88565b34801561041457600080fd5b5061026b610fb8565b34801561042957600080fd5b50610254610438366004611bf1565b610fbe565b34801561044957600080fd5b50610254610458366004611f73565b610ff7565b34801561046957600080fd5b50610208610478366004611da5565b611022565b34801561048957600080fd5b5061026b610498366004611bf1565b611121565b3480156104a957600080fd5b506102546104b8366004611bf1565b6114e7565b3480156104c957600080fd5b5061026b611514565b3480156104de57600080fd5b506102546104ed366004611c30565b61151d565b3480156104fe57600080fd5b5061023461156a565b34801561051357600080fd5b50610234611579565b34801561052857600080fd5b50610234611588565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c9061056690879060040161205f565b60206040518083038186803b15801561057e57600080fd5b505afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b69190611d58565b90506105c0611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105f090889060040161205f565b60c06040518083038186803b15801561060857600080fd5b505afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190611de0565b905081610655576000809350935050506106f6565b600086600181111561066357fe5b14801561067257508060a00151155b15610685576000809350935050506106f6565b600061069086611121565b905060018760018111156106a057fe5b14156106c2576020909101516001600160801b03168110935091506106f69050565b60008760018111156106d057fe5b14156106f2576040909101516001600160801b03168111935091506106f69050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061074c90339060040161205f565b60206040518083038186803b15801561076457600080fd5b505afa158015610778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079c9190611d58565b6107c15760405162461bcd60e51b81526004016107b8906121cf565b60405180910390fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a08231906107f890309060040161205f565b60206040518083038186803b15801561081057600080fd5b505afa158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190611f8b565b106108d35760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f39061087f9084906004016122f8565b602060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d19190611d58565b505b6000806108e1600085610531565b91509150816108ef57600080fd5b60006108fc600554610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610933908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b031916815261097e93929190600401612073565b6000604051808303818588803b15801561099757600080fd5b505af11580156109ab573d6000803e3d6000fd5b50505050506000806109be600088611022565b91509150816109cc57600080fd5b6109d4611597565b6009546040516001600160a01b039091169063d061ce509030908a90610a009089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d93929190612102565b600060405180830381600087803b158015610a4757600080fd5b505af1158015610a5b573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b03163314610a8757600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610ad35764746a528800610ad5565b3a5b9050610ae181846115cd565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610b3257600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610b9657600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610b90573d6000803e3d6000fd5b50610bb0565b600054610bb0906001600160a01b038481169116836115f7565b5050565b6000546001600160a01b03163314610bcb57600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610bf057600080fd5b622dc6c08110610bff57600080fd5b600455565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60035481565b6007546001600160a01b031681565b6000546001600160a01b031681565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da90610c7790339060040161205f565b60206040518083038186803b158015610c8f57600080fd5b505afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc79190611d58565b610ce35760405162461bcd60e51b81526004016107b8906121cf565b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610d1a90309060040161205f565b60206040518083038186803b158015610d3257600080fd5b505afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a9190611f8b565b10610df55760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610da19084906004016122f8565b602060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df39190611d58565b505b600080610e03600185610531565b9150915081610e1157600080fd5b6000610e1e600454610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610e55908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610ea093929190600401612073565b6000604051808303818588803b158015610eb957600080fd5b505af1158015610ecd573d6000803e3d6000fd5b5050505050600080610ee0600188611022565b9150915081610eee57600080fd5b610ef6611597565b6009546040516001600160a01b039091169063d061ce509030908a90610f229089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d939291906120a8565b6001546001600160a01b03163314610f6657600080fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f9f57600080fd5b610fb36001600160a01b03841683836115f7565b505050565b60025481565b6001546001600160a01b03163314610fd557600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461100e57600080fd5b622dc6c0811061101d57600080fd5b600555565b60008061102d611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d49061105d90879060040161205f565b60c06040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190611de0565b905060006110ba85611121565b905060018660018111156110ca57fe5b14156110ea576040909101516001600160801b03168110925090506106f6565b60008660018111156110f857fe5b1415611118576020909101516001600160801b03168111925090506106f6565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061115e90869060040161205f565b60006040518083038186803b15801561117657600080fd5b505afa15801561118a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b29190810190611cad565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190611c14565b905060008060005b845181101561149e57600085828151811061125a57fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b8152600401611295919061205f565b60806040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e59190611fa3565b935093509350506112f4611afc565b8315158061130157508215155b1561138f5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df61133a896024850161205f565b60206040518083038186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190611f8b565b905290505b831561147857604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b906113cf90899060040161205f565b604080518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190611d74565b915050611429611afc565b506040805160208101909152818152611440611afc565b506040805160208101909152848152611457611afc565b61146283838761164d565b91505061147081898e6116a6565b9c5050505050505b821561148d576114898184896116a6565b9750505b505060019093019250611243915050565b50806114b257600019945050505050610ae5565b60008282670de0b6b3a764000002816114c757fe5b0490506114dc670de0b6b3a7640000826116f3565b979650505050505050565b6000546001600160a01b031633146114fe57600080fd5b6001546001600160a01b031615610fd557600080fd5b64746a52880081565b6000546001600160a01b0316331461153457600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fb3573d6000803e3d6000fd5b6006546001600160a01b031681565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156115cb5760405133904780156108fc02916000818181858888f193505050501580156115c9573d6000803e3d6000fd5b505b565b60008115806115e8575050808202828282816115e557fe5b04145b6115f157600080fd5b92915050565b610fb38363a9059cbb60e01b848460405160240161161692919061215c565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611723565b6000611657611afc565b6000611661611afc565b61166b87876117b2565b9092509050600082600381111561167e57fe5b1461168d57909250905061169e565b61169781866117b2565b9350935050505b935093915050565b60008060006116b3611afc565b6116bd878761189c565b909250905060008260038111156116d057fe5b146116e1575091506000905061169e565b6116976116ed82611904565b86611913565b60008161171461170b85670de0b6b3a76400006115cd565b60028504611939565b8161171b57fe5b049392505050565b6060611778826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119499092919063ffffffff16565b805190915015610fb357808060200190518101906117969190611d58565b610fb35760405162461bcd60e51b81526004016107b8906121f5565b60006117bc611afc565b6000806117d186600001518660000151611960565b909250905060008260038111156117e457fe5b14611803575060408051602081019091526000815290925090506106f6565b6000806118186706f05b59d3b2000084611913565b9092509050600082600381111561182b57fe5b1461184e57816040518060200160405280600081525095509550505050506106f6565b60008061186383670de0b6b3a764000061199f565b9092509050600082600381111561187657fe5b1461187d57fe5b604080516020810190915290815260009a909950975050505050505050565b60006118a6611afc565b6000806118b7866000015186611960565b909250905060008260038111156118ca57fe5b146118e9575060408051602081019091526000815290925090506106f6565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b60008083830184811061192b576000925090506106f6565b6002600092509250506106f6565b808201828110156115f157600080fd5b606061195884846000856119ca565b949350505050565b60008083611973575060009050806106f6565b8383028385828161198057fe5b0414611994576002600092509250506106f6565b6000925090506106f6565b600080826119b357506001905060006106f6565b60008385816119be57fe5b04915091509250929050565b60606119d585611a8e565b6119f15760405162461bcd60e51b81526004016107b890612198565b60006060866001600160a01b03168587604051611a0e9190612043565b60006040518083038185875af1925050503d8060008114611a4b576040519150601f19603f3d011682016040523d82523d6000602084013e611a50565b606091505b50915091508115611a645791506119589050565b805115611a745780518082602001fd5b8360405162461bcd60e51b81526004016107b89190612185565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611958575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b80356115f181612362565b80516115f181612362565b600082601f830112611b35578081fd5b611b3f604061230f565b9050808284604085011115611b5357600080fd5b60005b6002811015611b7f578135611b6a81612362565b83526020928301929190910190600101611b56565b50505092915050565b600082601f830112611b98578081fd5b813567ffffffffffffffff811115611bae578182fd5b611bc1601f8201601f191660200161230f565b9150808252836020828501011115611bd857600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215611c02578081fd5b8135611c0d81612362565b9392505050565b600060208284031215611c25578081fd5b8151611c0d81612362565b60008060408385031215611c42578081fd5b8235611c4d81612362565b946020939093013593505050565b600080600060608486031215611c6f578081fd5b8335611c7a81612362565b92506020840135611c8a81612362565b929592945050506040919091013590565b60008060408385031215611c42578182fd5b60006020808385031215611cbf578182fd5b825167ffffffffffffffff80821115611cd6578384fd5b818501915085601f830112611ce9578384fd5b815181811115611cf7578485fd5b8381029150611d0784830161230f565b8181528481019084860184860187018a1015611d21578788fd5b8795505b83861015611d4b57611d378a82611b1a565b835260019590950194918601918601611d25565b5098975050505050505050565b600060208284031215611d69578081fd5b8151611c0d81612377565b60008060408385031215611d86578182fd5b82518015158114611d95578283fd5b6020939093015192949293505050565b60008060408385031215611db7578182fd5b823560028110611dc5578283fd5b91506020830135611dd581612362565b809150509250929050565b600060c08284031215611df1578081fd5b611dfb60c061230f565b8251611e0681612362565b81526020830151611e1681612385565b60208201526040830151611e2981612385565b60408201526060830151611e3c81612385565b60608201526080830151611e4f81612385565b608082015260a0830151611e6281612377565b60a08201529392505050565b600080600060808486031215611e82578081fd5b833567ffffffffffffffff80821115611e99578283fd5b8186019150610120808389031215611eaf578384fd5b611eb88161230f565b9050611ec48884611b0f565b8152611ed38860208501611b0f565b6020820152604083013560408201526060830135606082015260808301356080820152611f038860a08501611b0f565b60a0820152611f158860c08501611b0f565b60c082015260e083013582811115611f2b578485fd5b611f3789828601611b88565b60e0830152506101009283013592810192909252509250611f5b8560208601611b25565b9150611f6a8560608601611b0f565b90509250925092565b600060208284031215611f84578081fd5b5035919050565b600060208284031215611f9c578081fd5b5051919050565b60008060008060808587031215611fb8578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b60028110156120115781516001600160a01b0316845260209384019390910190600101611fe9565b50505050565b6000815180845261202f816020860160208601612336565b601f01601f19169290920160200192915050565b60008251612055818460208701612336565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0384811682528316602082015260606040820181905260009061209f90830184612017565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b03929092168252602082015260400190565b9115158252602082015260400190565b600060208252611c0d6020830184612017565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600c908201526b139bdd08185d5d1a08189bdd60a21b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060808252612253608083018651611fd8565b602085015161226560a0840182611fd8565b50604085015160c0830152606085015160e08301526080850151610100818185015260a0870151915061012061229d81860184611fd8565b60c088015192506122b2610140860184611fd8565b60e0880151925080610160860152506122cf6101a0850183612017565b9087015161018085015291506122ea90506020830185611fe5565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561232e57600080fd5b604052919050565b60005b83811015612351578181015183820152602001612339565b838111156120115750506000910152565b6001600160a01b03811681146115c957600080fd5b80151581146115c957600080fd5b6001600160801b03811681146115c957600080fdfea264697066735822122031c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a64736f6c634300060c0033000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b
Deployed Bytecode
0x6080604052600436106101e35760003560e01c80638da5cb5b11610102578063c91d59fe11610095578063e9bb84c211610064578063e9bb84c2146104d2578063ec23ef27146104f2578063f24ccbfe14610507578063f851a4401461051c576101e3565b8063c91d59fe146102cd578063d98bb5b11461047d578063deca5f881461049d578063e3bbb4f1146104bd576101e3565b8063a56f9718116100d1578063a56f971814610408578063a7304bf71461041d578063a8c903231461043d578063bfc361721461045d576101e3565b80638da5cb5b146103a057806398a3f265146103b55780639da6136b146103c85780639db5dbe4146103e8576101e3565b806336fc603f1161017a5780634d3f199e116101495780634d3f199e14610341578063526d646114610361578063696806c01461037657806379521f021461038b576101e3565b806336fc603f146102e257806339df1878146102f75780633a1283221461030c57806341c0e1b51461032c576101e3565b80631e48907b116101b65780631e48907b1461027857806329ad0f36146102985780632a56f602146102ad57806332ac5cd2146102cd576101e3565b806306d5e37e146101e8578063109d0af81461021f578063139198941461024157806318bf60e114610256575b600080fd5b3480156101f457600080fd5b50610208610203366004611da5565b610531565b604051610216929190612175565b60405180910390f35b34801561022b57600080fd5b506102346106fd565b604051610216919061205f565b61025461024f366004611e6e565b610715565b005b34801561026257600080fd5b5061026b610a6a565b60405161021691906122f8565b34801561028457600080fd5b50610254610293366004611bf1565b610a70565b3480156102a457600080fd5b50610234610aa9565b3480156102b957600080fd5b5061026b6102c8366004611f73565b610ab8565b3480156102d957600080fd5b50610234610aea565b3480156102ee57600080fd5b5061026b610afd565b34801561030357600080fd5b50610234610b03565b34801561031857600080fd5b50610254610327366004611c9b565b610b1b565b34801561033857600080fd5b50610254610bb4565b34801561034d57600080fd5b5061025461035c366004611f73565b610bd9565b34801561036d57600080fd5b50610234610c04565b34801561038257600080fd5b5061026b610c1c565b34801561039757600080fd5b50610234610c22565b3480156103ac57600080fd5b50610234610c31565b6102546103c3366004611e6e565b610c40565b3480156103d457600080fd5b506102546103e3366004611bf1565b610f4f565b3480156103f457600080fd5b50610254610403366004611c5b565b610f88565b34801561041457600080fd5b5061026b610fb8565b34801561042957600080fd5b50610254610438366004611bf1565b610fbe565b34801561044957600080fd5b50610254610458366004611f73565b610ff7565b34801561046957600080fd5b50610208610478366004611da5565b611022565b34801561048957600080fd5b5061026b610498366004611bf1565b611121565b3480156104a957600080fd5b506102546104b8366004611bf1565b6114e7565b3480156104c957600080fd5b5061026b611514565b3480156104de57600080fd5b506102546104ed366004611c30565b61151d565b3480156104fe57600080fd5b5061023461156a565b34801561051357600080fd5b50610234611579565b34801561052857600080fd5b50610234611588565b600754604051632e4aba1f60e21b8152600091829182916001600160a01b03169063b92ae87c9061056690879060040161205f565b60206040518083038186803b15801561057e57600080fd5b505afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b69190611d58565b90506105c0611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d4906105f090889060040161205f565b60c06040518083038186803b15801561060857600080fd5b505afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190611de0565b905081610655576000809350935050506106f6565b600086600181111561066357fe5b14801561067257508060a00151155b15610685576000809350935050506106f6565b600061069086611121565b905060018760018111156106a057fe5b14156106c2576020909101516001600160801b03168110935091506106f69050565b60008760018111156106d057fe5b14156106f2576040909101516001600160801b03168111935091506106f69050565b5050505b9250929050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061074c90339060040161205f565b60206040518083038186803b15801561076457600080fd5b505afa158015610778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079c9190611d58565b6107c15760405162461bcd60e51b81526004016107b8906121cf565b60405180910390fd5b6003546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a08231906107f890309060040161205f565b60206040518083038186803b15801561081057600080fd5b505afa158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190611f8b565b106108d35760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f39061087f9084906004016122f8565b602060405180830381600087803b15801561089957600080fd5b505af11580156108ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d19190611d58565b505b6000806108e1600085610531565b91509150816108ef57600080fd5b60006108fc600554610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610933908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663f708847b60e01b1790525160e086901b6001600160e01b031916815261097e93929190600401612073565b6000604051808303818588803b15801561099757600080fd5b505af11580156109ab573d6000803e3d6000fd5b50505050506000806109be600088611022565b91509150816109cc57600080fd5b6109d4611597565b6009546040516001600160a01b039091169063d061ce509030908a90610a009089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d93929190612102565b600060405180830381600087803b158015610a4757600080fd5b505af1158015610a5b573d6000803e3d6000fd5b50505050505050505050505050565b60055481565b6001546001600160a01b03163314610a8757600080fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b031681565b60008064746a5288003a1115610ad35764746a528800610ad5565b3a5b9050610ae181846115cd565b9150505b919050565b6eb3f879cb30fe243b4dfee438691c0481565b60045481565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6000546001600160a01b03163314610b3257600080fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0383161415610b9657600080546040516001600160a01b039091169183156108fc02918491818181858888f19350505050158015610b90573d6000803e3d6000fd5b50610bb0565b600054610bb0906001600160a01b038481169116836115f7565b5050565b6000546001600160a01b03163314610bcb57600080fd5b6000546001600160a01b0316ff5b6000546001600160a01b03163314610bf057600080fd5b622dc6c08110610bff57600080fd5b600455565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60035481565b6007546001600160a01b031681565b6000546001600160a01b031681565b6040516320eb73ed60e11b815273637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da90610c7790339060040161205f565b60206040518083038186803b158015610c8f57600080fd5b505afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc79190611d58565b610ce35760405162461bcd60e51b81526004016107b8906121cf565b6002546040516370a0823160e01b815281906eb3f879cb30fe243b4dfee438691c04906370a0823190610d1a90309060040161205f565b60206040518083038186803b158015610d3257600080fd5b505afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a9190611f8b565b10610df55760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390610da19084906004016122f8565b602060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df39190611d58565b505b600080610e03600185610531565b9150915081610e1157600080fd5b6000610e1e600454610ab8565b6006546008546040519293506001600160a01b0391821692638a0e833f9234928a92911690610e55908d908d90899060240161223f565b60408051601f198184030181529181526020820180516001600160e01b031663745ce7c160e01b1790525160e086901b6001600160e01b0319168152610ea093929190600401612073565b6000604051808303818588803b158015610eb957600080fd5b505af1158015610ecd573d6000803e3d6000fd5b5050505050600080610ee0600188611022565b9150915081610eee57600080fd5b610ef6611597565b6009546040516001600160a01b039091169063d061ce509030908a90610f229089908790602001612301565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610a2d939291906120a8565b6001546001600160a01b03163314610f6657600080fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f9f57600080fd5b610fb36001600160a01b03841683836115f7565b505050565b60025481565b6001546001600160a01b03163314610fd557600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461100e57600080fd5b622dc6c0811061101d57600080fd5b600555565b60008061102d611ac7565b60075460405163335d71f560e21b81526001600160a01b039091169063cd75c7d49061105d90879060040161205f565b60c06040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190611de0565b905060006110ba85611121565b905060018660018111156110ca57fe5b14156110ea576040909101516001600160801b03168110925090506106f6565b60008660018111156110f857fe5b1415611118576020909101516001600160801b03168111925090506106f6565b50509250929050565b604051632aff3bff60e21b8152600090606090733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063abfceffc9061115e90869060040161205f565b60006040518083038186803b15801561117657600080fd5b505afa15801561118a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b29190810190611cad565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561120357600080fd5b505afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190611c14565b905060008060005b845181101561149e57600085828151811061125a57fe5b602002602001015190506000806000836001600160a01b031663c37f68e28c6040518263ffffffff1660e01b8152600401611295919061205f565b60806040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e59190611fa3565b935093509350506112f4611afc565b8315158061130157508215155b1561138f5760408051602081019182905263fc57d4df60e01b909152806001600160a01b038b1663fc57d4df61133a896024850161205f565b60206040518083038186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190611f8b565b905290505b831561147857604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b906113cf90899060040161205f565b604080518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190611d74565b915050611429611afc565b506040805160208101909152818152611440611afc565b506040805160208101909152848152611457611afc565b61146283838761164d565b91505061147081898e6116a6565b9c5050505050505b821561148d576114898184896116a6565b9750505b505060019093019250611243915050565b50806114b257600019945050505050610ae5565b60008282670de0b6b3a764000002816114c757fe5b0490506114dc670de0b6b3a7640000826116f3565b979650505050505050565b6000546001600160a01b031633146114fe57600080fd5b6001546001600160a01b031615610fd557600080fd5b64746a52880081565b6000546001600160a01b0316331461153457600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fb3573d6000803e3d6000fd5b6006546001600160a01b031681565b6009546001600160a01b031681565b6001546001600160a01b031681565b47156115cb5760405133904780156108fc02916000818181858888f193505050501580156115c9573d6000803e3d6000fd5b505b565b60008115806115e8575050808202828282816115e557fe5b04145b6115f157600080fd5b92915050565b610fb38363a9059cbb60e01b848460405160240161161692919061215c565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611723565b6000611657611afc565b6000611661611afc565b61166b87876117b2565b9092509050600082600381111561167e57fe5b1461168d57909250905061169e565b61169781866117b2565b9350935050505b935093915050565b60008060006116b3611afc565b6116bd878761189c565b909250905060008260038111156116d057fe5b146116e1575091506000905061169e565b6116976116ed82611904565b86611913565b60008161171461170b85670de0b6b3a76400006115cd565b60028504611939565b8161171b57fe5b049392505050565b6060611778826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119499092919063ffffffff16565b805190915015610fb357808060200190518101906117969190611d58565b610fb35760405162461bcd60e51b81526004016107b8906121f5565b60006117bc611afc565b6000806117d186600001518660000151611960565b909250905060008260038111156117e457fe5b14611803575060408051602081019091526000815290925090506106f6565b6000806118186706f05b59d3b2000084611913565b9092509050600082600381111561182b57fe5b1461184e57816040518060200160405280600081525095509550505050506106f6565b60008061186383670de0b6b3a764000061199f565b9092509050600082600381111561187657fe5b1461187d57fe5b604080516020810190915290815260009a909950975050505050505050565b60006118a6611afc565b6000806118b7866000015186611960565b909250905060008260038111156118ca57fe5b146118e9575060408051602081019091526000815290925090506106f6565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b60008083830184811061192b576000925090506106f6565b6002600092509250506106f6565b808201828110156115f157600080fd5b606061195884846000856119ca565b949350505050565b60008083611973575060009050806106f6565b8383028385828161198057fe5b0414611994576002600092509250506106f6565b6000925090506106f6565b600080826119b357506001905060006106f6565b60008385816119be57fe5b04915091509250929050565b60606119d585611a8e565b6119f15760405162461bcd60e51b81526004016107b890612198565b60006060866001600160a01b03168587604051611a0e9190612043565b60006040518083038185875af1925050503d8060008114611a4b576040519150601f19603f3d011682016040523d82523d6000602084013e611a50565b606091505b50915091508115611a645791506119589050565b805115611a745780518082602001fd5b8360405162461bcd60e51b81526004016107b89190612185565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611958575050151592915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060200160405280600081525090565b80356115f181612362565b80516115f181612362565b600082601f830112611b35578081fd5b611b3f604061230f565b9050808284604085011115611b5357600080fd5b60005b6002811015611b7f578135611b6a81612362565b83526020928301929190910190600101611b56565b50505092915050565b600082601f830112611b98578081fd5b813567ffffffffffffffff811115611bae578182fd5b611bc1601f8201601f191660200161230f565b9150808252836020828501011115611bd857600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215611c02578081fd5b8135611c0d81612362565b9392505050565b600060208284031215611c25578081fd5b8151611c0d81612362565b60008060408385031215611c42578081fd5b8235611c4d81612362565b946020939093013593505050565b600080600060608486031215611c6f578081fd5b8335611c7a81612362565b92506020840135611c8a81612362565b929592945050506040919091013590565b60008060408385031215611c42578182fd5b60006020808385031215611cbf578182fd5b825167ffffffffffffffff80821115611cd6578384fd5b818501915085601f830112611ce9578384fd5b815181811115611cf7578485fd5b8381029150611d0784830161230f565b8181528481019084860184860187018a1015611d21578788fd5b8795505b83861015611d4b57611d378a82611b1a565b835260019590950194918601918601611d25565b5098975050505050505050565b600060208284031215611d69578081fd5b8151611c0d81612377565b60008060408385031215611d86578182fd5b82518015158114611d95578283fd5b6020939093015192949293505050565b60008060408385031215611db7578182fd5b823560028110611dc5578283fd5b91506020830135611dd581612362565b809150509250929050565b600060c08284031215611df1578081fd5b611dfb60c061230f565b8251611e0681612362565b81526020830151611e1681612385565b60208201526040830151611e2981612385565b60408201526060830151611e3c81612385565b60608201526080830151611e4f81612385565b608082015260a0830151611e6281612377565b60a08201529392505050565b600080600060808486031215611e82578081fd5b833567ffffffffffffffff80821115611e99578283fd5b8186019150610120808389031215611eaf578384fd5b611eb88161230f565b9050611ec48884611b0f565b8152611ed38860208501611b0f565b6020820152604083013560408201526060830135606082015260808301356080820152611f038860a08501611b0f565b60a0820152611f158860c08501611b0f565b60c082015260e083013582811115611f2b578485fd5b611f3789828601611b88565b60e0830152506101009283013592810192909252509250611f5b8560208601611b25565b9150611f6a8560608601611b0f565b90509250925092565b600060208284031215611f84578081fd5b5035919050565b600060208284031215611f9c578081fd5b5051919050565b60008060008060808587031215611fb8578182fd5b505082516020840151604085015160609095015191969095509092509050565b6001600160a01b03169052565b8060005b60028110156120115781516001600160a01b0316845260209384019390910190600101611fe9565b50505050565b6000815180845261202f816020860160208601612336565b601f01601f19169290920160200192915050565b60008251612055818460208701612336565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0384811682528316602082015260606040820181905260009061209f90830184612017565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052601690820152754175746f6d61746963436f6d706f756e64526570617960501b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b0384811682528316602082015260806040820181905260169082015275105d5d1bdb585d1a58d0dbdb5c1bdd5b99109bdbdcdd60521b60a082015260c06060820181905260009061209f90830184612017565b6001600160a01b03929092168252602082015260400190565b9115158252602082015260400190565b600060208252611c0d6020830184612017565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600c908201526b139bdd08185d5d1a08189bdd60a21b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060808252612253608083018651611fd8565b602085015161226560a0840182611fd8565b50604085015160c0830152606085015160e08301526080850151610100818185015260a0870151915061012061229d81860184611fd8565b60c088015192506122b2610140860184611fd8565b60e0880151925080610160860152506122cf6101a0850183612017565b9087015161018085015291506122ea90506020830185611fe5565b826060830152949350505050565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561232e57600080fd5b604052919050565b60005b83811015612351578181015183820152602001612339565b838111156120115750506000910152565b6001600160a01b03811681146115c957600080fd5b80151581146115c957600080fd5b6001600160801b03811681146115c957600080fdfea264697066735822122031c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a64736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b
-----Decoded View---------------
Arg [0] : _compoundMonitorProxy (address): 0xB1cF8DE8e791E4Ed1Bd86c03E2fc1f14389Cb10a
Arg [1] : _subscriptions (address): 0x52015EFFD577E08f498a0CCc11905925D58D6207
Arg [2] : _compoundFlashLoanTaker (address): 0x533c8844bA1922b88d892aCA090df0cC0c292F1b
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b1cf8de8e791e4ed1bd86c03e2fc1f14389cb10a
Arg [1] : 00000000000000000000000052015effd577e08f498a0ccc11905925d58d6207
Arg [2] : 000000000000000000000000533c8844ba1922b88d892aca090df0cc0c292f1b
Deployed Bytecode Sourcemap
60500:8974:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65890:749;;;;;;;;;;-1:-1:-1;65890:749:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;42601:108;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;64089:1137::-;;;;;;:::i;:::-;;:::i;:::-;;60850:36;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;8640:122::-;;;;;;;;;;-1:-1:-1;8640:122:0;;;;;:::i;:::-;;:::i;61300:44::-;;;;;;;;;;;;;:::i;67634:203::-;;;;;;;;;;-1:-1:-1;67634:203:0;;;;;:::i;:::-;;:::i;60895:96::-;;;;;;;;;;;;;:::i;60807:36::-;;;;;;;;;;;;;:::i;60998:85::-;;;;;;;;;;;;;:::i;8935:285::-;;;;;;;;;;-1:-1:-1;8935:285:0;;;;;:::i;:::-;;:::i;8808:80::-;;;;;;;;;;;;;:::i;68648:144::-;;;;;;;;;;-1:-1:-1;68648:144:0;;;;;:::i;:::-;;:::i;61090:89::-;;;;;;;;;;;;;:::i;60696:32::-;;;;;;;;;;;;;:::i;61243:50::-;;;;;;;;;;;;;:::i;7598:20::-;;;;;;;;;;;;;:::i;62556:1134::-;;;;;;:::i;:::-;;:::i;68004:182::-;;;;;;;;;;-1:-1:-1;68004:182:0;;;;;:::i;:::-;;:::i;69027:156::-;;;;;;;;;;-1:-1:-1;69027:156:0;;;;;:::i;:::-;;:::i;60657:32::-;;;;;;;;;;;;;:::i;8419:122::-;;;;;;;;;;-1:-1:-1;8419:122:0;;;;;:::i;:::-;;:::i;68345:144::-;;;;;;;;;;-1:-1:-1;68345:144:0;;;;;:::i;:::-;;:::i;66936:490::-;;;;;;;;;;-1:-1:-1;66936:490:0;;;;;:::i;:::-;;:::i;42828:1709::-;;;;;;;;;;-1:-1:-1;42828:1709:0;;;;;:::i;:::-;;:::i;8136:161::-;;;;;;;;;;-1:-1:-1;8136:161:0;;;;;:::i;:::-;;:::i;60737:49::-;;;;;;;;;;;;;:::i;69358:113::-;;;;;;;;;;-1:-1:-1;69358:113:0;;;;;:::i;:::-;;:::i;61188:48::-;;;;;;;;;;;;;:::i;61353:65::-;;;;;;;;;;;;;:::i;7625:20::-;;;;;;;;;;;;;:::i;65890:749::-;65999:21;;:41;;-1:-1:-1;;;65999:41:0;;65958:4;;;;;;-1:-1:-1;;;;;65999:21:0;;:34;;:41;;66034:5;;65999:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65981:59;;66051:50;;:::i;:::-;66104:21;;:38;;-1:-1:-1;;;66104:38:0;;-1:-1:-1;;;;;66104:21:0;;;;:31;;:38;;66136:5;;66104:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66051:91;;66199:10;66194:34;;66219:5;66226:1;66211:17;;;;;;;;66194:34;66301:12;66290:7;:23;;;;;;;;;:47;;;;;66318:6;:19;;;66317:20;66290:47;66286:70;;;66347:5;66354:1;66339:17;;;;;;;;66286:70;66369:14;66386:21;66401:5;66386:14;:21::i;:::-;66369:38;-1:-1:-1;66435:12:0;66424:7;:23;;;;;;;;;66420:212;;;66484:15;;;;;-1:-1:-1;;;;;66472:27:0;;;;-1:-1:-1;66472:9:0;-1:-1:-1;66464:47:0;;-1:-1:-1;66464:47:0;66420:212;66544:12;66533:7;:23;;;;;;;;;66529:103;;;66593:15;;;;;-1:-1:-1;;;;;66581:27:0;;;;-1:-1:-1;66581:9:0;-1:-1:-1;66573:47:0;;-1:-1:-1;66573:47:0;66529:103;65890:749;;;;;;;;;:::o;42601:108::-;42666:42;42601:108;:::o;64089:1137::-;61470:53;;-1:-1:-1;;;61470:53:0;;61137:42;;61470:41;;:53;;61512:10;;61470:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;61462:78;;;;-1:-1:-1;;;61462:78:0;;;;;;;:::i;:::-;;;;;;;;;64302:15:::1;::::0;10454:33:::1;::::0;-1:-1:-1;;;10454:33:0;;64302:15;;10356:42:::1;::::0;10454:18:::1;::::0;:33:::1;::::0;10481:4:::1;::::0;10454:33:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;10450:99;;10515:22;::::0;-1:-1:-1;;;10515:22:0;;10356:42:::1;::::0;10515:13:::1;::::0;:22:::1;::::0;10529:7;;10515:22:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10450:99;64333:14:::2;64349:16:::0;64369:28:::2;64377:12;64391:5;64369:7;:28::i;:::-;64332:65;;;;64416:9;64408:18;;;::::0;::::2;;64470:15;64488:27;64500:14;;64488:11;:27::i;:::-;64528:20;::::0;64613:29:::2;::::0;64657:246:::2;::::0;64470:45;;-1:-1:-1;;;;;;64528:20:0;;::::2;::::0;:32:::2;::::0;64568:9:::2;::::0;64593:5;;64613:29;::::2;::::0;64657:246:::2;::::0;64825:7;;64851:11;;64470:45;;64657:246:::2;;;:::i;:::-;;::::0;;-1:-1:-1;;64657:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;64657:246:0::2;-1:-1:-1::0;;;64657:246:0::2;::::0;;64528:386;::::2;::::0;;;-1:-1:-1;;;;;;64528:386:0;;;::::2;::::0;;;64657:246;64528:386:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;64930:16;64948:15:::0;64967:35:::2;64982:12;64996:5;64967:14;:35::i;:::-;64929:73;;;;65021:11;65013:20;;;::::0;::::2;;65099:11;:9;:11::i;:::-;65123:6;::::0;65182:35:::2;::::0;-1:-1:-1;;;;;65123:6:0;;::::2;::::0;:10:::2;::::0;65142:4:::2;::::0;65149:5;;65182:35:::2;::::0;65193:11;;65206:10;;65182:35:::2;;;:::i;:::-;;;;;;;;;;;;;65123:95;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;10561:1;;;;;61551::::1;64089:1137:::0;;;:::o;60850:36::-;;;;:::o;8640:122::-;8721:5;;-1:-1:-1;;;;;8721:5:0;8707:10;:19;8699:28;;;;;;8740:5;:14;;-1:-1:-1;;;;;;8740:14:0;-1:-1:-1;;;;;8740:14:0;;;;;;;;;;8640:122::o;61300:44::-;;;-1:-1:-1;;;;;61300:44:0;;:::o;67634:203::-;67693:4;67710:13;60774:12;67726:11;:28;;:58;;60774:12;67726:58;;;67757:11;67726:58;67710:74;;67804:25;67808:8;67818:10;67804:3;:25::i;:::-;67797:32;;;67634:203;;;;:::o;60895:96::-;60949:42;60895:96;:::o;60807:36::-;;;;:::o;60998:85::-;61041:42;60998:85;:::o;8935:285::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;9035:42:::1;-1:-1:-1::0;;;;;9025:52:0;::::1;;9021:192;;;9102:5;::::0;;9094:32:::1;::::0;-1:-1:-1;;;;;9102:5:0;;::::1;::::0;9094:32;::::1;;;::::0;9118:7;;9094:32;9102:5;9094:32;9118:7;9102:5;9094:32;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;9021:192;;;9186:5;::::0;9159:42:::1;::::0;-1:-1:-1;;;;;9159:26:0;;::::1;::::0;9186:5:::1;9193:7:::0;9159:26:::1;:42::i;:::-;8935:285:::0;;:::o;8808:80::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;8873:5:::1;::::0;-1:-1:-1;;;;;8873:5:0::1;8852:28;68648:144:::0;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;68738:7:::1;68727:8;:18;68719:27;;;::::0;::::1;;68759:14;:25:::0;68648:144::o;61090:89::-;61137:42;61090:89;:::o;60696:32::-;;;;:::o;61243:50::-;;;-1:-1:-1;;;;;61243:50:0;;:::o;7598:20::-;;;-1:-1:-1;;;;;7598:20:0;;:::o;62556:1134::-;61470:53;;-1:-1:-1;;;61470:53:0;;61137:42;;61470:41;;:53;;61512:10;;61470:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;61462:78;;;;-1:-1:-1;;;61462:78:0;;;;;;;:::i;:::-;62769:15:::1;::::0;10454:33:::1;::::0;-1:-1:-1;;;10454:33:0;;62769:15;;10356:42:::1;::::0;10454:18:::1;::::0;:33:::1;::::0;10481:4:::1;::::0;10454:33:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;10450:99;;10515:22;::::0;-1:-1:-1;;;10515:22:0;;10356:42:::1;::::0;10515:13:::1;::::0;:22:::1;::::0;10529:7;;10515:22:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10450:99;62800:14:::2;62816:16:::0;62836:28:::2;62844:12;62858:5;62836:7;:28::i;:::-;62799:65;;;;62883:9;62875:18;;;::::0;::::2;;62937:15;62955:27;62967:14;;62955:11;:27::i;:::-;62995:20;::::0;63080:29:::2;::::0;63124:246:::2;::::0;62937:45;;-1:-1:-1;;;;;;62995:20:0;;::::2;::::0;:32:::2;::::0;63035:9:::2;::::0;63060:5;;63080:29;::::2;::::0;63124:246:::2;::::0;63292:7;;63318:11;;62937:45;;63124:246:::2;;;:::i;:::-;;::::0;;-1:-1:-1;;63124:246:0;;::::2;::::0;;;;;;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;63124:246:0::2;-1:-1:-1::0;;;63124:246:0::2;::::0;;62995:386;::::2;::::0;;;-1:-1:-1;;;;;;62995:386:0;;;::::2;::::0;;;63124:246;62995:386:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;63395:16;63413:15:::0;63432:35:::2;63447:12;63461:5;63432:14;:35::i;:::-;63394:73;;;;63486:11;63478:20;;;::::0;::::2;;63563:11;:9;:11::i;:::-;63587:6;::::0;63646:35:::2;::::0;-1:-1:-1;;;;;63587:6:0;;::::2;::::0;:10:::2;::::0;63606:4:::2;::::0;63613:5;;63646:35:::2;::::0;63657:11;;63670:10;;63646:35:::2;;;:::i;:::-;;;;;;;;;;;;;63587:95;;;;;;;;;;;;;;;;;:::i;68004:182::-:0;7782:5;;-1:-1:-1;;;;;7782:5:0;7791:10;7782:19;7774:28;;;;;;68113:29:::1;:65:::0;;-1:-1:-1;;;;;;68113:65:0::1;-1:-1:-1::0;;;;;68113:65:0;;;::::1;::::0;;;::::1;::::0;;68004:182::o;69027:156::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;69128:47:::1;-1:-1:-1::0;;;;;69128:33:0;::::1;69162:3:::0;69167:7;69128:33:::1;:47::i;:::-;69027:156:::0;;;:::o;60657:32::-;;;;:::o;8419:122::-;8500:5;;-1:-1:-1;;;;;8500:5:0;8486:10;:19;8478:28;;;;;;8519:5;:14;;-1:-1:-1;;;;;;8519:14:0;-1:-1:-1;;;;;8519:14:0;;;;;;;;;;8419:122::o;68345:144::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;68435:7:::1;68424:8;:18;68416:27;;;::::0;::::1;;68456:14;:25:::0;68345:144::o;66936:490::-;67011:4;67017;67034:50;;:::i;:::-;67105:21;;:38;;-1:-1:-1;;;67105:38:0;;-1:-1:-1;;;;;67105:21:0;;;;:31;;:38;;67137:5;;67105:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67097:46;;67156:14;67173:21;67188:5;67173:14;:21::i;:::-;67156:38;-1:-1:-1;67222:12:0;67211:7;:23;;;;;;;;;67207:212;;;67271:15;;;;;-1:-1:-1;;;;;67259:27:0;;;;-1:-1:-1;67259:9:0;-1:-1:-1;67251:47:0;;67207:212;67331:12;67320:7;:23;;;;;;;;;67316:103;;;67380:15;;;;;-1:-1:-1;;;;;67368:27:0;;;;-1:-1:-1;67368:9:0;-1:-1:-1;67360:47:0;;67316:103;66936:490;;;;;;;:::o;42828:1709::-;42976:23;;-1:-1:-1;;;42976:23:0;;42888:4;;42950:23;;42666:42;;42976:16;;:23;;42993:5;;42976:23;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;42976:23:0;;;;;;;;;;;;:::i;:::-;42950:49;;43010:18;42666:42;-1:-1:-1;;;;;43031:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43010:34;;43059:18;43092:14;43128:6;43123:1242;43144:6;:13;43140:1;:17;43123:1242;;;43179:13;43195:6;43202:1;43195:9;;;;;;;;;;;;;;43179:25;;43224:18;43244;43264:25;43350:5;-1:-1:-1;;;;;43334:41:0;;43376:5;43334:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43221:161;;;;;;;43399:22;;:::i;:::-;43442:18;;;;:40;;-1:-1:-1;43464:18:0;;;43442:40;43438:173;;;43517:78;;;;;;;;;;-1:-1:-1;;;43532:61:0;;;43517:78;-1:-1:-1;;;;;43532:54:0;;;:61;43587:5;43532:61;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43517:78;;43503:92;-1:-1:-1;43438:173:0;43672:18;;43668:497;;43743:28;;-1:-1:-1;;;43743:28:0;;43716:23;;42666:42;;43743:12;;:28;;43764:5;;43743:28;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43713:58;;;43792:27;;:::i;:::-;-1:-1:-1;43822:35:0;;;;;;;;;;;;43876:23;;:::i;:::-;-1:-1:-1;43902:37:0;;;;;;;;;;;;43963:22;;:::i;:::-;43989:52;43997:16;44015:12;44029:11;43989:7;:52::i;:::-;43960:81;;;44082:67;44107:11;44120:13;44135;44082:24;:67::i;:::-;44062:87;-1:-1:-1;;;;;;43668:497:0;44220:18;;44216:138;;44275:63;44300:11;44313:13;44328:9;44275:24;:63::i;:::-;44259:79;-1:-1:-1;;44216:138:0;-1:-1:-1;;43159:3:0;;;;;-1:-1:-1;43123:1242:0;;-1:-1:-1;;43123:1242:0;;-1:-1:-1;44381:14:0;44377:35;;-1:-1:-1;;44397:15:0;;;;;;;;44377:35;44425:20;44471:13;44449:9;44461:6;44449:18;44448:36;;;;;;44425:59;;44502:27;44507:4;44513:15;44502:4;:27::i;:::-;44495:34;42828:1709;-1:-1:-1;;;;;;;42828:1709:0:o;8136:161::-;8217:5;;-1:-1:-1;;;;;8217:5:0;8203:10;:19;8195:28;;;;;;8242:5;;-1:-1:-1;;;;;8242:5:0;:19;8234:28;;;;;60737:49;60774:12;60737:49;:::o;69358:113::-;7694:5;;-1:-1:-1;;;;;7694:5:0;7703:10;7694:19;7686:28;;;;;;69442:21:::1;::::0;-1:-1:-1;;;;;69442:12:0;::::1;::::0;:21;::::1;;;::::0;69455:7;;69442:21:::1;::::0;;;69455:7;69442:12;:21;::::1;;;;;;;;;;;;;::::0;::::1;;;;61188:48:::0;;;-1:-1:-1;;;;;61188:48:0;;:::o;61353:65::-;;;-1:-1:-1;;;;;61353:65:0;;:::o;7625:20::-;;;-1:-1:-1;;;;;7625:20:0;;:::o;65307:184::-;65388:21;:25;65384:100;;65430:42;;:10;;65450:21;65430:42;;;;;;;;;65450:21;65430:10;:42;;;;;;;;;;;;;;;;;;;;;65384:100;65307:184::o;22452:127::-;22510:9;22540:6;;;:30;;-1:-1:-1;;22555:5:0;;;22569:1;22564;22555:5;22564:1;22550:15;;;;;:20;22540:30;22532:39;;;;;;22452:127;;;;:::o;5643:176::-;5725:86;5745:5;5775:23;;;5800:2;5804:5;5752:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;5752:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;5752:58:0;-1:-1:-1;;;;;;5752:58:0;;;;;;;;;;5725:19;:86::i;36840:284::-;36922:9;36933:10;;:::i;:::-;36957:13;36972;;:::i;:::-;36989:12;36996:1;36999;36989:6;:12::i;:::-;36956:45;;-1:-1:-1;36956:45:0;-1:-1:-1;37023:18:0;37016:3;:25;;;;;;;;;37012:74;;37066:3;;-1:-1:-1;37071:2:0;-1:-1:-1;37058:16:0;;37012:74;37103:13;37110:2;37114:1;37103:6;:13::i;:::-;37096:20;;;;;;36840:284;;;;;;;:::o;33312:328::-;33409:9;33420:4;33438:13;33453:18;;:::i;:::-;33475:20;33485:1;33488:6;33475:9;:20::i;:::-;33437:58;;-1:-1:-1;33437:58:0;-1:-1:-1;33517:18:0;33510:3;:25;;;;;;;;;33506:73;;-1:-1:-1;33560:3:0;-1:-1:-1;33565:1:0;;-1:-1:-1;33552:15:0;;33506:73;33598:34;33606:17;33615:7;33606:8;:17::i;:::-;33625:6;33598:7;:34::i;23493:120::-;23552:9;23604:1;23578:23;23582:11;23586:1;23182:6;23582:3;:11::i;:::-;23599:1;23595;:5;23578:3;:23::i;:::-;:27;;;;;;;23493:120;-1:-1:-1;;;23493:120:0:o;7112:419::-;7194:23;7220:69;7248:4;7220:69;;;;;;;;;;;;;;;;;7228:5;-1:-1:-1;;;;;7220:27:0;;;:69;;;;;:::i;:::-;7304:17;;7194:95;;-1:-1:-1;7304:21:0;7300:224;;7446:10;7435:30;;;;;;;;;;;;:::i;:::-;7427:85;;;;-1:-1:-1;;;7427:85:0;;;;;;;:::i;35336:1136::-;35403:9;35414:10;;:::i;:::-;35440:14;35456:24;35484:31;35492:1;:10;;;35504:1;:10;;;35484:7;:31::i;:::-;35439:76;;-1:-1:-1;35439:76:0;-1:-1:-1;35538:18:0;35530:4;:26;;;;;;;;;35526:92;;-1:-1:-1;35587:18:0;;;;;;;;;-1:-1:-1;35587:18:0;;35581:4;;-1:-1:-1;35587:18:0;-1:-1:-1;35573:33:0;;35526:92;35935:14;;35992:42;30779:10;36014:19;35992:7;:42::i;:::-;35934:100;;-1:-1:-1;35934:100:0;-1:-1:-1;36057:18:0;36049:4;:26;;;;;;;;;36045:92;;36100:4;36106:18;;;;;;;;36121:1;36106:18;;;36092:33;;;;;;;;;;36045:92;36150:14;36166:12;36182:51;36190:32;30700:4;36182:7;:51::i;:::-;36149:84;;-1:-1:-1;36149:84:0;-1:-1:-1;36379:18:0;36371:4;:26;;;;;;;;;36364:34;;;;36439:24;;;;;;;;;;;;-1:-1:-1;;36439:24:0;;-1:-1:-1;35336:1136:0;-1:-1:-1;;;;;;;;35336:1136:0:o;32388:353::-;32457:9;32468:10;;:::i;:::-;32492:14;32508:19;32531:27;32539:1;:10;;;32551:6;32531:7;:27::i;:::-;32491:67;;-1:-1:-1;32491:67:0;-1:-1:-1;32581:18:0;32573:4;:26;;;;;;;;;32569:92;;-1:-1:-1;32630:18:0;;;;;;;;;-1:-1:-1;32630:18:0;;32624:4;;-1:-1:-1;32630:18:0;-1:-1:-1;32616:33:0;;32569:92;32701:31;;;;;;;;;;;;-1:-1:-1;;32701:31:0;;-1:-1:-1;32388:353:0;-1:-1:-1;;;;32388:353:0:o;37667:213::-;37849:12;30700:4;37849:23;;;37667:213::o;30029:258::-;30085:9;;30122:5;;;30144:6;;;30140:140;;30175:18;;-1:-1:-1;30195:1:0;-1:-1:-1;30167:30:0;;30140:140;30238:26;30266:1;30230:38;;;;;;;22210:113;22303:5;;;22298:16;;;;22290:25;;;;;2034:196;2137:12;2169:53;2192:6;2200:4;2206:1;2209:12;2169:22;:53::i;:::-;2162:60;2034:196;-1:-1:-1;;;;2034:196:0:o;28920:343::-;28976:9;;29008:6;29004:69;;-1:-1:-1;29039:18:0;;-1:-1:-1;29039:18:0;29031:30;;29004:69;29094:5;;;29098:1;29094;:5;:1;29116:5;;;;;:10;29112:144;;29151:26;29179:1;29143:38;;;;;;;29112:144;29222:18;;-1:-1:-1;29242:1:0;-1:-1:-1;29214:30:0;;29358:215;29414:9;;29446:6;29442:77;;-1:-1:-1;29477:26:0;;-1:-1:-1;29505:1:0;29469:38;;29442:77;29539:18;29563:1;29559;:5;;;;;;29531:34;;;;29358:215;;;;;:::o;2796:979::-;2926:12;2959:18;2970:6;2959:10;:18::i;:::-;2951:60;;;;-1:-1:-1;;;2951:60:0;;;;;;;:::i;:::-;3085:12;3099:23;3126:6;-1:-1:-1;;;;;3126:11:0;3146:8;3157:4;3126:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3084:78;;;;3177:7;3173:595;;;3208:10;-1:-1:-1;3201:17:0;;-1:-1:-1;3201:17:0;3173:595;3322:17;;:21;3318:439;;3585:10;3579:17;3646:15;3633:10;3629:2;3625:19;3618:44;3533:148;3728:12;3721:20;;-1:-1:-1;;;3721:20:0;;;;;;;;:::i;821:619::-;881:4;1349:20;;1192:66;1389:23;;;;;;:42;;-1:-1:-1;;1416:15:0;;;1381:51;-1:-1:-1;;821:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;:::i;142:134::-;220:13;;238:33;220:13;238:33;:::i;455:616::-;;570:3;563:4;555:6;551:17;547:27;537:2;;-1:-1;;578:12;537:2;631:78;27191:17;631:78;:::i;:::-;622:87;;715:16;774:17;832:3;27191:17;807:3;803:27;800:36;797:2;;;849:1;;839:12;797:2;874:1;859:206;612:4;881:1;878:13;859:206;;;85:6;72:20;97:33;124:5;97:33;:::i;:::-;952:50;;27203:4;1016:14;;;;1044;;;;;906:1;899:9;859:206;;;863:14;;;530:541;;;;:::o;1963:440::-;;2064:3;2057:4;2049:6;2045:17;2041:27;2031:2;;-1:-1;;2072:12;2031:2;2119:6;2106:20;27684:18;27676:6;27673:30;27670:2;;;-1:-1;;27706:12;27670:2;2141:64;27779:9;27760:17;;-1:-1;;27756:33;27847:4;27837:15;2141:64;:::i;:::-;2132:73;;2225:6;2218:5;2211:21;2329:3;27847:4;2320:6;2253;2311:16;;2308:25;2305:2;;;2346:1;;2336:12;2305:2;31974:6;27847:4;2253:6;2249:17;27847:4;2287:5;2283:16;31951:30;32030:1;32012:16;;;27847:4;32012:16;32005:27;2287:5;2024:379;-1:-1;;2024:379::o;5891:241::-;;5995:2;5983:9;5974:7;5970:23;5966:32;5963:2;;;-1:-1;;6001:12;5963:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6053:63;5957:175;-1:-1;;;5957:175::o;6139:263::-;;6254:2;6242:9;6233:7;6229:23;6225:32;6222:2;;;-1:-1;;6260:12;6222:2;226:6;220:13;238:33;265:5;238:33;:::i;6409:382::-;;;6538:2;6526:9;6517:7;6513:23;6509:32;6506:2;;;-1:-1;;6544:12;6506:2;371:6;358:20;383:41;418:5;383:41;:::i;:::-;6596:71;6704:2;6743:22;;;;5680:20;;-1:-1;;;6500:291::o;6798:491::-;;;;6936:2;6924:9;6915:7;6911:23;6907:32;6904:2;;;-1:-1;;6942:12;6904:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6994:63;-1:-1;7094:2;7133:22;;72:20;97:33;72:20;97:33;:::i;:::-;6898:391;;7102:63;;-1:-1;;;7202:2;7241:22;;;;5680:20;;6898:391::o;7296:366::-;;;7417:2;7405:9;7396:7;7392:23;7388:32;7385:2;;;-1:-1;;7423:12;7669:392;;7809:2;;7797:9;7788:7;7784:23;7780:32;7777:2;;;-1:-1;;7815:12;7777:2;7866:17;7860:24;7904:18;;7896:6;7893:30;7890:2;;;-1:-1;;7926:12;7890:2;8028:6;8017:9;8013:22;;;1225:3;1218:4;1210:6;1206:17;1202:27;1192:2;;-1:-1;;1233:12;1192:2;1273:6;1267:13;7904:18;27381:6;27378:30;27375:2;;;-1:-1;;27411:12;27375:2;7809;27448:6;27444:17;;;1295:80;7809:2;27444:17;27509:15;1295:80;:::i;:::-;1403:21;;;1460:14;;;;1435:17;;;1540:27;;;;;1537:36;-1:-1;1534:2;;;-1:-1;;1576:12;1534:2;-1:-1;1602:10;;1596:217;1621:6;1618:1;1615:13;1596:217;;;1701:48;1745:3;1733:10;1701:48;:::i;:::-;1689:61;;1643:1;1636:9;;;;;1764:14;;;;1792;;1596:217;;;-1:-1;7946:99;7771:290;-1:-1;;;;;;;;7771:290::o;8068:257::-;;8180:2;8168:9;8159:7;8155:23;8151:32;8148:2;;;-1:-1;;8186:12;8148:2;1908:6;1902:13;1920:30;1944:5;1920:30;:::i;8332:393::-;;;8461:2;8449:9;8440:7;8436:23;8432:32;8429:2;;;-1:-1;;8467:12;8429:2;1908:6;1902:13;32773:5;29534:13;29527:21;32751:5;32748:32;32738:2;;-1:-1;;32784:12;32738:2;8627;8677:22;;;;5828:13;8519:71;;5828:13;;-1:-1;;;8423:302::o;8732:388::-;;;8864:2;8852:9;8843:7;8839:23;8835:32;8832:2;;;-1:-1;;8870:12;8832:2;2502:6;2489:20;32890:1;32883:5;32880:12;32870:2;;-1:-1;;32896:12;32870:2;8922:74;-1:-1;9033:2;9072:22;;72:20;97:33;72:20;97:33;:::i;:::-;9041:63;;;;8826:294;;;;;:::o;9127:328::-;;9274:3;9262:9;9253:7;9249:23;9245:33;9242:2;;;-1:-1;;9281:12;9242:2;2788:20;9274:3;2788:20;:::i;:::-;226:6;220:13;238:33;265:5;238:33;:::i;:::-;2865:86;;3016:2;3081:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3016:2;3031:16;;3024:86;3175:2;3240:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3175:2;3190:16;;3183:86;3343:2;3408:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3343:2;3358:16;;3351:86;3511:3;3577:22;;5550:13;5568:33;5550:13;5568:33;:::i;:::-;3511:3;3527:16;;3520:86;3675:3;3738:22;;1902:13;1920:30;1902:13;1920:30;:::i;:::-;3675:3;3691:16;;3684:83;3695:5;9236:219;-1:-1;;;9236:219::o;9462:684::-;;;;9653:3;9641:9;9632:7;9628:23;9624:33;9621:2;;;-1:-1;;9660:12;9621:2;9718:17;9705:31;9756:18;;9748:6;9745:30;9742:2;;;-1:-1;;9778:12;9742:2;9874:6;9863:9;9859:22;;;3958:6;;3946:9;3941:3;3937:19;3933:32;3930:2;;;-1:-1;;3968:12;3930:2;3996:22;3958:6;3996:22;:::i;:::-;3987:31;;4103:49;4148:3;4124:22;4103:49;:::i;:::-;4085:16;4078:75;4251:49;4296:3;4218:2;4276:9;4272:22;4251:49;:::i;:::-;4218:2;4237:5;4233:16;4226:75;4367:2;4425:9;4421:22;5680:20;4367:2;4386:5;4382:16;4375:75;4517:2;4575:9;4571:22;5680:20;4517:2;4536:5;4532:16;4525:75;9653:3;4724:9;4720:22;5680:20;9653:3;4685:5;4681:16;4674:75;4847:49;4892:3;4813;4872:9;4868:22;4847:49;:::i;:::-;4813:3;4833:5;4829:16;4822:75;5000:49;5045:3;4966;5025:9;5021:22;5000:49;:::i;:::-;4966:3;4986:5;4982:16;4975:75;5143:3;5132:9;5128:19;5115:33;9756:18;5160:6;5157:30;5154:2;;;-1:-1;;5190:12;5154:2;5235:58;5289:3;5280:6;5269:9;5265:22;5235:58;:::i;:::-;5143:3;5217:16;;5210:84;-1:-1;5358:3;5415:22;;;5680:20;5374:18;;;5367:77;;;;-1:-1;5221:5;-1:-1;9946:76;10014:7;4218:2;9990:22;;9946:76;:::i;:::-;9936:86;;10077:53;10122:7;4517:2;10102:9;10098:22;10077:53;:::i;:::-;10067:63;;9615:531;;;;;:::o;10153:241::-;;10257:2;10245:9;10236:7;10232:23;10228:32;10225:2;;;-1:-1;;10263:12;10225:2;-1:-1;5680:20;;10219:175;-1:-1;10219:175::o;10401:263::-;;10516:2;10504:9;10495:7;10491:23;10487:32;10484:2;;;-1:-1;;10522:12;10484:2;-1:-1;5828:13;;10478:186;-1:-1;10478:186::o;10671:672::-;;;;;10837:3;10825:9;10816:7;10812:23;10808:33;10805:2;;;-1:-1;;10844:12;10805:2;-1:-1;;5828:13;;11007:2;11057:22;;5828:13;11126:2;11176:22;;5828:13;11245:2;11295:22;;;5828:13;;;;;-1:-1;5828:13;;-1:-1;10799:544;-1:-1;10799:544::o;11681:103::-;-1:-1;;;;;29742:54;11742:37;;11736:48::o;11944:660::-;12307:21;12349:1;12334:258;28067:4;12356:1;12353:13;12334:258;;;12420:13;;-1:-1;;;;;29742:54;11742:37;;11513:4;11504:14;;;;28432;;;;27684:18;12374:9;12334:258;;;12338:14;;12056:548;;:::o;12723:323::-;;12855:5;28175:12;28712:6;28707:3;28700:19;12938:52;12983:6;28749:4;28744:3;28740:14;28749:4;12964:5;12960:16;12938:52;:::i;:::-;27779:9;32391:14;-1:-1;;32387:28;13002:39;;;;28749:4;13002:39;;12803:243;-1:-1;;12803:243::o;18793:271::-;;13563:5;28175:12;13674:52;13719:6;13714:3;13707:4;13700:5;13696:16;13674:52;:::i;:::-;13738:16;;;;;18927:137;-1:-1;;18927:137::o;19071:222::-;-1:-1;;;;;29742:54;;;;11742:37;;19198:2;19183:18;;19169:124::o;19545:528::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;19910:2;19895:18;;11742:37;19746:2;19947;19932:18;;19925:48;;;19545:528;;19987:76;;19731:18;;20049:6;19987:76;:::i;:::-;19979:84;19717:356;-1:-1;;;;;19717:356::o;20080:834::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;20547:2;20532:18;;11742:37;20382:3;20584:2;20569:18;;20562:48;;;15284:2;20367:19;;;28700;-1:-1;;;29753:42;28740:14;;15300:45;15364:12;20788:2;20773:18;;20766:48;;;20080:834;;20828:76;;15364:12;;20890:6;20828:76;:::i;20921:834::-;-1:-1;;;;;29742:54;;;11742:37;;29742:54;;21388:2;21373:18;;11742:37;21223:3;21425:2;21410:18;;21403:48;;;15615:2;21208:19;;;28700;-1:-1;;;29753:42;28740:14;;15631:45;15695:12;21629:2;21614:18;;21607:48;;;20921:834;;21669:76;;15695:12;;21731:6;21669:76;:::i;21762:333::-;-1:-1;;;;;29742:54;;;;11742:37;;22081:2;22066:18;;18624:37;21917:2;21902:18;;21888:207::o;22102:321::-;29534:13;;29527:21;12677:34;;22409:2;22394:18;;18624:37;22251:2;22236:18;;22222:201::o;23849:310::-;;23996:2;24017:17;24010:47;24071:78;23996:2;23985:9;23981:18;24135:6;24071:78;:::i;24166:416::-;24366:2;24380:47;;;15946:2;24351:18;;;28700:19;15982:31;28740:14;;;15962:52;16033:12;;;24337:245::o;24589:416::-;24789:2;24803:47;;;16284:2;24774:18;;;28700:19;-1:-1;;;28740:14;;;16300:35;16354:12;;;24760:245::o;25012:416::-;25212:2;25226:47;;;16605:2;25197:18;;;28700:19;16641:34;28740:14;;;16621:55;-1:-1;;;16696:12;;;16689:34;16742:12;;;25183:245::o;25435:705::-;;25724:3;25746:17;25739:47;17114:63;25724:3;25713:9;25709:19;17091:16;17085:23;17114:63;:::i;:::-;17260:4;17253:5;17249:16;17243:23;17272:63;17320:14;25713:9;17320:14;17306:12;17272:63;:::i;:::-;;17419:4;17412:5;17408:16;17402:23;17479:14;25713:9;17479:14;18624:37;17579:4;17572:5;17568:16;17562:23;17639:14;25713:9;17639:14;18624:37;25724:3;17730:5;17726:16;17720:23;17797:14;17720:23;17797:14;25713:9;17797:14;18624:37;17320:14;17887:5;17883:16;17877:23;17857:43;;17014:6;17906:63;17014:6;25713:9;17954:14;17940:12;17906:63;:::i;:::-;17479:14;18049:5;18045:16;18039:23;18019:43;;18068:63;18116:14;25713:9;18116:14;18102:12;18068:63;:::i;:::-;17639:14;18207:5;18203:16;18197:23;18177:43;;17014:6;18240:14;25713:9;18240:14;18233:38;;18286:71;17005:16;25713:9;17005:16;18338:12;18286:71;:::i;:::-;18434:18;;;18428:25;18507:16;;;18624:37;18278:79;-1:-1;25929:118;;-1:-1;17260:4;26028:18;;26019:6;25929:118;:::i;:::-;18654:5;17579:4;26115:9;26111:18;18624:37;25695:445;;;;;;:::o;26147:222::-;18624:37;;;26274:2;26259:18;;26245:124::o;26376:333::-;18624:37;;;26695:2;26680:18;;18624:37;26531:2;26516:18;;26502:207::o;26716:256::-;26778:2;26772:9;26804:17;;;26879:18;26864:34;;26900:22;;;26861:62;26858:2;;;26936:1;;26926:12;26858:2;26778;26945:22;26756:216;;-1:-1;26756:216::o;32047:268::-;32112:1;32119:101;32133:6;32130:1;32127:13;32119:101;;;32200:11;;;32194:18;32181:11;;;32174:39;32155:2;32148:10;32119:101;;;32235:6;32232:1;32229:13;32226:2;;;-1:-1;;32112:1;32282:16;;32275:27;32096:219::o;32428:117::-;-1:-1;;;;;29742:54;;32487:35;;32477:2;;32536:1;;32526:12;32692:111;32773:5;29534:13;29527:21;32751:5;32748:32;32738:2;;32794:1;;32784:12;32922:117;-1:-1;;;;;33009:5;29622:46;32984:5;32981:35;32971:2;;33030:1;;33020:12
Swarm Source
ipfs://31c9f9c7a2cb17365bc987bf2c91fa0796d9b7065ad9ac93985703eb0c73fc6a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 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.