Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
CompoundSaverFlashProxy
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-02-26 */ /** */ pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; abstract contract IFeeRecipient { function getFeeAddr() public view virtual returns (address); function changeWalletAddr(address _newWallet) public virtual; } 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 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); } } } } 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 AdminAuth { using SafeERC20 for ERC20; address public owner; address public admin; modifier onlyOwner() { require(owner == msg.sender); _; } constructor() public { owner = msg.sender; } /// @notice Admin is set by owner first time, after that admin is super role and has permission to change owner /// @param _admin Address of multisig that becomes admin function setAdminByOwner(address _admin) public { require(msg.sender == owner); require(admin == address(0)); admin = _admin; } /// @notice Admin is able to set new admin /// @param _admin Address of multisig that becomes new admin function setAdminByAdmin(address _admin) public { require(msg.sender == admin); admin = _admin; } /// @notice Admin is able to change owner /// @param _owner Address of new owner function setOwnerByAdmin(address _owner) public { require(msg.sender == admin); owner = _owner; } /// @notice Destroy the contract function kill() public onlyOwner { selfdestruct(payable(owner)); } /// @notice withdraw stuck funds function withdrawStuckFunds(address _token, uint _amount) public onlyOwner { if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { payable(owner).transfer(_amount); } else { ERC20(_token).safeTransfer(owner, _amount); } } } 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 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 {} } 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); } abstract contract CEtherInterface { function mint() external virtual payable; function repayBorrow() external virtual payable; } 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 DSAuthority { function canCall(address src, address dst, bytes4 sig) public virtual view returns (bool); } contract DSAuthEvents { event LogSetAuthority(address indexed authority); event LogSetOwner(address indexed owner); } contract DSAuth is DSAuthEvents { DSAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(address(authority)); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else if (authority == DSAuthority(0)) { return false; } else { return authority.canCall(src, address(this), sig); } } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint256 wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } abstract contract DSProxy is DSAuth, DSNote { DSProxyCache public cache; // global cache for contracts constructor(address _cacheAddr) public { require(setCache(_cacheAddr)); } // solhint-disable-next-line no-empty-blocks receive() external payable {} // use the proxy to execute calldata _data on contract _code // function execute(bytes memory _code, bytes memory _data) // public // payable // virtual // returns (address target, bytes32 response); function execute(address _target, bytes memory _data) public payable virtual returns (bytes32 response); //set new cache function setCache(address _cacheAddr) public virtual payable returns (bool); } contract DSProxyCache { mapping(bytes32 => address) cache; function read(bytes memory _code) public view returns (address) { bytes32 hash = keccak256(_code); return cache[hash]; } function write(bytes memory _code) public returns (address target) { assembly { target := create(0, add(_code, 0x20), mload(_code)) switch iszero(extcodesize(target)) case 1 { // throw if contract failed to deploy revert(0, 0) } } bytes32 hash = keccak256(_code); cache[hash] = target; } } 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 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; } } /// @title Utlity functions for Compound contracts contract CompoundSaverHelper is DSMath, Exponential { using SafeERC20 for ERC20; IFeeRecipient public constant _feeRecipient = IFeeRecipient(0x39C4a92Dc506300c3Ea4c67ca4CA611102ee6F2A); address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F; uint public constant MANUAL_SERVICE_FEE = 400; // 0.25% Fee uint public constant AUTOMATIC_SERVICE_FEE = 333; // 0.3% Fee address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address public constant CETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5; address public constant COMPTROLLER = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; address public constant COMPOUND_LOGGER = 0x3DD0CDf5fFA28C6847B4B276e2fD256046a44bb7; address public constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B; /// @notice Helper method to payback the Compound debt /// @dev If amount is bigger it will repay the whole debt and send the extra to the _user /// @param _amount Amount of tokens we want to repay /// @param _cBorrowToken Ctoken address we are repaying /// @param _borrowToken Token address we are repaying /// @param _user Owner of the compound position we are paying back function paybackDebt(uint _amount, address _cBorrowToken, address _borrowToken, address payable _user) internal { uint wholeDebt = CTokenInterface(_cBorrowToken).borrowBalanceCurrent(address(this)); if (_amount > wholeDebt) { if (_borrowToken == ETH_ADDRESS) { _user.transfer((_amount - wholeDebt)); } else { ERC20(_borrowToken).safeTransfer(_user, (_amount - wholeDebt)); } _amount = wholeDebt; } approveCToken(_borrowToken, _cBorrowToken); if (_borrowToken == ETH_ADDRESS) { CEtherInterface(_cBorrowToken).repayBorrow{value: _amount}(); } else { require(CTokenInterface(_cBorrowToken).repayBorrow(_amount) == 0); } } /// @notice Calculates the fee amount /// @param _amount Amount that is converted /// @param _user Actuall user addr not DSProxy /// @param _gasCost Ether amount of gas we are spending for tx /// @param _cTokenAddr CToken addr. of token we are getting for the fee /// @return feeAmount The amount we took for the fee function getFee(uint _amount, address _user, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) { uint fee = MANUAL_SERVICE_FEE; if (BotRegistry(BOT_REGISTRY_ADDRESS).botList(tx.origin)) { fee = AUTOMATIC_SERVICE_FEE; } address tokenAddr = getUnderlyingAddr(_cTokenAddr); if (Discount(DISCOUNT_ADDR).isCustomFeeSet(_user)) { fee = Discount(DISCOUNT_ADDR).getCustomServiceFee(_user); } feeAmount = (fee == 0) ? 0 : (_amount / fee); if (_gasCost != 0) { address oracle = ComptrollerInterface(COMPTROLLER).oracle(); uint usdTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr); uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(CETH_ADDRESS); uint tokenPriceInEth = wdiv(usdTokenPrice, ethPrice); _gasCost = wdiv(_gasCost, tokenPriceInEth); feeAmount = add(feeAmount, _gasCost); } // fee can't go over 20% of the whole amount if (feeAmount > (_amount / 5)) { feeAmount = _amount / 5; } address walletAddr = _feeRecipient.getFeeAddr(); if (tokenAddr == ETH_ADDRESS) { payable(walletAddr).transfer(feeAmount); } else { ERC20(tokenAddr).safeTransfer(walletAddr, feeAmount); } } /// @notice Calculates the gas cost of transaction and send it to wallet /// @param _amount Amount that is converted /// @param _gasCost Ether amount of gas we are spending for tx /// @param _cTokenAddr CToken addr. of token we are getting for the fee /// @return feeAmount The amount we took for the fee function getGasCost(uint _amount, uint _gasCost, address _cTokenAddr) internal returns (uint feeAmount) { address tokenAddr = getUnderlyingAddr(_cTokenAddr); if (_gasCost != 0) { address oracle = ComptrollerInterface(COMPTROLLER).oracle(); uint usdTokenPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cTokenAddr); uint ethPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(CETH_ADDRESS); uint tokenPriceInEth = wdiv(usdTokenPrice, ethPrice); feeAmount = wdiv(_gasCost, tokenPriceInEth); } // fee can't go over 20% of the whole amount if (feeAmount > (_amount / 5)) { feeAmount = _amount / 5; } address walletAddr = _feeRecipient.getFeeAddr(); if (tokenAddr == ETH_ADDRESS) { payable(walletAddr).transfer(feeAmount); } else { ERC20(tokenAddr).safeTransfer(walletAddr, feeAmount); } } /// @notice Enters the market for the collatera and borrow tokens /// @param _cTokenAddrColl Collateral address we are entering the market in /// @param _cTokenAddrBorrow Borrow address we are entering the market in function enterMarket(address _cTokenAddrColl, address _cTokenAddrBorrow) internal { address[] memory markets = new address[](2); markets[0] = _cTokenAddrColl; markets[1] = _cTokenAddrBorrow; ComptrollerInterface(COMPTROLLER).enterMarkets(markets); } /// @notice Approves CToken contract to pull underlying tokens from the DSProxy /// @param _tokenAddr Token we are trying to approve /// @param _cTokenAddr Address which will gain the approval function approveCToken(address _tokenAddr, address _cTokenAddr) internal { if (_tokenAddr != ETH_ADDRESS) { ERC20(_tokenAddr).safeApprove(_cTokenAddr, uint(-1)); } } /// @notice Returns the underlying address of the cToken asset /// @param _cTokenAddress cToken address /// @return Token address of the cToken specified function getUnderlyingAddr(address _cTokenAddress) internal returns (address) { if (_cTokenAddress == CETH_ADDRESS) { return ETH_ADDRESS; } else { return CTokenInterface(_cTokenAddress).underlying(); } } /// @notice Returns the owner of the DSProxy that called the contract function getUserAddress() internal view returns (address) { DSProxy proxy = DSProxy(uint160(address(this))); return proxy.owner(); } /// @notice Returns the maximum amount of collateral available to withdraw /// @dev Due to rounding errors the result is - 1% wei from the exact amount /// @param _cCollAddress Collateral we are getting the max value of /// @param _account Users account /// @return Returns the max. collateral amount in that token function getMaxCollateral(address _cCollAddress, address _account) public returns (uint) { (, uint liquidityInUsd, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account); uint usersBalance = CTokenInterface(_cCollAddress).balanceOfUnderlying(_account); address oracle = ComptrollerInterface(COMPTROLLER).oracle(); if (liquidityInUsd == 0) return usersBalance; CTokenInterface(_cCollAddress).accrueInterest(); (, uint collFactorMantissa) = ComptrollerInterface(COMPTROLLER).markets(_cCollAddress); Exp memory collateralFactor = Exp({mantissa: collFactorMantissa}); (, uint tokensToUsd) = divScalarByExpTruncate(liquidityInUsd, collateralFactor); uint usdPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cCollAddress); uint liqInToken = wdiv(tokensToUsd, usdPrice); if (liqInToken > usersBalance) return usersBalance; return sub(liqInToken, (liqInToken / 100)); // cut off 1% due to rounding issues } /// @notice Returns the maximum amount of borrow amount available /// @dev Due to rounding errors the result is - 1% wei from the exact amount /// @param _cBorrowAddress Borrow token we are getting the max value of /// @param _account Users account /// @return Returns the max. borrow amount in that token function getMaxBorrow(address _cBorrowAddress, address _account) public returns (uint) { (, uint liquidityInUsd, ) = ComptrollerInterface(COMPTROLLER).getAccountLiquidity(_account); address oracle = ComptrollerInterface(COMPTROLLER).oracle(); CTokenInterface(_cBorrowAddress).accrueInterest(); uint usdPrice = CompoundOracleInterface(oracle).getUnderlyingPrice(_cBorrowAddress); uint liquidityInToken = wdiv(liquidityInUsd, usdPrice); return sub(liquidityInToken, (liquidityInToken / 100)); // cut off 1% due to rounding issues } } 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); } } /// @title Implements the actual logic of Repay/Boost with FL contract CompoundSaverFlashProxy is SaverExchangeCore, CompoundSaverHelper { address public constant DEFISAVER_LOGGER = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126; using SafeERC20 for ERC20; /// @notice Repays the position and sends tokens back for FL /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress] /// @param _gasCost Gas cost for transaction /// @param _flashLoanData Data about FL [amount, fee] function flashRepay( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost, uint[2] memory _flashLoanData // amount, fee ) public payable { enterMarket(_cAddresses[0], _cAddresses[1]); address payable user = payable(getUserAddress()); uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1]; uint maxColl = getMaxCollateral(_cAddresses[0], address(this)); // draw max coll require(CTokenInterface(_cAddresses[0]).redeemUnderlying(maxColl) == 0); address collToken = getUnderlyingAddr(_cAddresses[0]); address borrowToken = getUnderlyingAddr(_cAddresses[1]); uint swapAmount = 0; if (collToken != borrowToken) { // swap max coll + loanAmount _exData.srcAmount = maxColl + _flashLoanData[0]; (,swapAmount) = _sell(_exData); // get fee swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]); } else { swapAmount = (maxColl + _flashLoanData[0]); swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]); } // payback debt paybackDebt(swapAmount, _cAddresses[1], borrowToken, user); // draw collateral for loanAmount + loanFee require(CTokenInterface(_cAddresses[0]).redeemUnderlying(flashBorrowed) == 0); // repay flash loan returnFlashLoan(collToken, flashBorrowed); DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CompoundRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken)); } /// @notice Boosts the position and sends tokens back for FL /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress] /// @param _gasCost Gas cost for specific transaction /// @param _flashLoanData Data about FL [amount, fee] function flashBoost( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost, uint[2] memory _flashLoanData // amount, fee ) public payable { enterMarket(_cAddresses[0], _cAddresses[1]); address payable user = payable(getUserAddress()); uint flashBorrowed = _flashLoanData[0] + _flashLoanData[1]; // borrow max amount uint borrowAmount = getMaxBorrow(_cAddresses[1], address(this)); require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0); address collToken = getUnderlyingAddr(_cAddresses[0]); address borrowToken = getUnderlyingAddr(_cAddresses[1]); uint swapAmount = 0; if (collToken != borrowToken) { // get dfs fee borrowAmount -= getFee((borrowAmount + _flashLoanData[0]), user, _gasCost, _cAddresses[1]); _exData.srcAmount = (borrowAmount + _flashLoanData[0]); (,swapAmount) = _sell(_exData); } else { swapAmount = (borrowAmount + _flashLoanData[0]); swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]); } // deposit swaped collateral depositCollateral(collToken, _cAddresses[0], swapAmount); // borrow token to repay flash loan require(CTokenInterface(_cAddresses[1]).borrow(flashBorrowed) == 0); // repay flash loan returnFlashLoan(borrowToken, flashBorrowed); DefisaverLogger(DEFISAVER_LOGGER).Log(address(this), msg.sender, "CompoundBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken)); } /// @notice Helper method to deposit tokens in Compound /// @param _collToken Token address of the collateral /// @param _cCollToken CToken address of the collateral /// @param _depositAmount Amount to deposit function depositCollateral(address _collToken, address _cCollToken, uint _depositAmount) internal { approveCToken(_collToken, _cCollToken); if (_collToken != ETH_ADDRESS) { require(CTokenInterface(_cCollToken).mint(_depositAmount) == 0); } else { CEtherInterface(_cCollToken).mint{value: _depositAmount}(); // reverts on fail } } /// @notice Returns the tokens/ether to the msg.sender which is the FL contract /// @param _tokenAddr Address of token which we return /// @param _amount Amount to return function returnFlashLoan(address _tokenAddr, uint _amount) internal { if (_tokenAddr != ETH_ADDRESS) { ERC20(_tokenAddr).safeTransfer(msg.sender, _amount); } msg.sender.transfer(address(this).balance); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"AUTOMATIC_SERVICE_FEE","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":"CETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMPOUND_LOGGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMPTROLLER","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":"DISCOUNT_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISCOUNT_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC20_PROXY_0X","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KYBER_ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANUAL_SERVICE_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAVER_EXCHANGE_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZRX_ALLOWLIST_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_feeRecipient","outputs":[{"internalType":"contract IFeeRecipient","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":"uint256","name":"_gasCost","type":"uint256"},{"internalType":"uint256[2]","name":"_flashLoanData","type":"uint256[2]"}],"name":"flashBoost","outputs":[],"stateMutability":"payable","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":"uint256","name":"_gasCost","type":"uint256"},{"internalType":"uint256[2]","name":"_flashLoanData","type":"uint256[2]"}],"name":"flashRepay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_cBorrowAddress","type":"address"},{"internalType":"address","name":"_account","type":"address"}],"name":"getMaxBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_cCollAddress","type":"address"},{"internalType":"address","name":"_account","type":"address"}],"name":"getMaxCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"}],"name":"packExchangeData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"unpackExchangeData","outputs":[{"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"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b5061377f806100206000396000f3fe6080604052600436106101395760003560e01c806353485907116100ab578063a342f2381161006f578063a342f238146102e6578063a3b8e5d1146102fb578063a46a66c9146102bc578063a734f06e146101b2578063d0cc728914610328578063e19d5e181461033d57610140565b806353485907146102655780635f82c67e1461029257806368c28159146102a75780637b925ab1146102bc5780638c8a7958146102d157610140565b8063314b6332116100fd578063314b6332146101e757806339af24ae146101fc57806339df1878146102115780634ab45d33146102265780634d2ab9dc1461023b578063526d64611461025057610140565b8063040141e51461014557806304c9805c146101705780631ec18ec01461019257806329f7fc9e146101b25780632b6e6581146101c757610140565b3661014057005b600080fd5b34801561015157600080fd5b5061015a610350565b604051610167919061325e565b60405180910390f35b34801561017c57600080fd5b50610185610368565b60405161016791906135e9565b34801561019e57600080fd5b506101856101ad366004612eb7565b61036e565b3480156101be57600080fd5b5061015a6105a5565b3480156101d357600080fd5b506101856101e2366004612eb7565b6105b7565b3480156101f357600080fd5b5061015a610948565b34801561020857600080fd5b5061015a610960565b34801561021d57600080fd5b5061015a610978565b34801561023257600080fd5b5061015a610990565b34801561024757600080fd5b506101856109a8565b34801561025c57600080fd5b5061015a6109ae565b34801561027157600080fd5b50610285610280366004613064565b6109c6565b60405161016791906133ec565b34801561029e57600080fd5b5061015a610a6b565b6102ba6102b5366004613097565b610a83565b005b3480156102c857600080fd5b5061015a610d33565b3480156102dd57600080fd5b5061015a610d4b565b3480156102f257600080fd5b5061015a610d63565b34801561030757600080fd5b5061031b610316366004612fd0565b610d7b565b6040516101679190613550565b34801561033457600080fd5b5061015a610e15565b6102ba61034b366004613097565b610e2d565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b61014d81565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906103aa90869060040161325e565b60606040518083038186803b1580156103c257600080fd5b505afa1580156103d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fa91906131dc565b509150506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561044d57600080fd5b505afa158015610461573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104859190612e4d565b9050846001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104c257600080fd5b505af11580156104d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fa919061314e565b5060405163fc57d4df60e01b81526000906001600160a01b0383169063fc57d4df9061052a90899060040161325e565b60206040518083038186803b15801561054257600080fd5b505afa158015610556573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057a919061314e565b905060006105888483611076565b9050610598816064815b046110a7565b9450505050505b92915050565b60008051602061372a83398151915281565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906105f390869060040161325e565b60606040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906131dc565b509150506000846001600160a01b0316633af9e669856040518263ffffffff1660e01b8152600401610675919061325e565b602060405180830381600087803b15801561068f57600080fd5b505af11580156106a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c7919061314e565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561071857600080fd5b505afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190612e4d565b9050826107615750915061059f9050565b856001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561079c57600080fd5b505af11580156107b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d4919061314e565b50604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9061080f908a9060040161325e565b604080518083038186803b15801561082657600080fd5b505afa15801561083a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085e9190612f9f565b915050610869612c10565b506040805160208101909152818152600061088486836110b7565b9150506000846001600160a01b031663fc57d4df8b6040518263ffffffff1660e01b81526004016108b5919061325e565b60206040518083038186803b1580156108cd57600080fd5b505afa1580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610905919061314e565b905060006109138383611076565b90508681111561092d57869850505050505050505061059f565b61093981606481610592565b9b9a5050505050505050505050565b7325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d81565b733dd0cdf5ffa28c6847b4b276e2fd256046a44bb781565b735c55b921f590a89c1ebe84df170e655a82b6212681565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b61019081565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60608082600001518360200151846040015185606001516040516020016109f09493929190613341565b60408051601f1981840301815290829052608085015160a086015160c087015160e0880151610100890151949650606095610a2e95906020016135f2565b60405160208183030381529060405290508181604051602001610a529291906133ff565b604051602081830303815290604052925050505b919050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b610a9c8360005b6020020151846001602002015161110b565b6000610aa6611212565b6020808401518451918701519293500190600090610ac4903061036e565b602087015160405163317afabb60e21b81529192506001600160a01b03169063c5ebeaec90610af79084906004016135e9565b602060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b49919061314e565b15610b5357600080fd5b6000610b6587825b602002015161128f565b90506000610b74886001610b5b565b90506000816001600160a01b0316836001600160a01b031614610bc7578651610ba9908501878a8c60015b6020020151611345565b8751940393840160408b0152610bbe8a6117fe565b9150610be29050565b5085518301610bdf81898b60015b6020020151611a78565b90035b8851610bf090849083611d5b565b602089015160405163317afabb60e21b81526001600160a01b039091169063c5ebeaec90610c229088906004016135e9565b602060405180830381600087803b158015610c3c57600080fd5b505af1158015610c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c74919061314e565b15610c7e57600080fd5b610c888286611e6a565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338d60400151858888604051602001610cc89493929190613636565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf593929190613272565b600060405180830381600087803b158015610d0f57600080fd5b505af1158015610d23573d6000803e3d6000fd5b5050505050505050505050505050565b731b14e8d511c9a4395425314f849bd737baf8208f81565b734ba1f38427b33b8ab7bb0490200dae1f1c36823f81565b7339c4a92dc506300c3ea4c67ca4ca611102ee6f2a81565b610d83612c23565b60608083806020019051810190610d9a9190613003565b9150915081806020019051810190610db29190612e70565b606087015260408601526001600160a01b03908116602080870191909152911684528151610de7919083018101908301613166565b61010088015260e08701526001600160a01b0390811660c08701521660a08501526080840152509092915050565b7395e6f48254609a6ee006f7d493c8e5fb97094cef81565b610e38836000610a8a565b6000610e42611212565b6020830151835186519293500190600090610e5d90306105b7565b865160405163852a12e360e01b81529192506001600160a01b03169063852a12e390610e8d9084906004016135e9565b602060405180830381600087803b158015610ea757600080fd5b505af1158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf919061314e565b15610ee957600080fd5b6000610ef58782610b5b565b90506000610f04886001610b5b565b90506000816001600160a01b0316836001600160a01b031614610f4c578651840160408b0152610f338a6117fe565b9150610f45905081878a8c6001610b9f565b9003610f61565b5085518301610f5e81898b6001610bd5565b90035b610f74818a600160200201518489611ec8565b885160405163852a12e360e01b81526001600160a01b039091169063852a12e390610fa39088906004016135e9565b602060405180830381600087803b158015610fbd57600080fd5b505af1158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff5919061314e565b15610fff57600080fd5b6110098386611e6a565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338d604001518588886040516020016110499493929190613636565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf5939291906132cc565b60008161109861108e85670de0b6b3a76400006120da565b6002855b046120fe565b8161109f57fe5b049392505050565b8082038281111561059f57600080fd5b60008060006110c4612c10565b6110ce868661210e565b909250905060008260038111156110e157fe5b146110f25750915060009050611104565b60006110fd8261216d565b9350935050505b9250929050565b6040805160028082526060808301845292602083019080368337019050509050828160008151811061113957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050818160018151811061116757fe5b6001600160a01b0390921660209283029190910190910152604051631853304760e31b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063c2998238906111b690849060040161339f565b600060405180830381600087803b1580156111d057600080fd5b505af11580156111e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261120c9190810190612eef565b50505050565b600080309050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561125157600080fd5b505afa158015611265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112899190612e4d565b91505090565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed514156112cb575060008051602061372a833981519152610a66565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561130657600080fd5b505af115801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190612e4d565b9050610a66565b6040516320eb73ed60e11b81526000906101909073637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061138390329060040161325e565b60206040518083038186803b15801561139b57600080fd5b505afa1580156113af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d39190612f7f565b156113dd575061014d5b60006113e88461128f565b604051632cdc77ab60e21b8152909150731b14e8d511c9a4395425314f849bd737baf8208f9063b371deac9061142290899060040161325e565b60206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114729190612f7f565b1561150157604051636eeb543160e01b8152731b14e8d511c9a4395425314f849bd737baf8208f90636eeb5431906114ae90899060040161325e565b60206040518083038186803b1580156114c657600080fd5b505afa1580156114da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe919061314e565b91505b81156115165781878161151057fe5b04611519565b60005b925084156116e9576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561157057600080fd5b505afa158015611584573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a89190612e4d565b90506000816001600160a01b031663fc57d4df876040518263ffffffff1660e01b81526004016115d8919061325e565b60206040518083038186803b1580156115f057600080fd5b505afa158015611604573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611628919061314e565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b815260040161166c919061325e565b60206040518083038186803b15801561168457600080fd5b505afa158015611698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bc919061314e565b905060006116ca8383611076565b90506116d68982611076565b98506116e2878a6120fe565b9650505050505b600587048311156116fb576005870492505b60007339c4a92dc506300c3ea4c67ca4ca611102ee6f2a6001600160a01b031663b38779eb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561174a57600080fd5b505afa15801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190612e4d565b90506001600160a01b03821660008051602061372a83398151915214156117df576040516001600160a01b0382169085156108fc029086906000818181858888f193505050501580156117d9573d6000803e3d6000fd5b506117f3565b6117f36001600160a01b038316828661217c565b505050949350505050565b604081015181516000918291829182918291906001600160a01b031660008051602061372a83398151915214156118b057865161183a906121d2565b6001600160a01b031687526040808801518151630d0e30db60e41b8152915173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29263d0e30db09291600480830192600092919082900301818588803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b50505050505b61010087015115611907576118cd87600001518860400151612213565b60006118e18860000151896040015161225d565b90506118ef888260006122a4565b90955090935091508215611905578760c0015194505b505b81611921576119178760006125cf565b92508660a0015193505b611933876080015188604001516127e7565b611940886020015161280f565b10156119675760405162461bcd60e51b815260040161195e90613452565b60405180910390fd5b600061198673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261280f565b1115611a6c576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a08231906119cb90309060040161325e565b602060405180830381600087803b1580156119e557600080fd5b505af11580156119f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1d919061314e565b6040518263ffffffff1660e01b8152600401611a3991906135e9565b600060405180830381600087803b158015611a5357600080fd5b505af1158015611a67573d6000803e3d6000fd5b505050505b50919350915050915091565b600080611a848361128f565b90508315611c48576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b139190612e4d565b90506000816001600160a01b031663fc57d4df866040518263ffffffff1660e01b8152600401611b43919061325e565b60206040518083038186803b158015611b5b57600080fd5b505afa158015611b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b93919061314e565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b8152600401611bd7919061325e565b60206040518083038186803b158015611bef57600080fd5b505afa158015611c03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c27919061314e565b90506000611c358383611076565b9050611c418882611076565b9550505050505b60058504821115611c5a576005850491505b60007339c4a92dc506300c3ea4c67ca4ca611102ee6f2a6001600160a01b031663b38779eb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ca957600080fd5b505afa158015611cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce19190612e4d565b90506001600160a01b03821660008051602061372a8339815191521415611d3e576040516001600160a01b0382169084156108fc029085906000818181858888f19350505050158015611d38573d6000803e3d6000fd5b50611d52565b611d526001600160a01b038316828561217c565b50509392505050565b611d6583836128b3565b6001600160a01b03831660008051602061372a83398151915214611e105760405163140e25ad60e31b81526001600160a01b0383169063a0712d6890611daf9084906004016135e9565b602060405180830381600087803b158015611dc957600080fd5b505af1158015611ddd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e01919061314e565b15611e0b57600080fd5b611e65565b816001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e4b57600080fd5b505af1158015611e5f573d6000803e3d6000fd5b50505050505b505050565b6001600160a01b03821660008051602061372a83398151915214611e9c57611e9c6001600160a01b038316338361217c565b60405133904780156108fc02916000818181858888f19350505050158015611e65573d6000803e3d6000fd5b6040516305eff7ef60e21b81526000906001600160a01b038516906317bfdfbc90611ef790309060040161325e565b602060405180830381600087803b158015611f1157600080fd5b505af1158015611f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f49919061314e565b905080851115611fc9576001600160a01b03831660008051602061372a8339815191521415611faf576040516001600160a01b0383169082870380156108fc02916000818181858888f19350505050158015611fa9573d6000803e3d6000fd5b50611fc5565b611fc56001600160a01b0384168383880361217c565b8094505b611fd383856128b3565b6001600160a01b03831660008051602061372a833981519152141561204b57836001600160a01b0316634e4d9fea866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561202d57600080fd5b505af1158015612041573d6000803e3d6000fd5b50505050506120d3565b60405163073a938160e11b81526001600160a01b03851690630e752702906120779088906004016135e9565b602060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c9919061314e565b156120d357600080fd5b5050505050565b60008115806120f5575050808202828282816120f257fe5b04145b61059f57600080fd5b8082018281101561059f57600080fd5b6000612118612c10565b60008061212d670de0b6b3a7640000876128e7565b9092509050600082600381111561214057fe5b1461215f57506040805160208101909152600081529092509050611104565b6110fd818660000151612926565b51670de0b6b3a7640000900490565b611e658363a9059cbb60e01b848460405160240161219b929190613386565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526129d7565b60006001600160a01b03821660008051602061372a833981519152146121f8578161059f565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292915050565b6001600160a01b03821660008051602061372a83398151915214612259576122596001600160a01b0383167395e6f48254609a6ee006f7d493c8e5fb97094cef83612a66565b5050565b60006001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461228a57504761059f565b8147111561229c57814703905061059f565b504792915050565b60008080808460018111156122b557fe5b14156122d4576122cf8660e0015160248860400151612aa5565b6122e8565b6122e88660e0015160248860600151612aa5565b60c0860151604051620c045f60e41b8152734ba1f38427b33b8ab7bb0490200dae1f1c36823f9162c045f091612321919060040161325e565b60206040518083038186803b15801561233957600080fd5b505afa15801561234d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123719190612f7f565b1561237b57600094505b600061238a876020015161280f565b60c08801516040516302f5cc7960e11b8152919250734ba1f38427b33b8ab7bb0490200dae1f1c36823f916305eb98f2916123c79160040161325e565b60206040518083038186803b1580156123df57600080fd5b505afa1580156123f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124179190612f7f565b1561248a578660c001516001600160a01b0316868860e0015160405161243d9190613242565b60006040518083038185875af1925050503d806000811461247a576040519150601f19603f3d011682016040523d82523d6000602084013e61247f565b606091505b50508094505061248f565b600093505b604087015160009085156125c05788516124a89061280f565b60208a01519091506001600160a01b031660008051602061372a83398151915214156125ae576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a082319061250d90309060040161325e565b602060405180830381600087803b15801561252757600080fd5b505af115801561253b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255f919061314e565b6040518263ffffffff1660e01b815260040161257b91906135e9565b600060405180830381600087803b15801561259557600080fd5b505af11580156125a9573d6000803e3d6000fd5b505050505b826125bc8a6020015161280f565b0391505b90935091505093509350939050565b60a082015160405163e0aa279760e01b81526000917325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d9163e0aa27979161260c9160040161325e565b60206040518083038186803b15801561262457600080fd5b505afa158015612638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265c9190612f7f565b6126785760405162461bcd60e51b815260040161195e90613424565b60a08301516040840151845160009261269c926001600160a01b039092169161217c565b60008360018111156126aa57fe5b141561274a578360a001516001600160a01b031663cae270b6828660000151876020015188604001516040518563ffffffff1660e01b81526004016126f19392919061331d565b6020604051808303818588803b15801561270a57600080fd5b505af115801561271e573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612743919061314e565b91506127e0565b8360a001516001600160a01b031663153e66e6828660000151876020015188606001516040518563ffffffff1660e01b815260040161278b9392919061331d565b6020604051808303818588803b1580156127a457600080fd5b505af11580156127b8573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906127dd919061314e565b91505b5092915050565b6000670de0b6b3a76400006110986127ff85856120da565b6002670de0b6b3a7640000611092565b60006001600160a01b03821660008051602061372a8339815191521415612837575047610a66565b6040516370a0823160e01b81526001600160a01b038316906370a082319061286390309060040161325e565b60206040518083038186803b15801561287b57600080fd5b505afa15801561288f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059f919061314e565b6001600160a01b03821660008051602061372a83398151915214612259576122596001600160a01b03831682600019612a66565b600080836128fa57506000905080611104565b8383028385828161290757fe5b041461291b57600260009250925050611104565b600092509050611104565b6000612930612c10565b60008061294586670de0b6b3a76400006128e7565b9092509050600082600381111561295857fe5b1461297757506040805160208101909152600081529092509050611104565b6000806129848388612ad1565b9092509050600082600381111561299757fe5b146129ba5781604051806020016040528060008152509550955050505050611104565b604080516020810190915290815260009890975095505050505050565b6060612a2c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612afc9092919063ffffffff16565b805190915015611e655780806020019051810190612a4a9190612f7f565b611e655760405162461bcd60e51b815260040161195e90613506565b612a868363095ea7b360e01b84600060405160240161219b92919061336a565b611e658363095ea7b360e01b848460405160240161219b929190613386565b8160200183511015612ac95760405162461bcd60e51b815260040161195e90613489565b910160200152565b60008082612ae55750600190506000611104565b6000838581612af057fe5b04915091509250929050565b6060612b0b8484600085612b13565b949350505050565b6060612b1e85612bd7565b612b3a5760405162461bcd60e51b815260040161195e906134cf565b60006060866001600160a01b03168587604051612b579190613242565b60006040518083038185875af1925050503d8060008114612b94576040519150601f19603f3d011682016040523d82523d6000602084013e612b99565b606091505b50915091508115612bad579150612b0b9050565b805115612bbd5780518082602001fd5b8360405162461bcd60e51b815260040161195e91906133ec565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612b0b575050151592915050565b6040518060200160405280600081525090565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001600081525090565b803561059f81613711565b600082601f830112612cae578081fd5b612cb8604061365d565b9050808284604085011115612ccc57600080fd5b60005b6002811015612cee578135835260209283019290910190600101612ccf565b50505092915050565b600082601f830112612d07578081fd5b8135612d1a612d15826136c1565b61365d565b9150808252836020828501011115612d3157600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612d5a578081fd5b8151612d68612d15826136c1565b9150808252836020828501011115612d7f57600080fd5b6127e08160208401602086016136e5565b6000610120808385031215612da3578182fd5b612dac8161365d565b915050612db98383612c93565b8152612dc88360208401612c93565b6020820152604082013560408201526060820135606082015260808201356080820152612df88360a08401612c93565b60a0820152612e0a8360c08401612c93565b60c082015260e082013567ffffffffffffffff811115612e2957600080fd5b612e3584828501612cf7565b60e08301525061010080830135818301525092915050565b600060208284031215612e5e578081fd5b8151612e6981613711565b9392505050565b60008060008060808587031215612e85578283fd5b8451612e9081613711565b6020860151909450612ea181613711565b6040860151606090960151949790965092505050565b60008060408385031215612ec9578182fd5b8235612ed481613711565b91506020830135612ee481613711565b809150509250929050565b60006020808385031215612f01578182fd5b825167ffffffffffffffff811115612f17578283fd5b8301601f81018513612f27578283fd5b8051612f35612d15826136a1565b8181528381019083850185840285018601891015612f51578687fd5b8694505b83851015612f73578051835260019490940193918501918501612f55565b50979650505050505050565b600060208284031215612f90578081fd5b81518015158114612e69578182fd5b60008060408385031215612fb1578182fd5b82518015158114612fc0578283fd5b6020939093015192949293505050565b600060208284031215612fe1578081fd5b813567ffffffffffffffff811115612ff7578182fd5b6127dd84828501612cf7565b60008060408385031215613015578182fd5b825167ffffffffffffffff8082111561302c578384fd5b61303886838701612d4a565b9350602085015191508082111561304d578283fd5b5061305a85828601612d4a565b9150509250929050565b600060208284031215613075578081fd5b813567ffffffffffffffff81111561308b578182fd5b6127dd84828501612d90565b60008060008060c085870312156130ac578182fd5b843567ffffffffffffffff8111156130c2578283fd5b6130ce87828801612d90565b945050602086603f8701126130e1578283fd5b60026130ef612d1582613684565b8083890160608a018b811115613103578788fd5b875b85811015613129576131178d84612c93565b85529386019391860191600101613105565b509197505035945061314392508891505060808701612c9e565b905092959194509250565b60006020828403121561315f578081fd5b5051919050565b600080600080600060a0868803121561317d578283fd5b85519450602086015161318f81613711565b60408701519094506131a081613711565b606087015190935067ffffffffffffffff8111156131bc578182fd5b6131c888828901612d4a565b925050608086015190509295509295909350565b6000806000606084860312156131f0578081fd5b8351925060208401519150604084015190509250925092565b6001600160a01b03169052565b6000815180845261322e8160208601602086016136e5565b601f01601f19169290920160200192915050565b600082516132548184602087016136e5565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c10dbdb5c1bdd5b99109bdbdcdd609a1b60a082015260c0606082018190526000906132c390830184613216565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c436f6d706f756e64526570617960981b60a082015260c0606082018190526000906132c390830184613216565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156133e05783516001600160a01b0316835292840192918401916001016133bb565b50909695505050505050565b600060208252612e696020830184613216565b6000604082526134126040830185613216565b82810360208401526132c38185613216565b60208082526014908201527315dc985c1c195c881a5cc81b9bdd081d985b1a5960621b604082015260600190565b6020808252601a908201527f46696e616c20616d6f756e742069736e277420636f7272656374000000000000604082015260600190565b60208082526026908201527f496e636f7272656e74206c656e6774207768696c65207772697474696e6720626040820152653cba32b9999960d11b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060208252613564602083018451613209565b60208301516135766040840182613209565b506040830151606083015260608301516080830152608083015160a083015260a08301516135a760c0840182613209565b5060c08301516135ba60e0840182613209565b5060e083015161012061010081818601526135d9610140860184613216565b9501519301929092525090919050565b90815260200190565b8581526001600160a01b0385811660208301528416604082015260a06060820181905260009061362490830185613216565b90508260808301529695505050505050565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60405181810167ffffffffffffffff8111828210171561367c57600080fd5b604052919050565b600067ffffffffffffffff82111561369a578081fd5b5060200290565b600067ffffffffffffffff8211156136b7578081fd5b5060209081020190565b600067ffffffffffffffff8211156136d7578081fd5b50601f01601f191660200190565b60005b838110156137005781810151838201526020016136e8565b8381111561120c5750506000910152565b6001600160a01b038116811461372657600080fd5b5056fe000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea2646970667358221220fa32ed6546b976aa37636d2fb21e72bea7b15ac045cd20bee8b92d3f7e19b39b64736f6c634300060c0033
Deployed Bytecode
0x6080604052600436106101395760003560e01c806353485907116100ab578063a342f2381161006f578063a342f238146102e6578063a3b8e5d1146102fb578063a46a66c9146102bc578063a734f06e146101b2578063d0cc728914610328578063e19d5e181461033d57610140565b806353485907146102655780635f82c67e1461029257806368c28159146102a75780637b925ab1146102bc5780638c8a7958146102d157610140565b8063314b6332116100fd578063314b6332146101e757806339af24ae146101fc57806339df1878146102115780634ab45d33146102265780634d2ab9dc1461023b578063526d64611461025057610140565b8063040141e51461014557806304c9805c146101705780631ec18ec01461019257806329f7fc9e146101b25780632b6e6581146101c757610140565b3661014057005b600080fd5b34801561015157600080fd5b5061015a610350565b604051610167919061325e565b60405180910390f35b34801561017c57600080fd5b50610185610368565b60405161016791906135e9565b34801561019e57600080fd5b506101856101ad366004612eb7565b61036e565b3480156101be57600080fd5b5061015a6105a5565b3480156101d357600080fd5b506101856101e2366004612eb7565b6105b7565b3480156101f357600080fd5b5061015a610948565b34801561020857600080fd5b5061015a610960565b34801561021d57600080fd5b5061015a610978565b34801561023257600080fd5b5061015a610990565b34801561024757600080fd5b506101856109a8565b34801561025c57600080fd5b5061015a6109ae565b34801561027157600080fd5b50610285610280366004613064565b6109c6565b60405161016791906133ec565b34801561029e57600080fd5b5061015a610a6b565b6102ba6102b5366004613097565b610a83565b005b3480156102c857600080fd5b5061015a610d33565b3480156102dd57600080fd5b5061015a610d4b565b3480156102f257600080fd5b5061015a610d63565b34801561030757600080fd5b5061031b610316366004612fd0565b610d7b565b6040516101679190613550565b34801561033457600080fd5b5061015a610e15565b6102ba61034b366004613097565b610e2d565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b61014d81565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906103aa90869060040161325e565b60606040518083038186803b1580156103c257600080fd5b505afa1580156103d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fa91906131dc565b509150506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561044d57600080fd5b505afa158015610461573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104859190612e4d565b9050846001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104c257600080fd5b505af11580156104d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fa919061314e565b5060405163fc57d4df60e01b81526000906001600160a01b0383169063fc57d4df9061052a90899060040161325e565b60206040518083038186803b15801561054257600080fd5b505afa158015610556573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057a919061314e565b905060006105888483611076565b9050610598816064815b046110a7565b9450505050505b92915050565b60008051602061372a83398151915281565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906105f390869060040161325e565b60606040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906131dc565b509150506000846001600160a01b0316633af9e669856040518263ffffffff1660e01b8152600401610675919061325e565b602060405180830381600087803b15801561068f57600080fd5b505af11580156106a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c7919061314e565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561071857600080fd5b505afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190612e4d565b9050826107615750915061059f9050565b856001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561079c57600080fd5b505af11580156107b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d4919061314e565b50604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9061080f908a9060040161325e565b604080518083038186803b15801561082657600080fd5b505afa15801561083a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085e9190612f9f565b915050610869612c10565b506040805160208101909152818152600061088486836110b7565b9150506000846001600160a01b031663fc57d4df8b6040518263ffffffff1660e01b81526004016108b5919061325e565b60206040518083038186803b1580156108cd57600080fd5b505afa1580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610905919061314e565b905060006109138383611076565b90508681111561092d57869850505050505050505061059f565b61093981606481610592565b9b9a5050505050505050505050565b7325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d81565b733dd0cdf5ffa28c6847b4b276e2fd256046a44bb781565b735c55b921f590a89c1ebe84df170e655a82b6212681565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b61019081565b73637726f8b08a7abe3ae3acab01a80e2d8ddef77b81565b60608082600001518360200151846040015185606001516040516020016109f09493929190613341565b60408051601f1981840301815290829052608085015160a086015160c087015160e0880151610100890151949650606095610a2e95906020016135f2565b60405160208183030381529060405290508181604051602001610a529291906133ff565b604051602081830303815290604052925050505b919050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b610a9c8360005b6020020151846001602002015161110b565b6000610aa6611212565b6020808401518451918701519293500190600090610ac4903061036e565b602087015160405163317afabb60e21b81529192506001600160a01b03169063c5ebeaec90610af79084906004016135e9565b602060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b49919061314e565b15610b5357600080fd5b6000610b6587825b602002015161128f565b90506000610b74886001610b5b565b90506000816001600160a01b0316836001600160a01b031614610bc7578651610ba9908501878a8c60015b6020020151611345565b8751940393840160408b0152610bbe8a6117fe565b9150610be29050565b5085518301610bdf81898b60015b6020020151611a78565b90035b8851610bf090849083611d5b565b602089015160405163317afabb60e21b81526001600160a01b039091169063c5ebeaec90610c229088906004016135e9565b602060405180830381600087803b158015610c3c57600080fd5b505af1158015610c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c74919061314e565b15610c7e57600080fd5b610c888286611e6a565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338d60400151858888604051602001610cc89493929190613636565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf593929190613272565b600060405180830381600087803b158015610d0f57600080fd5b505af1158015610d23573d6000803e3d6000fd5b5050505050505050505050505050565b731b14e8d511c9a4395425314f849bd737baf8208f81565b734ba1f38427b33b8ab7bb0490200dae1f1c36823f81565b7339c4a92dc506300c3ea4c67ca4ca611102ee6f2a81565b610d83612c23565b60608083806020019051810190610d9a9190613003565b9150915081806020019051810190610db29190612e70565b606087015260408601526001600160a01b03908116602080870191909152911684528151610de7919083018101908301613166565b61010088015260e08701526001600160a01b0390811660c08701521660a08501526080840152509092915050565b7395e6f48254609a6ee006f7d493c8e5fb97094cef81565b610e38836000610a8a565b6000610e42611212565b6020830151835186519293500190600090610e5d90306105b7565b865160405163852a12e360e01b81529192506001600160a01b03169063852a12e390610e8d9084906004016135e9565b602060405180830381600087803b158015610ea757600080fd5b505af1158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf919061314e565b15610ee957600080fd5b6000610ef58782610b5b565b90506000610f04886001610b5b565b90506000816001600160a01b0316836001600160a01b031614610f4c578651840160408b0152610f338a6117fe565b9150610f45905081878a8c6001610b9f565b9003610f61565b5085518301610f5e81898b6001610bd5565b90035b610f74818a600160200201518489611ec8565b885160405163852a12e360e01b81526001600160a01b039091169063852a12e390610fa39088906004016135e9565b602060405180830381600087803b158015610fbd57600080fd5b505af1158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff5919061314e565b15610fff57600080fd5b6110098386611e6a565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338d604001518588886040516020016110499493929190613636565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf5939291906132cc565b60008161109861108e85670de0b6b3a76400006120da565b6002855b046120fe565b8161109f57fe5b049392505050565b8082038281111561059f57600080fd5b60008060006110c4612c10565b6110ce868661210e565b909250905060008260038111156110e157fe5b146110f25750915060009050611104565b60006110fd8261216d565b9350935050505b9250929050565b6040805160028082526060808301845292602083019080368337019050509050828160008151811061113957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050818160018151811061116757fe5b6001600160a01b0390921660209283029190910190910152604051631853304760e31b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063c2998238906111b690849060040161339f565b600060405180830381600087803b1580156111d057600080fd5b505af11580156111e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261120c9190810190612eef565b50505050565b600080309050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561125157600080fd5b505afa158015611265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112899190612e4d565b91505090565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed514156112cb575060008051602061372a833981519152610a66565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561130657600080fd5b505af115801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190612e4d565b9050610a66565b6040516320eb73ed60e11b81526000906101909073637726f8b08a7abe3ae3acab01a80e2d8ddef77b906341d6e7da9061138390329060040161325e565b60206040518083038186803b15801561139b57600080fd5b505afa1580156113af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d39190612f7f565b156113dd575061014d5b60006113e88461128f565b604051632cdc77ab60e21b8152909150731b14e8d511c9a4395425314f849bd737baf8208f9063b371deac9061142290899060040161325e565b60206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114729190612f7f565b1561150157604051636eeb543160e01b8152731b14e8d511c9a4395425314f849bd737baf8208f90636eeb5431906114ae90899060040161325e565b60206040518083038186803b1580156114c657600080fd5b505afa1580156114da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe919061314e565b91505b81156115165781878161151057fe5b04611519565b60005b925084156116e9576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561157057600080fd5b505afa158015611584573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a89190612e4d565b90506000816001600160a01b031663fc57d4df876040518263ffffffff1660e01b81526004016115d8919061325e565b60206040518083038186803b1580156115f057600080fd5b505afa158015611604573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611628919061314e565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b815260040161166c919061325e565b60206040518083038186803b15801561168457600080fd5b505afa158015611698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bc919061314e565b905060006116ca8383611076565b90506116d68982611076565b98506116e2878a6120fe565b9650505050505b600587048311156116fb576005870492505b60007339c4a92dc506300c3ea4c67ca4ca611102ee6f2a6001600160a01b031663b38779eb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561174a57600080fd5b505afa15801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190612e4d565b90506001600160a01b03821660008051602061372a83398151915214156117df576040516001600160a01b0382169085156108fc029086906000818181858888f193505050501580156117d9573d6000803e3d6000fd5b506117f3565b6117f36001600160a01b038316828661217c565b505050949350505050565b604081015181516000918291829182918291906001600160a01b031660008051602061372a83398151915214156118b057865161183a906121d2565b6001600160a01b031687526040808801518151630d0e30db60e41b8152915173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29263d0e30db09291600480830192600092919082900301818588803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b50505050505b61010087015115611907576118cd87600001518860400151612213565b60006118e18860000151896040015161225d565b90506118ef888260006122a4565b90955090935091508215611905578760c0015194505b505b81611921576119178760006125cf565b92508660a0015193505b611933876080015188604001516127e7565b611940886020015161280f565b10156119675760405162461bcd60e51b815260040161195e90613452565b60405180910390fd5b600061198673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261280f565b1115611a6c576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a08231906119cb90309060040161325e565b602060405180830381600087803b1580156119e557600080fd5b505af11580156119f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1d919061314e565b6040518263ffffffff1660e01b8152600401611a3991906135e9565b600060405180830381600087803b158015611a5357600080fd5b505af1158015611a67573d6000803e3d6000fd5b505050505b50919350915050915091565b600080611a848361128f565b90508315611c48576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b139190612e4d565b90506000816001600160a01b031663fc57d4df866040518263ffffffff1660e01b8152600401611b43919061325e565b60206040518083038186803b158015611b5b57600080fd5b505afa158015611b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b93919061314e565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b8152600401611bd7919061325e565b60206040518083038186803b158015611bef57600080fd5b505afa158015611c03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c27919061314e565b90506000611c358383611076565b9050611c418882611076565b9550505050505b60058504821115611c5a576005850491505b60007339c4a92dc506300c3ea4c67ca4ca611102ee6f2a6001600160a01b031663b38779eb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ca957600080fd5b505afa158015611cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce19190612e4d565b90506001600160a01b03821660008051602061372a8339815191521415611d3e576040516001600160a01b0382169084156108fc029085906000818181858888f19350505050158015611d38573d6000803e3d6000fd5b50611d52565b611d526001600160a01b038316828561217c565b50509392505050565b611d6583836128b3565b6001600160a01b03831660008051602061372a83398151915214611e105760405163140e25ad60e31b81526001600160a01b0383169063a0712d6890611daf9084906004016135e9565b602060405180830381600087803b158015611dc957600080fd5b505af1158015611ddd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e01919061314e565b15611e0b57600080fd5b611e65565b816001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e4b57600080fd5b505af1158015611e5f573d6000803e3d6000fd5b50505050505b505050565b6001600160a01b03821660008051602061372a83398151915214611e9c57611e9c6001600160a01b038316338361217c565b60405133904780156108fc02916000818181858888f19350505050158015611e65573d6000803e3d6000fd5b6040516305eff7ef60e21b81526000906001600160a01b038516906317bfdfbc90611ef790309060040161325e565b602060405180830381600087803b158015611f1157600080fd5b505af1158015611f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f49919061314e565b905080851115611fc9576001600160a01b03831660008051602061372a8339815191521415611faf576040516001600160a01b0383169082870380156108fc02916000818181858888f19350505050158015611fa9573d6000803e3d6000fd5b50611fc5565b611fc56001600160a01b0384168383880361217c565b8094505b611fd383856128b3565b6001600160a01b03831660008051602061372a833981519152141561204b57836001600160a01b0316634e4d9fea866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561202d57600080fd5b505af1158015612041573d6000803e3d6000fd5b50505050506120d3565b60405163073a938160e11b81526001600160a01b03851690630e752702906120779088906004016135e9565b602060405180830381600087803b15801561209157600080fd5b505af11580156120a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c9919061314e565b156120d357600080fd5b5050505050565b60008115806120f5575050808202828282816120f257fe5b04145b61059f57600080fd5b8082018281101561059f57600080fd5b6000612118612c10565b60008061212d670de0b6b3a7640000876128e7565b9092509050600082600381111561214057fe5b1461215f57506040805160208101909152600081529092509050611104565b6110fd818660000151612926565b51670de0b6b3a7640000900490565b611e658363a9059cbb60e01b848460405160240161219b929190613386565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526129d7565b60006001600160a01b03821660008051602061372a833981519152146121f8578161059f565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292915050565b6001600160a01b03821660008051602061372a83398151915214612259576122596001600160a01b0383167395e6f48254609a6ee006f7d493c8e5fb97094cef83612a66565b5050565b60006001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461228a57504761059f565b8147111561229c57814703905061059f565b504792915050565b60008080808460018111156122b557fe5b14156122d4576122cf8660e0015160248860400151612aa5565b6122e8565b6122e88660e0015160248860600151612aa5565b60c0860151604051620c045f60e41b8152734ba1f38427b33b8ab7bb0490200dae1f1c36823f9162c045f091612321919060040161325e565b60206040518083038186803b15801561233957600080fd5b505afa15801561234d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123719190612f7f565b1561237b57600094505b600061238a876020015161280f565b60c08801516040516302f5cc7960e11b8152919250734ba1f38427b33b8ab7bb0490200dae1f1c36823f916305eb98f2916123c79160040161325e565b60206040518083038186803b1580156123df57600080fd5b505afa1580156123f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124179190612f7f565b1561248a578660c001516001600160a01b0316868860e0015160405161243d9190613242565b60006040518083038185875af1925050503d806000811461247a576040519150601f19603f3d011682016040523d82523d6000602084013e61247f565b606091505b50508094505061248f565b600093505b604087015160009085156125c05788516124a89061280f565b60208a01519091506001600160a01b031660008051602061372a83398151915214156125ae576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a082319061250d90309060040161325e565b602060405180830381600087803b15801561252757600080fd5b505af115801561253b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255f919061314e565b6040518263ffffffff1660e01b815260040161257b91906135e9565b600060405180830381600087803b15801561259557600080fd5b505af11580156125a9573d6000803e3d6000fd5b505050505b826125bc8a6020015161280f565b0391505b90935091505093509350939050565b60a082015160405163e0aa279760e01b81526000917325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d9163e0aa27979161260c9160040161325e565b60206040518083038186803b15801561262457600080fd5b505afa158015612638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265c9190612f7f565b6126785760405162461bcd60e51b815260040161195e90613424565b60a08301516040840151845160009261269c926001600160a01b039092169161217c565b60008360018111156126aa57fe5b141561274a578360a001516001600160a01b031663cae270b6828660000151876020015188604001516040518563ffffffff1660e01b81526004016126f19392919061331d565b6020604051808303818588803b15801561270a57600080fd5b505af115801561271e573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612743919061314e565b91506127e0565b8360a001516001600160a01b031663153e66e6828660000151876020015188606001516040518563ffffffff1660e01b815260040161278b9392919061331d565b6020604051808303818588803b1580156127a457600080fd5b505af11580156127b8573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906127dd919061314e565b91505b5092915050565b6000670de0b6b3a76400006110986127ff85856120da565b6002670de0b6b3a7640000611092565b60006001600160a01b03821660008051602061372a8339815191521415612837575047610a66565b6040516370a0823160e01b81526001600160a01b038316906370a082319061286390309060040161325e565b60206040518083038186803b15801561287b57600080fd5b505afa15801561288f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059f919061314e565b6001600160a01b03821660008051602061372a83398151915214612259576122596001600160a01b03831682600019612a66565b600080836128fa57506000905080611104565b8383028385828161290757fe5b041461291b57600260009250925050611104565b600092509050611104565b6000612930612c10565b60008061294586670de0b6b3a76400006128e7565b9092509050600082600381111561295857fe5b1461297757506040805160208101909152600081529092509050611104565b6000806129848388612ad1565b9092509050600082600381111561299757fe5b146129ba5781604051806020016040528060008152509550955050505050611104565b604080516020810190915290815260009890975095505050505050565b6060612a2c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612afc9092919063ffffffff16565b805190915015611e655780806020019051810190612a4a9190612f7f565b611e655760405162461bcd60e51b815260040161195e90613506565b612a868363095ea7b360e01b84600060405160240161219b92919061336a565b611e658363095ea7b360e01b848460405160240161219b929190613386565b8160200183511015612ac95760405162461bcd60e51b815260040161195e90613489565b910160200152565b60008082612ae55750600190506000611104565b6000838581612af057fe5b04915091509250929050565b6060612b0b8484600085612b13565b949350505050565b6060612b1e85612bd7565b612b3a5760405162461bcd60e51b815260040161195e906134cf565b60006060866001600160a01b03168587604051612b579190613242565b60006040518083038185875af1925050503d8060008114612b94576040519150601f19603f3d011682016040523d82523d6000602084013e612b99565b606091505b50915091508115612bad579150612b0b9050565b805115612bbd5780518082602001fd5b8360405162461bcd60e51b815260040161195e91906133ec565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612b0b575050151592915050565b6040518060200160405280600081525090565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001600081525090565b803561059f81613711565b600082601f830112612cae578081fd5b612cb8604061365d565b9050808284604085011115612ccc57600080fd5b60005b6002811015612cee578135835260209283019290910190600101612ccf565b50505092915050565b600082601f830112612d07578081fd5b8135612d1a612d15826136c1565b61365d565b9150808252836020828501011115612d3157600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612d5a578081fd5b8151612d68612d15826136c1565b9150808252836020828501011115612d7f57600080fd5b6127e08160208401602086016136e5565b6000610120808385031215612da3578182fd5b612dac8161365d565b915050612db98383612c93565b8152612dc88360208401612c93565b6020820152604082013560408201526060820135606082015260808201356080820152612df88360a08401612c93565b60a0820152612e0a8360c08401612c93565b60c082015260e082013567ffffffffffffffff811115612e2957600080fd5b612e3584828501612cf7565b60e08301525061010080830135818301525092915050565b600060208284031215612e5e578081fd5b8151612e6981613711565b9392505050565b60008060008060808587031215612e85578283fd5b8451612e9081613711565b6020860151909450612ea181613711565b6040860151606090960151949790965092505050565b60008060408385031215612ec9578182fd5b8235612ed481613711565b91506020830135612ee481613711565b809150509250929050565b60006020808385031215612f01578182fd5b825167ffffffffffffffff811115612f17578283fd5b8301601f81018513612f27578283fd5b8051612f35612d15826136a1565b8181528381019083850185840285018601891015612f51578687fd5b8694505b83851015612f73578051835260019490940193918501918501612f55565b50979650505050505050565b600060208284031215612f90578081fd5b81518015158114612e69578182fd5b60008060408385031215612fb1578182fd5b82518015158114612fc0578283fd5b6020939093015192949293505050565b600060208284031215612fe1578081fd5b813567ffffffffffffffff811115612ff7578182fd5b6127dd84828501612cf7565b60008060408385031215613015578182fd5b825167ffffffffffffffff8082111561302c578384fd5b61303886838701612d4a565b9350602085015191508082111561304d578283fd5b5061305a85828601612d4a565b9150509250929050565b600060208284031215613075578081fd5b813567ffffffffffffffff81111561308b578182fd5b6127dd84828501612d90565b60008060008060c085870312156130ac578182fd5b843567ffffffffffffffff8111156130c2578283fd5b6130ce87828801612d90565b945050602086603f8701126130e1578283fd5b60026130ef612d1582613684565b8083890160608a018b811115613103578788fd5b875b85811015613129576131178d84612c93565b85529386019391860191600101613105565b509197505035945061314392508891505060808701612c9e565b905092959194509250565b60006020828403121561315f578081fd5b5051919050565b600080600080600060a0868803121561317d578283fd5b85519450602086015161318f81613711565b60408701519094506131a081613711565b606087015190935067ffffffffffffffff8111156131bc578182fd5b6131c888828901612d4a565b925050608086015190509295509295909350565b6000806000606084860312156131f0578081fd5b8351925060208401519150604084015190509250925092565b6001600160a01b03169052565b6000815180845261322e8160208601602086016136e5565b601f01601f19169290920160200192915050565b600082516132548184602087016136e5565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c10dbdb5c1bdd5b99109bdbdcdd609a1b60a082015260c0606082018190526000906132c390830184613216565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c436f6d706f756e64526570617960981b60a082015260c0606082018190526000906132c390830184613216565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156133e05783516001600160a01b0316835292840192918401916001016133bb565b50909695505050505050565b600060208252612e696020830184613216565b6000604082526134126040830185613216565b82810360208401526132c38185613216565b60208082526014908201527315dc985c1c195c881a5cc81b9bdd081d985b1a5960621b604082015260600190565b6020808252601a908201527f46696e616c20616d6f756e742069736e277420636f7272656374000000000000604082015260600190565b60208082526026908201527f496e636f7272656e74206c656e6774207768696c65207772697474696e6720626040820152653cba32b9999960d11b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b600060208252613564602083018451613209565b60208301516135766040840182613209565b506040830151606083015260608301516080830152608083015160a083015260a08301516135a760c0840182613209565b5060c08301516135ba60e0840182613209565b5060e083015161012061010081818601526135d9610140860184613216565b9501519301929092525090919050565b90815260200190565b8581526001600160a01b0385811660208301528416604082015260a06060820181905260009061362490830185613216565b90508260808301529695505050505050565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60405181810167ffffffffffffffff8111828210171561367c57600080fd5b604052919050565b600067ffffffffffffffff82111561369a578081fd5b5060200290565b600067ffffffffffffffff8211156136b7578081fd5b5060209081020190565b600067ffffffffffffffff8211156136d7578081fd5b50601f01601f191660200190565b60005b838110156137005781810151838201526020016136e8565b8381111561120c5750506000910152565b6001600160a01b038116811461372657600080fd5b5056fe000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea2646970667358221220fa32ed6546b976aa37636d2fb21e72bea7b15ac045cd20bee8b92d3f7e19b39b64736f6c634300060c0033
Deployed Bytecode Sourcemap
58559:5349:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15015:81;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;49180:48;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;57448:594::-;;;;;;;;;;-1:-1:-1;57448:594:0;;;;;:::i;:::-;;:::i;14922:86::-;;;;;;;;;;;;;:::i;56060:1049::-;;;;;;;;;;-1:-1:-1;56060:1049:0;;;;;:::i;:::-;;:::i;15197:92::-;;;;;;;;;;;;;:::i;49513:84::-;;;;;;;;;;;;;:::i;58644:85::-;;;;;;;;;;;;;:::i;49336:81::-;;;;;;;;;;;;;:::i;49115:45::-;;;;;;;;;;;;;:::i;49606:89::-;;;;;;;;;;;;;:::i;25978:641::-;;;;;;;;;;-1:-1:-1;25978:641:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;49424:80::-;;;;;;;;;;;;;:::i;61112:1711::-;;;;;;:::i;:::-;;:::i;:::-;;49024:82;;;;;;;;;;;;;:::i;15388:87::-;;;;;;;;;;;;;:::i;48912:103::-;;;;;;;;;;;;;:::i;26627:684::-;;;;;;;;;;-1:-1:-1;26627:684:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;15298:83::-;;;;;;;;;;;;;:::i;59074:1719::-;;;;;;:::i;:::-;;:::i;15015:81::-;15054:42;15015:81;:::o;49180:48::-;49225:3;49180:48;:::o;57448:594::-;57574:63;;-1:-1:-1;;;57574:63:0;;57529:4;;;;49462:42;;57574:53;;:63;;57628:8;;57574:63;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57546:91;;;;57648:14;49462:42;-1:-1:-1;;;;;57665:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57648:59;;57736:15;-1:-1:-1;;;;;57720:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;57798:67:0;;-1:-1:-1;;;57798:67:0;;57782:13;;-1:-1:-1;;;;;57798:50:0;;;;;:67;;57849:15;;57798:67;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57782:83;;57876:21;57900:30;57905:14;57921:8;57900:4;:30::i;:::-;57876:54;-1:-1:-1;57950:47:0;57876:54;57992:3;57876:54;57973:22;;57950:3;:47::i;:::-;57943:54;;;;;;57448:594;;;;;:::o;14922:86::-;-1:-1:-1;;;;;;;;;;;14922:86:0;:::o;56060:1049::-;56188:63;;-1:-1:-1;;;56188:63:0;;56143:4;;;;49462:42;;56188:53;;:63;;56242:8;;56188:63;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56160:91;;;;56262:17;56298:13;-1:-1:-1;;;;;56282:50:0;;56333:8;56282:60;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56262:80;;56353:14;49462:42;-1:-1:-1;;;;;56370:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56353:59;-1:-1:-1;56429:19:0;56425:44;;-1:-1:-1;56457:12:0;-1:-1:-1;56450:19:0;;-1:-1:-1;56450:19:0;56425:44;56498:13;-1:-1:-1;;;;;56482:45:0;;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;56572:56:0;;-1:-1:-1;;;56572:56:0;;56545:23;;49462:42;;56572:41;;:56;;56614:13;;56572:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56542:86;;;56639:27;;:::i;:::-;-1:-1:-1;56669:35:0;;;;;;;;;;;;-1:-1:-1;56740:56:0;56763:14;56669:35;56740:22;:56::i;:::-;56717:79;;;56809:13;56849:6;-1:-1:-1;;;;;56825:50:0;;56876:13;56825:65;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56809:81;;56901:15;56919:27;56924:11;56937:8;56919:4;:27::i;:::-;56901:45;;56976:12;56963:10;:25;56959:50;;;56997:12;56990:19;;;;;;;;;;;;56959:50;57029:35;57033:10;57059:3;57033:10;57046:16;;57029:35;57022:42;56060:1049;-1:-1:-1;;;;;;;;;;;56060:1049:0:o;15197:92::-;15247:42;15197:92;:::o;49513:84::-;49555:42;49513:84;:::o;58644:85::-;58687:42;58644:85;:::o;49336:81::-;49375:42;49336:81;:::o;49115:45::-;49157:3;49115:45;:::o;49606:89::-;49653:42;49606:89;:::o;25978:641::-;26053:12;26185:18;26231:7;:15;;;26261:7;:16;;;26292:7;:17;;;26324:7;:18;;;26206:147;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;26206:147:0;;;;;;;;;;26412:16;;;;26443:15;;;;26473:20;;;;26508:16;;;;26539:15;;;;26206:147;;-1:-1:-1;26366:18:0;;26387:178;;26539:15;26206:147;26387:178;;:::i;:::-;;;;;;;;;;;;;26366:199;;26598:5;26605;26587:24;;;;;;;;;:::i;:::-;;;;;;;;;;;;;26580:31;;;;25978:641;;;;:::o;49424:80::-;49462:42;49424:80;:::o;61112:1711::-;61357:43;61369:11;61381:1;61369:14;;;;;61385:11;61397:1;61385:14;;;;61357:11;:43::i;:::-;61413:20;61444:16;:14;:16::i;:::-;61513:17;;;;;61493;;61606:14;;;;61413:48;;-1:-1:-1;61493:37:0;;61472:18;;61593:43;;61630:4;61593:12;:43::i;:::-;61671:14;;;;61655:52;;-1:-1:-1;;;61655:52:0;;61573:63;;-1:-1:-1;;;;;;61655:38:0;;;;:52;;61573:63;;61655:52;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:57;61647:66;;;;;;61726:17;61746:33;61764:11;61726:17;61764:14;;;;;61746:17;:33::i;:::-;61726:53;-1:-1:-1;61790:19:0;61812:33;61830:11;61842:1;61830:14;;61812:33;61790:55;;61858:15;61907:11;-1:-1:-1;;;;;61894:24:0;:9;-1:-1:-1;;;;;61894:24:0;;61890:448;;62002:17;;61979:74;;61987:32;;62022:4;62028:8;62038:11;62050:1;62038:14;;;;;61979:6;:74::i;:::-;62104:17;;61963:90;;62089:32;;;62068:17;;;:54;62155:14;62068:17;62155:5;:14::i;:::-;62139:30;-1:-1:-1;61890:448:0;;-1:-1:-1;61890:448:0;;-1:-1:-1;62231:17:0;;62216:32;;62278:48;62216:32;62301:8;62311:11;62323:1;62311:14;;;;;62278:10;:48::i;:::-;62264:62;;61890:448;62417:14;;62388:56;;62406:9;;62433:10;62388:17;:56::i;:::-;62526:14;;;;62510:53;;-1:-1:-1;;;62510:53:0;;-1:-1:-1;;;;;62510:38:0;;;;;;:53;;62549:13;;62510:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:58;62502:67;;;;;;62611:43;62627:11;62640:13;62611:15;:43::i;:::-;58687:42;-1:-1:-1;;;;;62667:37:0;;62713:4;62720:10;62760:7;:17;;;62779:10;62791:9;62802:11;62749:65;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;62667:148;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61112:1711;;;;;;;;;;:::o;49024:82::-;49064:42;49024:82;:::o;15388:87::-;15433:42;15388:87;:::o;48912:103::-;48972:42;48912:103;:::o;26627:684::-;26695:27;;:::i;:::-;26750:18;26783;26826:5;26815:32;;;;;;;;;;;;:::i;:::-;26735:112;;;;27011:5;27000:52;;;;;;;;;;;;:::i;:::-;26968:18;;;26860:192;26936:17;;;26860:192;-1:-1:-1;;;;;26860:192:0;;;26905:16;;;;26860:192;;;;;;;;27245:58;;;;;;;;;;;;;:::i;:::-;27207:15;;;27065:238;27176:16;;;27065:238;-1:-1:-1;;;;;27065:238:0;;;27141:20;;;27065:238;;27111:15;;;27065:238;27080:16;;;27065:238;-1:-1:-1;27080:7:0;;26627:684;-1:-1:-1;;26627:684:0:o;15298:83::-;15339:42;15298:83;:::o;59074:1719::-;59319:43;59331:11;59343:1;59331:14;;59319:43;59375:20;59406:16;:14;:16::i;:::-;59475:17;;;;59455;;59537:14;;59375:48;;-1:-1:-1;59455:37:0;;59434:18;;59520:47;;59561:4;59520:16;:47::i;:::-;59630:14;;59614:57;;-1:-1:-1;;;59614:57:0;;59505:62;;-1:-1:-1;;;;;;59614:48:0;;;;:57;;59505:62;;59614:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:62;59606:71;;;;;;59690:17;59710:33;59728:11;59690:17;59728:14;;59710:33;59690:53;-1:-1:-1;59754:19:0;59776:33;59794:11;59806:1;59794:14;;59776:33;59754:55;;59822:15;59871:11;-1:-1:-1;;;;;59858:24:0;:9;-1:-1:-1;;;;;59858:24:0;;59854:449;;59972:17;;59962:27;;59942:17;;;:47;60020:14;59942:17;60020:5;:14::i;:::-;60004:30;-1:-1:-1;60089:50:0;;-1:-1:-1;60004:30:0;60108:4;60114:8;60124:11;60136:1;60124:14;;60089:50;60075:64;;59854:449;;;-1:-1:-1;60196:17:0;;60186:27;;60243:48;60186:27;60266:8;60276:11;60288:1;60276:14;;60243:48;60229:62;;59854:449;60340:58;60352:10;60364:11;60376:1;60364:14;;;;60380:11;60393:4;60340:11;:58::i;:::-;60488:14;;60472:63;;-1:-1:-1;;;60472:63:0;;-1:-1:-1;;;;;60472:48:0;;;;;;:63;;60521:13;;60472:63;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:68;60464:77;;;;;;60583:41;60599:9;60610:13;60583:15;:41::i;:::-;58687:42;-1:-1:-1;;;;;60637:37:0;;60683:4;60690:10;60730:7;:17;;;60749:10;60761:9;60772:11;60719:65;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;60637:148;;;;;;;;;;;;;;;;;:::i;9023:120::-;9082:9;9134:1;9108:23;9112:11;9116:1;8712:6;9112:3;:11::i;:::-;9129:1;9125;:5;;9108:3;:23::i;:::-;:27;;;;;;;9023:120;-1:-1:-1;;;9023:120:0:o;7861:113::-;7954:5;;;7949:16;;;;7941:25;;;;;40586:337;40674:9;40685:4;40703:13;40718:19;;:::i;:::-;40741:31;40756:6;40764:7;40741:14;:31::i;:::-;40702:70;;-1:-1:-1;40702:70:0;-1:-1:-1;40794:18:0;40787:3;:25;;;;;;;;;40783:73;;-1:-1:-1;40837:3:0;-1:-1:-1;40842:1:0;;-1:-1:-1;40829:15:0;;40783:73;40876:18;40896;40905:8;40896;:18::i;:::-;40868:47;;;;;;40586:337;;;;;;:::o;54325:292::-;54445:16;;;54459:1;54445:16;;;54418:24;54445:16;;;;;54418:24;54445:16;;;;;;;;;;-1:-1:-1;54445:16:0;54418:43;;54485:15;54472:7;54480:1;54472:10;;;;;;;;;;;;;:28;-1:-1:-1;;;;;54472:28:0;;;-1:-1:-1;;;;;54472:28:0;;;;;54524:17;54511:7;54519:1;54511:10;;;;;;;;-1:-1:-1;;;;;54511:30:0;;;:10;;;;;;;;;;;:30;54554:55;;-1:-1:-1;;;54554:55:0;;49462:42;;54554:46;;:55;;54601:7;;54554:55;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;54554:55:0;;;;;;;;;;;;:::i;:::-;;54325:292;;;:::o;55555:157::-;55604:7;55624:13;55664:4;55624:47;;55691:5;-1:-1:-1;;;;;55691:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;55684:20;;;55555:157;:::o;55211:261::-;55280:7;-1:-1:-1;;;;;55304:30:0;;49375:42;55304:30;55300:165;;;-1:-1:-1;;;;;;;;;;;;55351:18:0;;55300:165;55425:14;-1:-1:-1;;;;;55409:42:0;;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;55402:51;;;;51270:1455;51442:52;;-1:-1:-1;;;51442:52:0;;51369:14;;49157:3;;49653:42;;51442:41;;:52;;51484:9;;51442:52;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51438:112;;;-1:-1:-1;49225:3:0;51438:112;51562:17;51582:30;51600:11;51582:17;:30::i;:::-;51629:45;;-1:-1:-1;;;51629:45:0;;51562:50;;-1:-1:-1;49064:42:0;;51629:38;;:45;;51668:5;;51629:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51625:134;;;51697:50;;-1:-1:-1;;;51697:50:0;;49064:42;;51697:43;;:50;;51741:5;;51697:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51691:56;;51625:134;51784:8;;51783:32;;51811:3;51801:7;:13;;;;;;51783:32;;;51796:1;51783:32;51771:44;-1:-1:-1;51832:13:0;;51828:482;;51862:14;49462:42;-1:-1:-1;;;;;51879:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51862:59;;51938:18;51983:6;-1:-1:-1;;;;;51959:50:0;;52010:11;51959:63;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51938:84;;52037:13;52077:6;-1:-1:-1;;;;;52053:50:0;;49375:42;52053:64;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52037:80;;52134:20;52157:29;52162:13;52177:8;52157:4;:29::i;:::-;52134:52;;52214:31;52219:8;52229:15;52214:4;:31::i;:::-;52203:42;;52274:24;52278:9;52289:8;52274:3;:24::i;:::-;52262:36;;51828:482;;;;;52403:1;52393:7;:11;52380:9;:25;52376:81;;;52444:1;52434:7;:11;52422:23;;52376:81;52477:18;48972:42;-1:-1:-1;;;;;52498:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52477:47;-1:-1:-1;;;;;;52541:24:0;;-1:-1:-1;;;;;;;;;;;52541:24:0;52537:181;;;52582:39;;-1:-1:-1;;;;;52582:28:0;;;:39;;;;;52611:9;;52582:39;;;;52611:9;52582:28;:39;;;;;;;;;;;;;;;;;;;;;52537:181;;;52654:52;-1:-1:-1;;;;;52654:29:0;;52684:10;52696:9;52654:29;:52::i;:::-;51270:1455;;;;;;;;;:::o;18357:1522::-;18541:16;;;;18618:14;;18418:7;;;;;;;;;;18541:16;-1:-1:-1;;;;;18618:35:0;-1:-1:-1;;;;;;;;;;;18618:35:0;18614:191;;;18701:14;;18687:29;;:13;:29::i;:::-;-1:-1:-1;;;;;18670:46:0;;;18774:16;;;;;18731:62;;-1:-1:-1;;;18731:62:0;;;;15054:42;;18731:36;;18774:16;18731:62;;;;;18670:14;;18731:62;;;;;;;18774:16;15054:42;18731:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18614:191;18884:14;;;;:18;18880:372;;18919:48;18934:6;:14;;;18950:6;:16;;;18919:14;:48::i;:::-;18984:14;19001:48;19016:6;:14;;;19032:6;:16;;;19001:14;:48::i;:::-;18984:65;;19102:45;19112:6;19120:9;19131:15;19102:9;:45::i;:::-;19064:83;;-1:-1:-1;19064:83:0;;-1:-1:-1;19064:83:0;-1:-1:-1;19164:77:0;;;;19206:6;:19;;;19196:29;;19164:77;18880:372;;19322:7;19317:129;;19361:34;19371:6;19379:15;19361:9;:34::i;:::-;19346:49;;19420:6;:14;;;19410:24;;19317:129;19497:39;19502:6;:15;;;19519:6;:16;;;19497:4;:39::i;:::-;19466:27;19477:6;:15;;;19466:10;:27::i;:::-;:70;;19458:109;;;;-1:-1:-1;;;19458:109:0;;;;;;;:::i;:::-;;;;;;;;;19675:1;19648:24;15054:42;19648:10;:24::i;:::-;:28;19644:185;;;19749:53;;-1:-1:-1;;;19749:53:0;;15054:42;;19693:37;;15054:42;;19749:38;;:53;;19796:4;;19749:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;19693:124;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19644:185;-1:-1:-1;19849:7:0;;-1:-1:-1;19858:12:0;-1:-1:-1;;18357:1522:0;;;:::o;53063:1023::-;53151:14;53178:17;53198:30;53216:11;53198:17;:30::i;:::-;53178:50;-1:-1:-1;53245:13:0;;53241:430;;53275:14;49462:42;-1:-1:-1;;;;;53292:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53275:59;;53351:18;53396:6;-1:-1:-1;;;;;53372:50:0;;53423:11;53372:63;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53351:84;;53450:13;53490:6;-1:-1:-1;;;;;53466:50:0;;49375:42;53466:64;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53450:80;;53547:20;53570:29;53575:13;53590:8;53570:4;:29::i;:::-;53547:52;;53628:31;53633:8;53643:15;53628:4;:31::i;:::-;53616:43;;53241:430;;;;;53764:1;53754:7;:11;53741:9;:25;53737:81;;;53805:1;53795:7;:11;53783:23;;53737:81;53838:18;48972:42;-1:-1:-1;;;;;53859:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53838:47;-1:-1:-1;;;;;;53902:24:0;;-1:-1:-1;;;;;;;;;;;53902:24:0;53898:181;;;53943:39;;-1:-1:-1;;;;;53943:28:0;;;:39;;;;;53972:9;;53943:39;;;;53972:9;53943:28;:39;;;;;;;;;;;;;;;;;;;;;53898:181;;;54015:52;-1:-1:-1;;;;;54015:29:0;;54045:10;54057:9;54015:29;:52::i;:::-;53063:1023;;;;;;;:::o;63061:398::-;63170:38;63184:10;63196:11;63170:13;:38::i;:::-;-1:-1:-1;;;;;63225:25:0;;-1:-1:-1;;;;;;;;;;;63225:25:0;63221:231;;63275:49;;-1:-1:-1;;;63275:49:0;;-1:-1:-1;;;;;63275:33:0;;;;;:49;;63309:14;;63275:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:54;63267:63;;;;;;63221:231;;;63379:11;-1:-1:-1;;;;;63363:33:0;;63404:14;63363:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63221:231;63061:398;;;:::o;63653:250::-;-1:-1:-1;;;;;63736:25:0;;-1:-1:-1;;;;;;;;;;;63736:25:0;63732:109;;63778:51;-1:-1:-1;;;;;63778:30:0;;63809:10;63821:7;63778:30;:51::i;:::-;63853:42;;:10;;63873:21;63853:42;;;;;;;;;63873:21;63853:10;:42;;;;;;;;;;;;;;;;;;;50109:806;50249:66;;-1:-1:-1;;;50249:66:0;;50232:14;;-1:-1:-1;;;;;50249:51:0;;;;;:66;;50309:4;;50249:66;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;50232:83;;50342:9;50332:7;:19;50328:295;;;-1:-1:-1;;;;;50372:27:0;;-1:-1:-1;;;;;;;;;;;50372:27:0;50368:208;;;50420:37;;-1:-1:-1;;;;;50420:14:0;;;50436:19;;;50420:37;;;;;;;;;50436:19;50420:14;:37;;;;;;;;;;;;;;;;;;;;;50368:208;;;50498:62;-1:-1:-1;;;;;50498:32:0;;50531:5;50539:19;;;50498:32;:62::i;:::-;50602:9;50592:19;;50328:295;50635:42;50649:12;50663:13;50635;:42::i;:::-;-1:-1:-1;;;;;50694:27:0;;-1:-1:-1;;;;;;;;;;;50694:27:0;50690:218;;;50754:13;-1:-1:-1;;;;;50738:42:0;;50788:7;50738:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50690:218;;;50839:51;;-1:-1:-1;;;50839:51:0;;-1:-1:-1;;;;;50839:42:0;;;;;:51;;50882:7;;50839:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:56;50831:65;;;;;;50109:806;;;;;:::o;7982:127::-;8040:9;8070:6;;;:30;;-1:-1:-1;;8085:5:0;;;8099:1;8094;8085:5;8094:1;8080:15;;;;;:20;8070:30;8062:39;;;;;7740:113;7833:5;;;7828:16;;;;7820:25;;;;;39855:620;39935:9;39946:10;;:::i;:::-;40253:14;40269;40287:25;36384:4;40305:6;40287:7;:25::i;:::-;40252:60;;-1:-1:-1;40252:60:0;-1:-1:-1;40335:18:0;40327:4;:26;;;;;;;;;40323:92;;-1:-1:-1;40384:18:0;;;;;;;;;-1:-1:-1;40384:18:0;;40378:4;;-1:-1:-1;40384:18:0;-1:-1:-1;40370:33:0;;40323:92;40432:35;40439:9;40450:7;:16;;;40432:6;:35::i;43351:213::-;43533:12;36384:4;43533:23;;;43351:213::o;5825:176::-;5907:86;5927:5;5957:23;;;5982:2;5986:5;5934:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;5934:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;5934:58:0;-1:-1:-1;;;;;;5934:58:0;;;;;;;;;;5907:19;:86::i;24916:142::-;24976:7;-1:-1:-1;;;;;25003:25:0;;-1:-1:-1;;;;;;;;;;;25003:25:0;:47;;25046:4;25003:47;;;15054:42;24996:54;24916:142;-1:-1:-1;;24916:142:0:o;15951:212::-;-1:-1:-1;;;;;16033:31:0;;-1:-1:-1;;;;;;;;;;;16033:31:0;16029:127;;16081:63;-1:-1:-1;;;;;16081:29:0;;15339:42;16136:7;16081:29;:63::i;:::-;15951:212;;:::o;25227:743::-;25311:7;-1:-1:-1;;;;;25410:24:0;;15054:42;25410:24;25406:58;;-1:-1:-1;25443:21:0;25436:28;;25406:58;25739:10;25715:21;:34;25711:81;;;25782:10;25758:21;:34;25751:41;;;;25711:81;-1:-1:-1;25941:21:0;25227:743;;;;:::o;21805:1602::-;21942:12;;;;22062:5;:24;;;;;;;;;22058:197;;;22103:53;22116:7;:16;;;22134:2;22138:7;:17;;;22103:12;:53::i;:::-;22058:197;;;22189:54;22202:7;:16;;;22220:2;22224:7;:18;;;22189:12;:54::i;:::-;22321:20;;;;22271:71;;-1:-1:-1;;;22271:71:0;;15433:42;;22271:49;;:71;;22321:20;22271:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22267:118;;;22372:1;22359:14;;22267:118;22397:20;22420:28;22431:7;:16;;;22420:10;:28::i;:::-;22508:20;;;;22465:64;;-1:-1:-1;;;22465:64:0;;22397:51;;-1:-1:-1;15433:42:0;;22465;;:64;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22461:221;;;22560:7;:20;;;-1:-1:-1;;;;;22560:25:0;22593:10;22605:7;:16;;;22560:62;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22546:76;;;;;22461:221;;;22665:5;22655:15;;22461:221;22750:17;;;;22694:20;;22780:565;;;;22909:15;;22898:27;;:10;:27::i;:::-;22992:16;;;;22885:40;;-1:-1:-1;;;;;;22992:37:0;-1:-1:-1;;;;;;;;;;;22992:37:0;22988:210;;;23110:53;;-1:-1:-1;;;23110:53:0;;15054:42;;23050:37;;15054:42;;23110:38;;:53;;23157:4;;23110:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23050:132;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22988:210;23321:12;23290:28;23301:7;:16;;;23290:10;:28::i;:::-;:43;23275:58;;22780:565;23374:12;;-1:-1:-1;23388:10:0;-1:-1:-1;;21805:1602:0;;;;;;;:::o;23673:742::-;23852:15;;;;23795:73;;-1:-1:-1;;;23795:73:0;;23757:17;;15247:42;;23795:56;;:73;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23787:106;;;;-1:-1:-1;;;23787:106:0;;;;;;;:::i;:::-;23972:15;;;;23989:17;;;;23942:15;;23906:13;;23936:71;;-1:-1:-1;;;;;23936:35:0;;;;;:71::i;:::-;24033:15;24024:5;:24;;;;;;;;;24020:388;;;24100:7;:15;;;-1:-1:-1;;;;;24080:63:0;;24151:8;24161:7;:15;;;24178:7;:16;;;24196:7;:17;;;24080:134;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24065:149;;24020:388;;;24282:7;:15;;;-1:-1:-1;;;;;24262:62:0;;24332:8;24342:7;:15;;;24359:7;:16;;;24377:7;:18;;;24262:134;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24247:149;;24020:388;23673:742;;;;;:::o;8763:122::-;8822:9;8712:6;8848:23;8852:9;8856:1;8859;8852:3;:9::i;:::-;8869:1;8712:6;8863:7;;15668:275;15731:12;-1:-1:-1;;;;;15760:31:0;;-1:-1:-1;;;;;;;;;;;15760:31:0;15756:180;;;-1:-1:-1;15818:21:0;15756:180;;;15882:42;;-1:-1:-1;;;15882:42:0;;-1:-1:-1;;;;;15882:27:0;;;;;:42;;15918:4;;15882:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;54833:201::-;-1:-1:-1;;;;;54921:25:0;;-1:-1:-1;;;;;;;;;;;54921:25:0;54917:110;;54963:52;-1:-1:-1;;;;;54963:29:0;;54993:11;-1:-1:-1;;54963:29:0;:52::i;34605:343::-;34661:9;;34693:6;34689:69;;-1:-1:-1;34724:18:0;;-1:-1:-1;34724:18:0;34716:30;;34689:69;34779:5;;;34783:1;34779;:5;:1;34801:5;;;;;:10;34797:144;;34836:26;34864:1;34828:38;;;;;;;34797:144;34907:18;;-1:-1:-1;34927:1:0;-1:-1:-1;34899:30:0;;36831:515;36892:9;36903:10;;:::i;:::-;36927:14;36943:20;36967:22;36975:3;36384:4;36967:7;:22::i;:::-;36926:63;;-1:-1:-1;36926:63:0;-1:-1:-1;37012:18:0;37004:4;:26;;;;;;;;;37000:92;;-1:-1:-1;37061:18:0;;;;;;;;;-1:-1:-1;37061:18:0;;37055:4;;-1:-1:-1;37061:18:0;-1:-1:-1;37047:33:0;;37000:92;37105:14;37121:13;37138:31;37146:15;37163:5;37138:7;:31::i;:::-;37104:65;;-1:-1:-1;37104:65:0;-1:-1:-1;37192:18:0;37184:4;:26;;;;;;;;;37180:92;;37235:4;37241:18;;;;;;;;37256:1;37241:18;;;37227:33;;;;;;;;;;37180:92;37312:25;;;;;;;;;;;;-1:-1:-1;;37312:25:0;;-1:-1:-1;36831:515:0;-1:-1:-1;;;;;;36831:515:0:o;7294:419::-;7376:23;7402:69;7430:4;7402:69;;;;;;;;;;;;;;;;;7410:5;-1:-1:-1;;;;;7402:27:0;;;:69;;;;;:::i;:::-;7486:17;;7376:95;;-1:-1:-1;7486:21:0;7482:224;;7628:10;7617:30;;;;;;;;;;;;:::i;:::-;7609:85;;;;-1:-1:-1;;;7609:85:0;;;;;;;:::i;6374:281::-;6460:86;6480:5;6510:22;;;6534:7;6543:1;6487:58;;;;;;;;;:::i;6460:86::-;6557:90;6577:5;6607:22;;;6631:7;6640:5;6584:62;;;;;;;;;:::i;24423:397::-;24532:6;24541:2;24532:11;24520:2;:9;:23;24516:104;;;24560:48;;-1:-1:-1;;;24560:48:0;;;;;;;:::i;24516:104::-;24779:15;;24686:2;24779:15;24772:30;24757:56::o;35043:215::-;35099:9;;35131:6;35127:77;;-1:-1:-1;35162:26:0;;-1:-1:-1;35190:1:0;35154:38;;35127:77;35224:18;35248:1;35244;:5;;;;;;35216:34;;;;35043:215;;;;;:::o;2218:196::-;2321:12;2353:53;2376:6;2384:4;2390:1;2393:12;2353:22;:53::i;:::-;2346:60;2218:196;-1:-1:-1;;;;2218:196:0:o;2980:979::-;3110:12;3143:18;3154:6;3143:10;:18::i;:::-;3135:60;;;;-1:-1:-1;;;3135:60:0;;;;;;;:::i;:::-;3269:12;3283:23;3310:6;-1:-1:-1;;;;;3310:11:0;3330:8;3341:4;3310:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3268:78;;;;3361:7;3357:595;;;3392:10;-1:-1:-1;3385:17:0;;-1:-1:-1;3385:17:0;3357:595;3506:17;;:21;3502:439;;3769:10;3763:17;3830:15;3817:10;3813:2;3809:19;3802:44;3717:148;3912:12;3905:20;;-1:-1:-1;;;3905:20:0;;;;;;;;:::i;1005:619::-;1065:4;1533:20;;1376:66;1573:23;;;;;;:42;;-1:-1:-1;;1600:15:0;;;1565:51;-1:-1:-1;;1005:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;:::i;1102:616::-;;1217:3;1210:4;1202:6;1198:17;1194:27;1184:2;;-1:-1;;1225:12;1184:2;1278:78;29821:17;1278:78;:::i;:::-;1269:87;;1362:16;1421:17;1479:3;29821:17;1454:3;1450:27;1447:36;1444:2;;;1496:1;;1486:12;1444:2;1521:1;1506:206;1259:4;1528:1;1525:13;1506:206;;;5253:20;;1599:50;;29833:4;1663:14;;;;1691;;;;1553:1;1546:9;1506:206;;;1510:14;;;1177:541;;;;:::o;2610:440::-;;2711:3;2704:4;2696:6;2692:17;2688:27;2678:2;;-1:-1;;2719:12;2678:2;2766:6;2753:20;2788:64;2803:48;2844:6;2803:48;:::i;:::-;2788:64;:::i;:::-;2779:73;;2872:6;2865:5;2858:21;2976:3;2908:4;2967:6;2900;2958:16;;2955:25;2952:2;;;2993:1;;2983:12;2952:2;33742:6;2908:4;2900:6;2896:17;2908:4;2934:5;2930:16;33719:30;33798:1;33780:16;;;2908:4;33780:16;33773:27;2934:5;2671:379;-1:-1;;2671:379::o;3059:442::-;;3171:3;3164:4;3156:6;3152:17;3148:27;3138:2;;-1:-1;;3179:12;3138:2;3219:6;3213:13;3241:64;3256:48;3297:6;3256:48;:::i;3241:64::-;3232:73;;3325:6;3318:5;3311:21;3429:3;3361:4;3420:6;3353;3411:16;;3408:25;3405:2;;;3446:1;;3436:12;3405:2;3456:39;3488:6;3361:4;3387:5;3383:16;3361:4;3353:6;3349:17;3456:39;:::i;3553:1626::-;;3672:6;;3660:9;3655:3;3651:19;3647:32;3644:2;;;-1:-1;;3682:12;3644:2;3710:22;3672:6;3710:22;:::i;:::-;3701:31;;;3817:49;3862:3;3838:22;3817:49;:::i;:::-;3799:16;3792:75;3965:49;4010:3;3932:2;3990:9;3986:22;3965:49;:::i;:::-;3932:2;3951:5;3947:16;3940:75;4081:2;4139:9;4135:22;5253:20;4081:2;4100:5;4096:16;4089:75;4231:2;4289:9;4285:22;5253:20;4231:2;4250:5;4246:16;4239:75;4379:3;4438:9;4434:22;5253:20;4379:3;4399:5;4395:16;4388:75;4561:49;4606:3;4527;4586:9;4582:22;4561:49;:::i;:::-;4527:3;4547:5;4543:16;4536:75;4714:49;4759:3;4680;4739:9;4735:22;4714:49;:::i;:::-;4680:3;4700:5;4696:16;4689:75;4857:3;4846:9;4842:19;4829:33;4882:18;4874:6;4871:30;4868:2;;;3785:1;;4904:12;4868:2;4949:58;5003:3;4994:6;4983:9;4979:22;4949:58;:::i;:::-;4857:3;4935:5;4931:16;4924:84;;5072:3;;5133:9;5129:22;5253:20;5072:3;5092:5;5088:18;5081:77;;3638:1541;;;;:::o;5464:263::-;;5579:2;5567:9;5558:7;5554:23;5550:32;5547:2;;;-1:-1;;5585:12;5547:2;226:6;220:13;238:33;265:5;238:33;:::i;:::-;5637:74;5541:186;-1:-1;;;5541:186::o;5734:704::-;;;;;5916:3;5904:9;5895:7;5891:23;5887:33;5884:2;;;-1:-1;;5923:12;5884:2;375:6;369:13;387:41;422:5;387:41;:::i;:::-;6094:2;6152:22;;369:13;5975:82;;-1:-1;387:41;369:13;387:41;:::i;:::-;6221:2;6271:22;;5401:13;6340:2;6390:22;;;5401:13;5878:560;;6102:82;;-1:-1;5878:560;-1:-1;;;5878:560::o;6445:366::-;;;6566:2;6554:9;6545:7;6541:23;6537:32;6534:2;;;-1:-1;;6572:12;6534:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6624:63;-1:-1;6724:2;6763:22;;72:20;97:33;72:20;97:33;:::i;:::-;6732:63;;;;6528:283;;;;;:::o;6818:392::-;;6958:2;;6946:9;6937:7;6933:23;6929:32;6926:2;;;-1:-1;;6964:12;6926:2;7015:17;7009:24;7053:18;7045:6;7042:30;7039:2;;;-1:-1;;7075:12;7039:2;7162:22;;1865:4;1853:17;;1849:27;-1:-1;1839:2;;-1:-1;;1880:12;1839:2;1920:6;1914:13;1942:80;1957:64;2014:6;1957:64;:::i;1942:80::-;2050:21;;;2107:14;;;;2082:17;;;2196;;;2187:27;;;;2184:36;-1:-1;2181:2;;;-1:-1;;2223:12;2181:2;-1:-1;2249:10;;2243:217;2268:6;2265:1;2262:13;2243:217;;;5401:13;;2336:61;;2290:1;2283:9;;;;;2411:14;;;;2439;;2243:217;;;-1:-1;7095:99;6920:290;-1:-1;;;;;;;6920:290::o;7217:257::-;;7329:2;7317:9;7308:7;7304:23;7300:32;7297:2;;;-1:-1;;7335:12;7297:2;2555:6;2549:13;34541:5;32538:13;32531:21;34519:5;34516:32;34506:2;;-1:-1;;34552:12;7481:393;;;7610:2;7598:9;7589:7;7585:23;7581:32;7578:2;;;-1:-1;;7616:12;7578:2;2555:6;2549:13;34541:5;32538:13;32531:21;34519:5;34516:32;34506:2;;-1:-1;;34552:12;34506:2;7776;7826:22;;;;5401:13;7668:71;;5401:13;;-1:-1;;;7572:302::o;7881:345::-;;7994:2;7982:9;7973:7;7969:23;7965:32;7962:2;;;-1:-1;;8000:12;7962:2;8058:17;8045:31;8096:18;8088:6;8085:30;8082:2;;;-1:-1;;8118:12;8082:2;8148:62;8202:7;8193:6;8182:9;8178:22;8148:62;:::i;8233:593::-;;;8383:2;8371:9;8362:7;8358:23;8354:32;8351:2;;;-1:-1;;8389:12;8351:2;8440:17;8434:24;8478:18;;8470:6;8467:30;8464:2;;;-1:-1;;8500:12;8464:2;8530:73;8595:7;8586:6;8575:9;8571:22;8530:73;:::i;:::-;8520:83;;8661:2;8650:9;8646:18;8640:25;8626:39;;8478:18;8677:6;8674:30;8671:2;;;-1:-1;;8707:12;8671:2;;8737:73;8802:7;8793:6;8782:9;8778:22;8737:73;:::i;:::-;8727:83;;;8345:481;;;;;:::o;8833:387::-;;8967:2;8955:9;8946:7;8942:23;8938:32;8935:2;;;-1:-1;;8973:12;8935:2;9031:17;9018:31;9069:18;9061:6;9058:30;9055:2;;;-1:-1;;9091:12;9055:2;9121:83;9196:7;9187:6;9176:9;9172:22;9121:83;:::i;9227:856::-;;;;;9458:3;9446:9;9437:7;9433:23;9429:33;9426:2;;;-1:-1;;9465:12;9426:2;9523:17;9510:31;9561:18;9553:6;9550:30;9547:2;;;-1:-1;;9583:12;9547:2;9613:83;9688:7;9679:6;9668:9;9664:22;9613:83;:::i;:::-;9603:93;;;9733:2;574:3;555:17;9799:9;555:17;551:27;541:2;;-1:-1;;582:12;541:2;616:4;635:78;650:62;616:4;650:62;:::i;635:78::-;719:16;9733:2;9799:9;9795:22;807:27;9799:9;807:27;836:3;807:27;804:36;801:2;;;-1:-1;;843:12;801:2;-1:-1;863:206;616:4;885:1;882:13;863:206;;;968:37;1001:3;989:10;968:37;:::i;:::-;956:50;;1020:14;;;;1048;;;;910:1;903:9;863:206;;;-1:-1;9741:86;;-1:-1;;5253:20;;-1:-1;9991:76;;-1:-1;10059:7;;-1:-1;;9972:3;10035:22;;9991:76;:::i;:::-;9981:86;;9420:663;;;;;;;:::o;10090:263::-;;10205:2;10193:9;10184:7;10180:23;10176:32;10173:2;;;-1:-1;;10211:12;10173:2;-1:-1;5401:13;;10167:186;-1:-1;10167:186::o;10360:938::-;;;;;;10568:3;10556:9;10547:7;10543:23;10539:33;10536:2;;;-1:-1;;10575:12;10536:2;5407:6;5401:13;10627:74;;10738:2;10800:9;10796:22;369:13;387:41;422:5;387:41;:::i;:::-;10865:2;10923:22;;369:13;10746:82;;-1:-1;387:41;369:13;387:41;:::i;:::-;11013:2;10998:18;;10992:25;10873:82;;-1:-1;11037:18;11026:30;;11023:2;;;-1:-1;;11059:12;11023:2;11089:73;11154:7;11145:6;11134:9;11130:22;11089:73;:::i;:::-;11079:83;;;11199:3;11254:9;11250:22;5401:13;11208:74;;10530:768;;;;;;;;:::o;11305:535::-;;;;11454:2;11442:9;11433:7;11429:23;11425:32;11422:2;;;-1:-1;;11460:12;11422:2;5407:6;5401:13;11512:74;;11623:2;11677:9;11673:22;5401:13;11631:74;;11742:2;11796:9;11792:22;5401:13;11750:74;;11416:424;;;;;:::o;12178:103::-;-1:-1;;;;;32626:54;12239:37;;12233:48::o;13137:323::-;;13269:5;31011:12;31555:6;31550:3;31543:19;13352:52;13397:6;31592:4;31587:3;31583:14;31592:4;13378:5;13374:16;13352:52;:::i;:::-;34175:7;34159:14;-1:-1;;34155:28;13416:39;;;;31592:4;13416:39;;13217:243;-1:-1;;13217:243::o;19295:271::-;;13977:5;31011:12;14088:52;14133:6;14128:3;14121:4;14114:5;14110:16;14088:52;:::i;:::-;14152:16;;;;;19429:137;-1:-1;;19429:137::o;19573:222::-;-1:-1;;;;;32626:54;;;;12239:37;;19700:2;19685:18;;19671:124::o;20047:866::-;-1:-1;;;;;32626:54;;;12108:58;;32626:54;;20546:2;20531:18;;12108:58;20365:3;20583:2;20568:18;;20561:48;;;15077:2;20350:19;;;31543;-1:-1;;;32637:42;31583:14;;15093:36;15148:12;20787:2;20772:18;;20765:48;;;20047:866;;20827:76;;15148:12;;20889:6;20827:76;:::i;:::-;20819:84;20336:577;-1:-1;;;;;20336:577::o;20920:866::-;-1:-1;;;;;32626:54;;;12108:58;;32626:54;;21419:2;21404:18;;12108:58;21238:3;21456:2;21441:18;;21434:48;;;16063:2;21223:19;;;31543;-1:-1;;;32637:42;31583:14;;16079:36;16134:12;21660:2;21645:18;;21638:48;;;20920:866;;21700:76;;16134:12;;21762:6;21700:76;:::i;21793:444::-;-1:-1;;;;;32626:54;;;12239:37;;32626:54;;;;22140:2;22125:18;;12239:37;22223:2;22208:18;;19126:37;;;;21976:2;21961:18;;21947:290::o;22244:556::-;-1:-1;;;;;32626:54;;;12239:37;;32626:54;;;;22620:2;22605:18;;12239:37;22703:2;22688:18;;19126:37;22786:2;22771:18;;19126:37;;;;22455:3;22440:19;;22426:374::o;22807:345::-;-1:-1;;;;;32626:54;;;;12239:37;;32842:4;32831:16;23138:2;23123:18;;14430:56;22968:2;22953:18;;22939:213::o;23159:333::-;-1:-1;;;;;32626:54;;;;12239:37;;23478:2;23463:18;;19126:37;23314:2;23299:18;;23285:207::o;23499:370::-;23676:2;23690:47;;;31011:12;;23661:18;;;31543:19;;;23499:370;;23676:2;30865:14;;;;31583;;;;23499:370;12847:260;12872:6;12869:1;12866:13;12847:260;;;12933:13;;-1:-1;;;;;32626:54;12239:37;;31398:14;;;;12001;;;;4882:18;12887:9;12847:260;;;-1:-1;23743:116;;23647:222;-1:-1;;;;;;23647:222::o;23876:306::-;;24021:2;24042:17;24035:47;24096:76;24021:2;24010:9;24006:18;24158:6;24096:76;:::i;24189:501::-;;24380:2;24401:17;24394:47;24455:76;24380:2;24369:9;24365:18;24517:6;24455:76;:::i;:::-;24579:9;24573:4;24569:20;24564:2;24553:9;24549:18;24542:48;24604:76;24675:4;24666:6;24604:76;:::i;25283:416::-;25483:2;25497:47;;;15399:2;25468:18;;;31543:19;-1:-1;;;31583:14;;;15415:43;15477:12;;;25454:245::o;25706:416::-;25906:2;25920:47;;;15728:2;25891:18;;;31543:19;15764:28;31583:14;;;15744:49;15812:12;;;25877:245::o;26129:416::-;26329:2;26343:47;;;16385:2;26314:18;;;31543:19;16421:34;31583:14;;;16401:55;-1:-1;;;16476:12;;;16469:30;16518:12;;;26300:245::o;26552:416::-;26752:2;26766:47;;;16769:2;26737:18;;;31543:19;16805:31;31583:14;;;16785:52;16856:12;;;26723:245::o;26975:416::-;27175:2;27189:47;;;17107:2;27160:18;;;31543:19;17143:34;31583:14;;;17123:55;-1:-1;;;17198:12;;;17191:34;17244:12;;;27146:245::o;27398:390::-;;27585:2;27606:17;27599:47;17616:63;27585:2;27574:9;27570:18;17593:16;17587:23;17616:63;:::i;:::-;27585:2;17755:5;17751:16;17745:23;17774:63;17822:14;27574:9;17822:14;17808:12;17774:63;:::i;:::-;;17822:14;17914:5;17910:16;17904:23;17981:14;27574:9;17981:14;19126:37;17981:14;18074:5;18070:16;18064:23;18141:14;27574:9;18141:14;19126:37;18141:14;18232:5;18228:16;18222:23;18299:14;27574:9;18299:14;19126:37;18299:14;18389:5;18385:16;18379:23;18408:63;18456:14;27574:9;18456:14;18442:12;18408:63;:::i;:::-;;18456:14;18551:5;18547:16;18541:23;18570:63;18618:14;27574:9;18618:14;18604:12;18570:63;:::i;:::-;;18618:14;18709:5;18705:16;18699:23;17516:6;18742:14;17516:6;18742:14;27574:9;18742:14;18735:38;18788:71;17507:16;27574:9;17507:16;18840:12;18788:71;:::i;:::-;18936:18;;18930:25;19009:16;;19126:37;;;;-1:-1;18780:79;;27556:232;-1:-1;27556:232::o;27795:222::-;19126:37;;;27922:2;27907:18;;27893:124::o;28024:752::-;19126:37;;;-1:-1;;;;;32626:54;;;28446:2;28431:18;;12239:37;32626:54;;28529:2;28514:18;;12239:37;32637:42;28566:2;28551:18;;28544:48;;;28024:752;;28606:76;;28266:19;;28668:6;28606:76;:::i;:::-;28598:84;;19156:5;28761:3;28750:9;28746:19;19126:37;28252:524;;;;;;;;:::o;28783:556::-;19126:37;;;29159:2;29144:18;;19126:37;;;;-1:-1;;;;;32626:54;;;29242:2;29227:18;;12239:37;32626:54;29325:2;29310:18;;12239:37;28994:3;28979:19;;28965:374::o;29346:256::-;29408:2;29402:9;29434:17;;;29509:18;29494:34;;29530:22;;;29491:62;29488:2;;;29566:1;;29556:12;29488:2;29408;29575:22;29386:216;;-1:-1;29386:216::o;29609:244::-;;29766:18;29758:6;29755:30;29752:2;;;-1:-1;;29788:12;29752:2;-1:-1;29833:4;29821:17;;29689:164::o;30111:304::-;;30270:18;30262:6;30259:30;30256:2;;;-1:-1;;30292:12;30256:2;-1:-1;30337:4;30325:17;;;30390:15;;30193:222::o;30422:321::-;;30565:18;30557:6;30554:30;30551:2;;;-1:-1;;30587:12;30551:2;-1:-1;34175:7;30641:17;-1:-1;;30637:33;30728:4;30718:15;;30488:255::o;33815:268::-;33880:1;33887:101;33901:6;33898:1;33895:13;33887:101;;;33968:11;;;33962:18;33949:11;;;33942:39;33923:2;33916:10;33887:101;;;34003:6;34000:1;33997:13;33994:2;;;-1:-1;;33880:1;34050:16;;34043:27;33864:219::o;34196:117::-;-1:-1;;;;;32626:54;;34255:35;;34245:2;;34304:1;;34294:12;34245:2;34239:74;:::o
Swarm Source
ipfs://fa32ed6546b976aa37636d2fb21e72bea7b15ac045cd20bee8b92d3f7e19b39b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.