Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
CompoundFlashLoanTaker
Compiler Version
v0.6.10+commit.00c0fcaf
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-08-26 */ /** *Submitted for verification at Etherscan.io on 2020-08-18 */ pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; interface ERC20 { function totalSupply() external view returns (uint256 supply); function balanceOf(address _owner) external view returns (uint256 balance); function transfer(address _to, uint256 _value) external returns (bool success); function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success); function allowance(address _owner, address _spender) external view returns (uint256 remaining); function decimals() external view returns (uint256 digits); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } abstract contract GasTokenInterface is ERC20 { function free(uint256 value) public virtual returns (bool success); function freeUpTo(uint256 value) public virtual returns (uint256 freed); function freeFrom(address from, uint256 value) public virtual returns (bool success); function freeFromUpTo(address from, uint256 value) public virtual returns (uint256 freed); } contract GasBurner { // solhint-disable-next-line const-name-snakecase GasTokenInterface public constant gasToken = GasTokenInterface(0x0000000000b3F879cb30FE243b4Dfee438691c04); modifier burnGas(uint _amount) { if (gasToken.balanceOf(address(this)) >= _amount) { gasToken.free(_amount); } _; } } abstract contract ILendingPool { function flashLoan( address payable _receiver, address _reserve, uint _amount, bytes calldata _params) external virtual; function deposit(address _reserve, uint256 _amount, uint16 _referralCode) external virtual payable; function setUserUseReserveAsCollateral(address _reserve, bool _useAsCollateral) external virtual; function borrow(address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode) external virtual; function repay( address _reserve, uint256 _amount, address payable _onBehalfOf) external virtual payable; function swapBorrowRateMode(address _reserve) external virtual; function getReserves() external virtual view returns(address[] memory); /// @param _reserve underlying token address function getReserveData(address _reserve) external virtual view returns ( uint256 totalLiquidity, // reserve total liquidity uint256 availableLiquidity, // reserve available liquidity for borrowing uint256 totalBorrowsStable, // total amount of outstanding borrows at Stable rate uint256 totalBorrowsVariable, // total amount of outstanding borrows at Variable rate uint256 liquidityRate, // current deposit APY of the reserve for depositors, in Ray units. uint256 variableBorrowRate, // current variable rate APY of the reserve pool, in Ray units. uint256 stableBorrowRate, // current stable rate APY of the reserve pool, in Ray units. uint256 averageStableBorrowRate, // current average stable borrow rate uint256 utilizationRate, // expressed as total borrows/total liquidity. uint256 liquidityIndex, // cumulative liquidity index uint256 variableBorrowIndex, // cumulative variable borrow index address aTokenAddress, // aTokens contract address for the specific _reserve uint40 lastUpdateTimestamp // timestamp of the last update of reserve data ); /// @param _user users address function getUserAccountData(address _user) external virtual view returns ( uint256 totalLiquidityETH, // user aggregated deposits across all the reserves. In Wei uint256 totalCollateralETH, // user aggregated collateral across all the reserves. In Wei uint256 totalBorrowsETH, // user aggregated outstanding borrows across all the reserves. In Wei uint256 totalFeesETH, // user aggregated current outstanding fees in ETH. In Wei uint256 availableBorrowsETH, // user available amount to borrow in ETH uint256 currentLiquidationThreshold, // user current average liquidation threshold across all the collaterals deposited uint256 ltv, // user average Loan-to-Value between all the collaterals uint256 healthFactor // user current Health Factor ); /// @param _reserve underlying token address /// @param _user users address function getUserReserveData(address _reserve, address _user) external virtual view returns ( uint256 currentATokenBalance, // user current reserve aToken balance uint256 currentBorrowBalance, // user current reserve outstanding borrow balance uint256 principalBorrowBalance, // user balance of borrowed asset uint256 borrowRateMode, // user borrow rate mode either Stable or Variable uint256 borrowRate, // user current borrow rate APY uint256 liquidityRate, // user current earn rate on _reserve uint256 originationFee, // user outstanding loan origination fee uint256 variableBorrowIndex, // user variable cumulative index uint256 lastUpdateTimestamp, // Timestamp of the last data update bool usageAsCollateralEnabled // Whether the user's current reserve is enabled as a collateral ); function getReserveConfigurationData(address _reserve) external virtual view returns ( uint256 ltv, uint256 liquidationThreshold, uint256 liquidationBonus, address rateStrategyAddress, bool usageAsCollateralEnabled, bool borrowingEnabled, bool stableBorrowRateEnabled, bool isActive ); // ------------------ LendingPoolCoreData ------------------------ function getReserveATokenAddress(address _reserve) public virtual view returns (address); function getReserveConfiguration(address _reserve) external virtual view returns (uint256, uint256, uint256, bool); function getUserUnderlyingAssetBalance(address _reserve, address _user) public virtual view returns (uint256); function getReserveCurrentLiquidityRate(address _reserve) public virtual view returns (uint256); function getReserveCurrentVariableBorrowRate(address _reserve) public virtual view returns (uint256); function getReserveTotalLiquidity(address _reserve) public virtual view returns (uint256); function getReserveAvailableLiquidity(address _reserve) public virtual view returns (uint256); function getReserveTotalBorrowsVariable(address _reserve) public virtual view returns (uint256); // ---------------- LendingPoolDataProvider --------------------- function calculateUserGlobalData(address _user) public virtual view returns ( uint256 totalLiquidityBalanceETH, uint256 totalCollateralBalanceETH, uint256 totalBorrowBalanceETH, uint256 totalFeesETH, uint256 currentLtv, uint256 currentLiquidationThreshold, uint256 healthFactor, bool healthFactorBelowThreshold ); } 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); } library Address { function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(ERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. */ function safeApprove(ERC20 token, address spender, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function _callOptionalReturn(ERC20 token, bytes memory data) private { bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } contract AdminAuth { using SafeERC20 for ERC20; address public owner; address public admin; modifier onlyOwner() { require(owner == msg.sender); _; } constructor() public { owner = msg.sender; } /// @notice Admin is set by owner first time, after that admin is super role and has permission to change owner /// @param _admin Address of multisig that becomes admin function setAdminByOwner(address _admin) public { require(msg.sender == owner); require(admin == address(0)); admin = _admin; } /// @notice Admin is able to set new admin /// @param _admin Address of multisig that becomes new admin function setAdminByAdmin(address _admin) public { require(msg.sender == admin); admin = _admin; } /// @notice Admin is able to change owner /// @param _owner Address of new owner function setOwnerByAdmin(address _owner) public { require(msg.sender == admin); owner = _owner; } /// @notice Destroy the contract function kill() public onlyOwner { selfdestruct(payable(owner)); } /// @notice withdraw stuck funds function withdrawStuckFunds(address _token, uint _amount) public onlyOwner { if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { payable(owner).transfer(_amount); } else { ERC20(_token).safeTransfer(owner, _amount); } } } contract ZrxAllowlist is AdminAuth { mapping (address => bool) public zrxAllowlist; function setAllowlistAddr(address _zrxAddr, bool _state) public onlyOwner { zrxAllowlist[_zrxAddr] = _state; } function isZrxAddr(address _zrxAddr) public view returns (bool) { return zrxAllowlist[_zrxAddr]; } } contract Discount { address public owner; mapping(address => CustomServiceFee) public serviceFees; uint256 constant MAX_SERVICE_FEE = 400; struct CustomServiceFee { bool active; uint256 amount; } constructor() public { owner = msg.sender; } function isCustomFeeSet(address _user) public view returns (bool) { return serviceFees[_user].active; } function getCustomServiceFee(address _user) public view returns (uint256) { return serviceFees[_user].amount; } function setServiceFee(address _user, uint256 _fee) public { require(msg.sender == owner, "Only owner"); require(_fee >= MAX_SERVICE_FEE || _fee == 0); serviceFees[_user] = CustomServiceFee({active: true, amount: _fee}); } function disableServiceFee(address _user) public { require(msg.sender == owner, "Only owner"); serviceFees[_user] = CustomServiceFee({active: false, amount: 0}); } } contract SaverExchangeHelper { using SafeERC20 for ERC20; address public constant KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address payable public constant WALLET_ID = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08; address public constant DISCOUNT_ADDRESS = 0x1b14E8D511c9A4395425314f849bD737BAF8208F; address public constant SAVER_EXCHANGE_REGISTRY = 0x25dd3F51e0C3c3Ff164DDC02A8E4D65Bb9cBB12D; address public constant ERC20_PROXY_0X = 0x95E6F48254609A6ee006F7D493c8e5fB97094ceF; address public constant ZRX_ALLOWLIST_ADDR = 0x019739e288973F92bDD3c1d87178E206E51fd911; function getDecimals(address _token) internal view returns (uint256) { if (_token == KYBER_ETH_ADDRESS) return 18; return ERC20(_token).decimals(); } function getBalance(address _tokenAddr) internal view returns (uint balance) { if (_tokenAddr == KYBER_ETH_ADDRESS) { balance = address(this).balance; } else { balance = ERC20(_tokenAddr).balanceOf(address(this)); } } function approve0xProxy(address _tokenAddr, uint _amount) internal { if (_tokenAddr != KYBER_ETH_ADDRESS) { ERC20(_tokenAddr).safeApprove(address(ERC20_PROXY_0X), _amount); } } function sendLeftover(address _srcAddr, address _destAddr, address payable _to) internal { // send back any leftover ether or tokens if (address(this).balance > 0) { _to.transfer(address(this).balance); } if (getBalance(_srcAddr) > 0) { ERC20(_srcAddr).safeTransfer(_to, getBalance(_srcAddr)); } if (getBalance(_destAddr) > 0) { ERC20(_destAddr).safeTransfer(_to, getBalance(_destAddr)); } } function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) { require(bs.length >= start + 32, "slicing out of range"); uint256 x; assembly { x := mload(add(bs, add(0x20, start))) } return x; } } contract SaverExchangeRegistry is AdminAuth { mapping(address => bool) private wrappers; constructor() public { wrappers[0x880A845A85F843a5c67DB2061623c6Fc3bB4c511] = true; wrappers[0x4c9B55f2083629A1F7aDa257ae984E03096eCD25] = true; wrappers[0x42A9237b872368E1bec4Ca8D26A928D7d39d338C] = true; } function addWrapper(address _wrapper) public onlyOwner { wrappers[_wrapper] = true; } function removeWrapper(address _wrapper) public onlyOwner { wrappers[_wrapper] = false; } function isWrapper(address _wrapper) public view returns(bool) { return wrappers[_wrapper]; } } contract SaverExchangeCore is SaverExchangeHelper, DSMath { // first is empty to keep the legacy order in place enum ExchangeType { _, OASIS, KYBER, UNISWAP, ZEROX } enum ActionType { SELL, BUY } struct ExchangeData { address srcAddr; address destAddr; uint srcAmount; uint destAmount; uint minPrice; address wrapper; address exchangeAddr; bytes callData; uint256 price0x; } /// @notice Internal method that preforms a sell on 0x/on-chain /// @dev Usefull for other DFS contract to integrate for exchanging /// @param exData Exchange data struct /// @return (address, uint) Address of the wrapper used and destAmount function _sell(ExchangeData memory exData) internal returns (address, uint) { address wrapper; uint swapedTokens; bool success; uint tokensLeft = exData.srcAmount; // if selling eth, convert to weth if (exData.srcAddr == KYBER_ETH_ADDRESS) { exData.srcAddr = ethToWethAddr(exData.srcAddr); TokenInterface(WETH_ADDRESS).deposit.value(exData.srcAmount)(); } // Try 0x first and then fallback on specific wrapper if (exData.price0x > 0) { approve0xProxy(exData.srcAddr, exData.srcAmount); (success, swapedTokens, tokensLeft) = takeOrder(exData, address(this).balance, ActionType.SELL); if (success) { wrapper = exData.exchangeAddr; } } // fallback to desired wrapper if 0x failed if (!success) { swapedTokens = saverSwap(exData, ActionType.SELL); wrapper = exData.wrapper; } require(getBalance(exData.destAddr) >= wmul(exData.minPrice, exData.srcAmount), "Final amount isn't correct"); // if anything is left in weth, pull it to user as eth if (getBalance(WETH_ADDRESS) > 0) { TokenInterface(WETH_ADDRESS).withdraw( TokenInterface(WETH_ADDRESS).balanceOf(address(this)) ); } return (wrapper, swapedTokens); } /// @notice Takes order from 0x and returns bool indicating if it is successful /// @param _exData Exchange data /// @param _ethAmount Ether fee needed for 0x order function takeOrder( ExchangeData memory _exData, uint256 _ethAmount, ActionType _type ) private returns (bool success, uint256, uint256) { // write in the exact amount we are selling/buing in an order if (_type == ActionType.SELL) { writeUint256(_exData.callData, 36, _exData.srcAmount); } else { writeUint256(_exData.callData, 36, _exData.destAmount); } if (ZrxAllowlist(ZRX_ALLOWLIST_ADDR).isZrxAddr(_exData.exchangeAddr)) { (success, ) = _exData.exchangeAddr.call{value: _ethAmount}(_exData.callData); } else { success = false; } uint256 tokensSwaped = 0; uint256 tokensLeft = _exData.srcAmount; if (success) { // check to see if any _src tokens are left over after exchange tokensLeft = getBalance(_exData.srcAddr); // convert weth -> eth if needed if (_exData.destAddr == KYBER_ETH_ADDRESS) { TokenInterface(WETH_ADDRESS).withdraw( TokenInterface(WETH_ADDRESS).balanceOf(address(this)) ); } // get the current balance of the swaped tokens tokensSwaped = getBalance(_exData.destAddr); } return (success, tokensSwaped, tokensLeft); } /// @notice Calls wraper contract for exchage to preform an on-chain swap /// @param _exData Exchange data struct /// @param _type Type of action SELL|BUY /// @return swapedTokens For Sell that the destAmount, for Buy thats the srcAmount function saverSwap(ExchangeData memory _exData, ActionType _type) internal returns (uint swapedTokens) { require(SaverExchangeRegistry(SAVER_EXCHANGE_REGISTRY).isWrapper(_exData.wrapper), "Wrapper is not valid"); uint ethValue = 0; ERC20(_exData.srcAddr).safeTransfer(_exData.wrapper, _exData.srcAmount); if (_type == ActionType.SELL) { swapedTokens = ExchangeInterfaceV2(_exData.wrapper). sell{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.srcAmount); } else { swapedTokens = ExchangeInterfaceV2(_exData.wrapper). buy{value: ethValue}(_exData.srcAddr, _exData.destAddr, _exData.destAmount); } } function writeUint256(bytes memory _b, uint256 _index, uint _input) internal pure { if (_b.length < _index + 32) { revert("Incorrent lengt while writting bytes32"); } bytes32 input = bytes32(_input); _index += 32; // Read the bytes32 from array memory assembly { mstore(add(_b, _index), input) } } /// @notice Converts Kybers Eth address -> Weth /// @param _src Input address function ethToWethAddr(address _src) internal pure returns (address) { return _src == KYBER_ETH_ADDRESS ? WETH_ADDRESS : _src; } function packExchangeData(ExchangeData memory _exData) public pure returns(bytes memory) { // splitting in two different bytes and encoding all because of stack too deep in decoding part bytes memory part1 = abi.encode( _exData.srcAddr, _exData.destAddr, _exData.srcAmount, _exData.destAmount ); bytes memory part2 = abi.encode( _exData.minPrice, _exData.wrapper, _exData.exchangeAddr, _exData.callData, _exData.price0x ); return abi.encode(part1, part2); } // solhint-disable-next-line no-empty-blocks receive() external virtual payable {} } contract DefisaverLogger { event LogEvent( address indexed contractAddress, address indexed caller, string indexed logName, bytes data ); // solhint-disable-next-line func-name-mixedcase function Log(address _contract, address _caller, string memory _logName, bytes memory _data) public { emit LogEvent(_contract, _caller, _logName, _data); } } abstract contract 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 CTokenInterface is ERC20 { function mint(uint256 mintAmount) external virtual returns (uint256); // function mint() external virtual payable; function accrueInterest() public virtual returns (uint); function redeem(uint256 redeemTokens) external virtual returns (uint256); function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256); function borrow(uint256 borrowAmount) external virtual returns (uint256); function repayBorrow(uint256 repayAmount) external virtual returns (uint256); function repayBorrow() external virtual payable; function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256); function repayBorrowBehalf(address borrower) external virtual payable; function liquidateBorrow(address borrower, uint256 repayAmount, address cTokenCollateral) external virtual returns (uint256); function liquidateBorrow(address borrower, address cTokenCollateral) external virtual payable; function exchangeRateCurrent() external virtual returns (uint256); function supplyRatePerBlock() external virtual returns (uint256); function borrowRatePerBlock() external virtual returns (uint256); function totalReserves() external virtual returns (uint256); function reserveFactorMantissa() external virtual returns (uint256); function borrowBalanceCurrent(address account) external virtual returns (uint256); function totalBorrowsCurrent() external virtual returns (uint256); function getCash() external virtual returns (uint256); function balanceOfUnderlying(address owner) external virtual returns (uint256); function underlying() external virtual returns (address); function getAccountSnapshot(address account) external virtual view returns (uint, uint, uint, uint); } abstract contract ComptrollerInterface { function enterMarkets(address[] calldata cTokens) external virtual returns (uint256[] memory); function exitMarket(address cToken) external virtual returns (uint256); function getAssetsIn(address account) external virtual view returns (address[] memory); function markets(address account) public virtual view returns (bool, uint256); function getAccountLiquidity(address account) external virtual view returns (uint256, uint256, uint256); function claimComp(address holder) virtual public; function oracle() public virtual view returns (address); } abstract contract 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 halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } /** * @dev Creates an exponential from numerator and denominator values. * Note: Returns an error if (`num` * 10e18) > MAX_INT, * or if `denom` is zero. */ function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint rational) = divUInt(scaledNumerator, denom); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: rational})); } /** * @dev Adds two exponentials, returning a new exponential. */ function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Subtracts two exponentials, returning a new exponential. */ function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Multiply an Exp by a scalar, returning a new Exp. */ function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(product)); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return addUInt(truncate(product), addend); } /** * @dev Divide an Exp by a scalar, returning a new Exp. */ function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); } /** * @dev Divide a scalar by an Exp, returning a new Exp. */ function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { /* We are doing this as: getExp(mulUInt(expScale, scalar), divisor.mantissa) How it works: Exp = a / b; Scalar = s; `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` */ (MathError err0, uint numerator) = mulUInt(expScale, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return getExp(numerator, divisor.mantissa); } /** * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. */ function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(fraction)); } /** * @dev Multiplies two exponentials, returning a new exponential. */ function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } // We add half the scale before dividing so that we get rounding instead of truncation. // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. assert(err2 == MathError.NO_ERROR); return (MathError.NO_ERROR, Exp({mantissa: product})); } /** * @dev Multiplies two exponentials given their mantissas, returning a new exponential. */ function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); } /** * @dev Multiplies three exponentials, returning a new exponential. */ function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { (MathError err, Exp memory ab) = mulExp(a, b); if (err != MathError.NO_ERROR) { return (err, ab); } return mulExp(ab, c); } /** * @dev Divides two exponentials, returning a new exponential. * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) */ function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { return getExp(a.mantissa, b.mantissa); } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } } /// @title Utlity functions for Compound contracts contract CompoundSaverHelper is DSMath, Exponential { using SafeERC20 for ERC20; address payable public constant WALLET_ADDR = 0x322d58b9E75a6918f7e7849AEe0fF09369977e08; address public constant DISCOUNT_ADDR = 0x1b14E8D511c9A4395425314f849bD737BAF8208F; uint public constant SERVICE_FEE = 400; // 0.25% Fee address public constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address public constant CETH_ADDRESS = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5; address public constant COMPTROLLER = 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; address public constant COMPOUND_LOGGER = 0x3DD0CDf5fFA28C6847B4B276e2fD256046a44bb7; /// @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 = 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; } if (tokenAddr == ETH_ADDRESS) { WALLET_ADDR.transfer(feeAmount); } else { ERC20(tokenAddr).safeTransfer(WALLET_ADDR, 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; } if (tokenAddr == ETH_ADDRESS) { WALLET_ADDR.transfer(feeAmount); } else { ERC20(tokenAddr).safeTransfer(WALLET_ADDR, 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 } } /// @title Contract that implements repay/boost functionality contract CompoundSaverProxy is CompoundSaverHelper, SaverExchangeCore { DefisaverLogger public constant logger = DefisaverLogger(0x5c55B921f590a89C1Ebe84dF170E655a82b62126); /// @notice Withdraws collateral, converts to borrowed token and repays debt /// @dev Called through the DSProxy /// @param _exData Exchange data /// @param _cAddresses Coll/Debt addresses [cCollAddress, cBorrowAddress] /// @param _gasCost Gas cost for specific transaction function repay( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost ) public payable { enterMarket(_cAddresses[0], _cAddresses[1]); address payable user = payable(getUserAddress()); uint maxColl = getMaxCollateral(_cAddresses[0], address(this)); uint collAmount = (_exData.srcAmount > maxColl) ? maxColl : _exData.srcAmount; require(CTokenInterface(_cAddresses[0]).redeemUnderlying(collAmount) == 0); address collToken = getUnderlyingAddr(_cAddresses[0]); address borrowToken = getUnderlyingAddr(_cAddresses[1]); uint swapAmount = 0; if (collToken != borrowToken) { (, swapAmount) = _sell(_exData); swapAmount -= getFee(swapAmount, user, _gasCost, _cAddresses[1]); } else { swapAmount = collAmount; swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]); } paybackDebt(swapAmount, _cAddresses[1], borrowToken, user); // handle 0x fee user.transfer(address(this).balance); // log amount, collToken, borrowToken logger.Log(address(this), msg.sender, "CompoundRepay", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken)); } /// @notice Borrows token, converts to collateral, and adds to position /// @dev Called through the DSProxy /// @param _exData Exchange data /// @param _cAddresses Coll/Debt addresses [cCollAddress, cBorrowAddress] /// @param _gasCost Gas cost for specific transaction function boost( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost ) public payable { enterMarket(_cAddresses[0], _cAddresses[1]); address payable user = payable(getUserAddress()); uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this)); uint borrowAmount = (_exData.srcAmount > maxBorrow) ? maxBorrow : _exData.srcAmount; require(CTokenInterface(_cAddresses[1]).borrow(borrowAmount) == 0); address collToken = getUnderlyingAddr(_cAddresses[0]); address borrowToken = getUnderlyingAddr(_cAddresses[1]); uint swapAmount = 0; if (collToken != borrowToken) { borrowAmount -= getFee(borrowAmount, user, _gasCost, _cAddresses[1]); _exData.srcAmount = borrowAmount; (,swapAmount) = _sell(_exData); } else { swapAmount = borrowAmount; swapAmount -= getGasCost(swapAmount, _gasCost, _cAddresses[1]); } approveCToken(collToken, _cAddresses[0]); if (collToken != ETH_ADDRESS) { require(CTokenInterface(_cAddresses[0]).mint(swapAmount) == 0); } else { CEtherInterface(_cAddresses[0]).mint{value: swapAmount}(); // reverts on fail } // handle 0x fee user.transfer(address(this).balance); // log amount, collToken, borrowToken logger.Log(address(this), msg.sender, "CompoundBoost", abi.encode(_exData.srcAmount, swapAmount, collToken, borrowToken)); } } abstract contract DSGuard { function canCall(address src_, address dst_, bytes4 sig) public view virtual returns (bool); function permit(bytes32 src, bytes32 dst, bytes32 sig) public virtual; function forbid(bytes32 src, bytes32 dst, bytes32 sig) public virtual; function permit(address src, address dst, bytes32 sig) public virtual; function forbid(address src, address dst, bytes32 sig) public virtual; } abstract contract DSGuardFactory { function newGuard() public virtual returns (DSGuard guard); } contract ProxyPermission { address public constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7; /// @notice Called in the context of DSProxy to authorize an address /// @param _contractAddr Address which will be authorized function givePermission(address _contractAddr) public { address currAuthority = address(DSAuth(address(this)).authority()); DSGuard guard = DSGuard(currAuthority); if (currAuthority == address(0)) { guard = DSGuardFactory(FACTORY_ADDRESS).newGuard(); DSAuth(address(this)).setAuthority(DSAuthority(address(guard))); } guard.permit(_contractAddr, address(this), bytes4(keccak256("execute(address,bytes)"))); } /// @notice Called in the context of DSProxy to remove authority of an address /// @param _contractAddr Auth address which will be removed from authority list function removePermission(address _contractAddr) public { address currAuthority = address(DSAuth(address(this)).authority()); // if there is no authority, that means that contract doesn't have permission if (currAuthority == address(0)) { return; } DSGuard guard = DSGuard(currAuthority); guard.forbid(_contractAddr, address(this), bytes4(keccak256("execute(address,bytes)"))); } } /// @title Entry point for the FL Repay Boosts, called by DSProxy contract CompoundFlashLoanTaker is CompoundSaverProxy, ProxyPermission, GasBurner { ILendingPool public constant lendingPool = ILendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); address payable public constant COMPOUND_SAVER_FLASH_LOAN = 0x0ed294340b6328647A652207AA72902747C84c94; /// @notice Repays the position with it's own fund or with FL if needed /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress] /// @param _gasCost Gas cost for specific transaction function repayWithLoan( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost ) public payable burnGas(25) { uint maxColl = getMaxCollateral(_cAddresses[0], address(this)); if (_exData.srcAmount <= maxColl) { repay(_exData, _cAddresses, _gasCost); } else { // 0x fee COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value); uint loanAmount = (_exData.srcAmount - maxColl); bytes memory encoded = packExchangeData(_exData); bytes memory paramsData = abi.encode(encoded, _cAddresses, _gasCost, true, address(this)); givePermission(COMPOUND_SAVER_FLASH_LOAN); lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[0]), loanAmount, paramsData); removePermission(COMPOUND_SAVER_FLASH_LOAN); logger.Log(address(this), msg.sender, "CompoundFlashRepay", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[0])); } } /// @notice Boosts the position with it's own fund or with FL if needed /// @param _exData Exchange data /// @param _cAddresses cTokens addreses and exchange [cCollAddress, cBorrowAddress, exchangeAddress] /// @param _gasCost Gas cost for specific transaction function boostWithLoan( ExchangeData memory _exData, address[2] memory _cAddresses, // cCollAddress, cBorrowAddress uint256 _gasCost ) public payable burnGas(20) { uint maxBorrow = getMaxBorrow(_cAddresses[1], address(this)); if (_exData.srcAmount <= maxBorrow) { boost(_exData, _cAddresses, _gasCost); } else { // 0x fee COMPOUND_SAVER_FLASH_LOAN.transfer(msg.value); uint loanAmount = (_exData.srcAmount - maxBorrow); bytes memory paramsData = abi.encode(packExchangeData(_exData), _cAddresses, _gasCost, false, address(this)); givePermission(COMPOUND_SAVER_FLASH_LOAN); lendingPool.flashLoan(COMPOUND_SAVER_FLASH_LOAN, getUnderlyingAddr(_cAddresses[1]), loanAmount, paramsData); removePermission(COMPOUND_SAVER_FLASH_LOAN); logger.Log(address(this), msg.sender, "CompoundFlashBoost", abi.encode(loanAmount, _exData.srcAmount, _cAddresses[1])); } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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":"COMPOUND_SAVER_FLASH_LOAN","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMPTROLLER","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":"FACTORY_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":"SAVER_EXCHANGE_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SERVICE_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WALLET_ADDR","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WALLET_ID","outputs":[{"internalType":"address payable","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":[{"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"}],"name":"boost","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"}],"name":"boostWithLoan","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gasToken","outputs":[{"internalType":"contract GasTokenInterface","name":"","type":"address"}],"stateMutability":"view","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":[{"internalType":"address","name":"_contractAddr","type":"address"}],"name":"givePermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lendingPool","outputs":[{"internalType":"contract ILendingPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","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"}],"name":"packExchangeData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_contractAddr","type":"address"}],"name":"removePermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"price0x","type":"uint256"}],"internalType":"struct SaverExchangeCore.ExchangeData","name":"_exData","type":"tuple"},{"internalType":"address[2]","name":"_cAddresses","type":"address[2]"},{"internalType":"uint256","name":"_gasCost","type":"uint256"}],"name":"repay","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"}],"name":"repayWithLoan","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b50613c1b806100206000396000f3fe6080604052600436106101bb5760003560e01c80635f82c67e116100ec578063a734f06e1161008a578063d3661fa511610064578063d3661fa5146102c6578063e074bb47146103ed578063f24ccbfe1461040d578063f708847b14610422576101c2565b8063a734f06e14610247578063c91d59fe146103c3578063d0cc7289146103d8576101c2565b80638823151b116100c65780638823151b146103845780638c8a795814610399578063a46a66c91461036f578063a59a9973146103ae576101c2565b80635f82c67e14610347578063745ce7c11461035c5780637b925ab11461036f576101c2565b806339af24ae116101595780634595f535116101335780634595f535146102db5780634ab45d33146102f057806350c86de514610305578063534859071461031a576101c2565b806339af24ae146102915780633d391f70146102a657806344169752146102c6576101c2565b80631ec18ec0116101955780631ec18ec01461021a57806329f7fc9e146102475780632b6e65811461025c578063314b63321461027c576101c2565b8063040141e5146101c7578063099a8653146101f25780630edec02614610207576101c2565b366101c257005b600080fd5b3480156101d357600080fd5b506101dc610435565b6040516101e99190613634565b60405180910390f35b6102056102003660046134e2565b61044d565b005b6102056102153660046134e2565b610697565b34801561022657600080fd5b5061023a61023536600461338e565b610995565b6040516101e99190613a8d565b34801561025357600080fd5b506101dc610bcc565b34801561026857600080fd5b5061023a61027736600461338e565b610bde565b34801561028857600080fd5b506101dc610f6f565b34801561029d57600080fd5b506101dc610f87565b3480156102b257600080fd5b506102056102c136600461334f565b610f9f565b3480156102d257600080fd5b506101dc61117f565b3480156102e757600080fd5b506101dc611197565b3480156102fc57600080fd5b506101dc6111af565b34801561031157600080fd5b5061023a6111c7565b34801561032657600080fd5b5061033a6103353660046134af565b6111cd565b6040516101e991906138bc565b34801561035357600080fd5b506101dc611272565b61020561036a3660046134e2565b61128a565b34801561037b57600080fd5b506101dc6115c8565b34801561039057600080fd5b506101dc6115e0565b3480156103a557600080fd5b506101dc6115f8565b3480156103ba57600080fd5b506101dc611610565b3480156103cf57600080fd5b506101dc611628565b3480156103e457600080fd5b506101dc61163b565b3480156103f957600080fd5b5061020561040836600461334f565b611653565b34801561041957600080fd5b506101dc611701565b6102056104303660046134e2565b611719565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104668260005b60200201518360016020020151611a4c565b6000610470611b53565b9050600061048584825b602002015130610bde565b905060008186604001511161049e5785604001516104a0565b815b855160405163852a12e360e01b81529192506001600160a01b03169063852a12e3906104d0908490600401613a8d565b602060405180830381600087803b1580156104ea57600080fd5b505af11580156104fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105229190613585565b1561052c57600080fd5b600061053e86825b6020020151611bd0565b9050600061054d876001610534565b905060006001600160a01b038381169083161461058c5761056d89611c86565b915061058590508187898b60015b6020020151611ee8565b90036105a4565b50826105a181888a60015b60200201516122a8565b90035b6105b78189600160200201518489612526565b6040516001600160a01b038716904780156108fc02916000818181858888f193505050501580156105ec573d6000803e3d6000fd5b50735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338c6040015185888860405160200161062d9493929190613af9565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161065a939291906136f8565b600060405180830381600087803b15801561067457600080fd5b505af1158015610688573d6000803e3d6000fd5b50505050505050505050505050565b6106a2826000610454565b60006106ac611b53565b905060006106c28460015b602002015130610995565b90506000818660400151116106db5785604001516106dd565b815b602086015160405163317afabb60e21b81529192506001600160a01b03169063c5ebeaec90610710908490600401613a8d565b602060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107629190613585565b1561076c57600080fd5b60006107788682610534565b90506000610787876001610534565b905060006001600160a01b03838116908316146107c9576107ac8487898b600161057b565b90930360408901819052926107c089611c86565b91506107db9050565b50826107d881888a6001610597565b90035b87516107e8908490612737565b6001600160a01b038316600080516020613bc68339815191521461089657875160405163140e25ad60e31b81526001600160a01b039091169063a0712d6890610835908490600401613a8d565b602060405180830381600087803b15801561084f57600080fd5b505af1158015610863573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108879190613585565b1561089157600080fd5b6108f2565b87600060200201516001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156108d857600080fd5b505af11580156108ec573d6000803e3d6000fd5b50505050505b6040516001600160a01b038716904780156108fc02916000818181858888f19350505050158015610927573d6000803e3d6000fd5b50735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338c604001518588886040516020016109689493929190613af9565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161065a939291906136a7565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906109d1908690600401613634565b60606040518083038186803b1580156109e957600080fd5b505afa1580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a21919061359d565b509150506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015610a7457600080fd5b505afa158015610a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aac9190613372565b9050846001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ae957600080fd5b505af1158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b219190613585565b5060405163fc57d4df60e01b81526000906001600160a01b0383169063fc57d4df90610b51908990600401613634565b60206040518083038186803b158015610b6957600080fd5b505afa158015610b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba19190613585565b90506000610baf8483612775565b9050610bbf816064815b046127a6565b9450505050505b92915050565b600080516020613bc683398151915281565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c7990610c1a908690600401613634565b60606040518083038186803b158015610c3257600080fd5b505afa158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a919061359d565b509150506000846001600160a01b0316633af9e669856040518263ffffffff1660e01b8152600401610c9c9190613634565b602060405180830381600087803b158015610cb657600080fd5b505af1158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee9190613585565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015610d3f57600080fd5b505afa158015610d53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d779190613372565b905082610d8857509150610bc69050565b856001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610dc357600080fd5b505af1158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190613585565b50604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b90610e36908a90600401613634565b604080518083038186803b158015610e4d57600080fd5b505afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e85919061347e565b915050610e9061320b565b5060408051602081019091528181526000610eab86836127b6565b9150506000846001600160a01b031663fc57d4df8b6040518263ffffffff1660e01b8152600401610edc9190613634565b60206040518083038186803b158015610ef457600080fd5b505afa158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c9190613585565b90506000610f3a8383612775565b905086811115610f54578698505050505050505050610bc6565b610f6081606481610bb9565b9b9a5050505050505050505050565b7325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d81565b733dd0cdf5ffa28c6847b4b276e2fd256046a44bb781565b6000306001600160a01b031663bf7e214f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fda57600080fd5b505afa158015610fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110129190613372565b9050806001600160a01b03811661110357735a15566417e6c1c9546523066500bddbc53f88c76001600160a01b03166365688cc96040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561107257600080fd5b505af1158015611086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110aa9190613372565b604051637a9e5e4b60e01b81529091503090637a9e5e4b906110d0908490600401613634565b600060405180830381600087803b1580156110ea57600080fd5b505af11580156110fe573d6000803e3d6000fd5b505050505b806001600160a01b031663cbeea68c843060405161112090613612565b6040519081900381206001600160e01b031960e086901b1682526111489392916004016137dc565b600060405180830381600087803b15801561116257600080fd5b505af1158015611176573d6000803e3d6000fd5b50505050505050565b73322d58b9e75a6918f7e7849aee0ff09369977e0881565b730ed294340b6328647a652207aa72902747c84c9481565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b61019081565b60608082600001518360200151846040015185606001516040516020016111f7949392919061382d565b60408051601f1981840301815290829052608085015160a086015160c087015160e08801516101008901519496506060956112359590602001613a96565b6040516020818303038152906040529050818160405160200161125992919061393c565b604051602081830303815290604052925050505b919050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516370a0823160e01b815260199081906eb3f879cb30fe243b4dfee438691c04906370a08231906112c1903090600401613634565b60206040518083038186803b1580156112d957600080fd5b505afa1580156112ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113119190613585565b1061139c5760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390611348908490600401613a8d565b602060405180830381600087803b15801561136257600080fd5b505af1158015611376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139a919061345e565b505b60006113a8848261047a565b9050808560400151116113c5576113c085858561044d565b6115c1565b604051730ed294340b6328647a652207aa72902747c84c94903480156108fc02916000818181858888f19350505050158015611405573d6000803e3d6000fd5b5060408501518190036060611419876111cd565b905060608187876001306040516020016114379594939291906138cf565b6040516020818303038152906040529050611465730ed294340b6328647a652207aa72902747c84c94610f9f565b73398ec7346dcd622edc5ae82352f02be94c62d119635cffe9de730ed294340b6328647a652207aa72902747c84c9461149f8a6000610534565b86856040518563ffffffff1660e01b81526004016114c0949392919061379f565b600060405180830381600087803b1580156114da57600080fd5b505af11580156114ee573d6000803e3d6000fd5b5050505061150f730ed294340b6328647a652207aa72902747c84c94611653565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033868c604001518c60006002811061154757fe5b602002015160405160200161155e93929190613ada565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161158b93929190613749565b600060405180830381600087803b1580156115a557600080fd5b505af11580156115b9573d6000803e3d6000fd5b505050505050505b5050505050565b731b14e8d511c9a4395425314f849bd737baf8208f81565b735a15566417e6c1c9546523066500bddbc53f88c781565b73019739e288973f92bdd3c1d87178e206e51fd91181565b73398ec7346dcd622edc5ae82352f02be94c62d11981565b6eb3f879cb30fe243b4dfee438691c0481565b7395e6f48254609a6ee006f7d493c8e5fb97094cef81565b6000306001600160a01b031663bf7e214f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561168e57600080fd5b505afa1580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190613372565b90506001600160a01b0381166116dc57506116fe565b6000819050806001600160a01b0316632bc3217d843060405161112090613612565b50565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040516370a0823160e01b815260149081906eb3f879cb30fe243b4dfee438691c04906370a0823190611750903090600401613634565b60206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190613585565b1061182b5760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f3906117d7908490600401613a8d565b602060405180830381600087803b1580156117f157600080fd5b505af1158015611805573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611829919061345e565b505b60006118388460016106b7565b905080856040015111611850576113c0858585610697565b604051730ed294340b6328647a652207aa72902747c84c94903480156108fc02916000818181858888f19350505050158015611890573d6000803e3d6000fd5b50604085015181900360606118a4876111cd565b86866000306040516020016118bd9594939291906138cf565b60405160208183030381529060405290506118eb730ed294340b6328647a652207aa72902747c84c94610f9f565b73398ec7346dcd622edc5ae82352f02be94c62d119635cffe9de730ed294340b6328647a652207aa72902747c84c94611925896001610534565b85856040518563ffffffff1660e01b8152600401611946949392919061379f565b600060405180830381600087803b15801561196057600080fd5b505af1158015611974573d6000803e3d6000fd5b50505050611995730ed294340b6328647a652207aa72902747c84c94611653565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033858b604001518b6001600281106119cd57fe5b60200201516040516020016119e493929190613ada565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401611a1193929190613648565b600060405180830381600087803b158015611a2b57600080fd5b505af1158015611a3f573d6000803e3d6000fd5b5050505050505050505050565b60408051600280825260608083018452926020830190803683370190505090508281600081518110611a7a57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508181600181518110611aa857fe5b6001600160a01b0390921660209283029190910190910152604051631853304760e31b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063c299823890611af790849060040161386f565b600060405180830381600087803b158015611b1157600080fd5b505af1158015611b25573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b4d91908101906133c6565b50505050565b600080309050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9257600080fd5b505afa158015611ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bca9190613372565b91505090565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed51415611c0c5750600080516020613bc683398151915261126d565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611c4757600080fd5b505af1158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7f9190613372565b905061126d565b604081015181516000918291829182918291906001600160a01b0316600080516020613bc68339815191521415611d38578651611cc29061280a565b6001600160a01b031687526040808801518151630d0e30db60e41b8152915173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29263d0e30db09291600480830192600092919082900301818588803b158015611d1e57600080fd5b505af1158015611d32573d6000803e3d6000fd5b50505050505b61010087015115611d7757611d558760000151886040015161284b565b611d6187476000612897565b90945090925090508115611d77578660c0015193505b81611d9157611d87876000612b1b565b92508660a0015193505b611da387608001518860400151612d39565b611db08860200151612d61565b1015611dd75760405162461bcd60e51b8152600401611dce9061398f565b60405180910390fd5b6000611df673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d61565b1115611edc576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a0823190611e3b903090600401613634565b602060405180830381600087803b158015611e5557600080fd5b505af1158015611e69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8d9190613585565b6040518263ffffffff1660e01b8152600401611ea99190613a8d565b600060405180830381600087803b158015611ec357600080fd5b505af1158015611ed7573d6000803e3d6000fd5b505050505b50919350915050915091565b600061019081611ef784611bd0565b604051632cdc77ab60e21b8152909150731b14e8d511c9a4395425314f849bd737baf8208f9063b371deac90611f31908990600401613634565b60206040518083038186803b158015611f4957600080fd5b505afa158015611f5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f81919061345e565b1561201057604051636eeb543160e01b8152731b14e8d511c9a4395425314f849bd737baf8208f90636eeb543190611fbd908990600401613634565b60206040518083038186803b158015611fd557600080fd5b505afa158015611fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200d9190613585565b91505b81156120255781878161201f57fe5b04612028565b60005b925084156121f8576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561207f57600080fd5b505afa158015612093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b79190613372565b90506000816001600160a01b031663fc57d4df876040518263ffffffff1660e01b81526004016120e79190613634565b60206040518083038186803b1580156120ff57600080fd5b505afa158015612113573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121379190613585565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b815260040161217b9190613634565b60206040518083038186803b15801561219357600080fd5b505afa1580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613585565b905060006121d98383612775565b90506121e58982612775565b98506121f1878a612e05565b9650505050505b6005870483111561220a576005870492505b6001600160a01b038116600080516020613bc683398151915214156122705760405173322d58b9e75a6918f7e7849aee0ff09369977e089084156108fc029085906000818181858888f1935050505015801561226a573d6000803e3d6000fd5b5061229e565b61229e6001600160a01b03821673322d58b9e75a6918f7e7849aee0ff09369977e088563ffffffff612e1516565b5050949350505050565b6000806122b483611bd0565b90508315612478576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561230b57600080fd5b505afa15801561231f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123439190613372565b90506000816001600160a01b031663fc57d4df866040518263ffffffff1660e01b81526004016123739190613634565b60206040518083038186803b15801561238b57600080fd5b505afa15801561239f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c39190613585565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b81526004016124079190613634565b60206040518083038186803b15801561241f57600080fd5b505afa158015612433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124579190613585565b905060006124658383612775565b90506124718882612775565b9550505050505b6005850482111561248a576005850491505b6001600160a01b038116600080516020613bc683398151915214156124f05760405173322d58b9e75a6918f7e7849aee0ff09369977e089083156108fc029084906000818181858888f193505050501580156124ea573d6000803e3d6000fd5b5061251e565b61251e6001600160a01b03821673322d58b9e75a6918f7e7849aee0ff09369977e088463ffffffff612e1516565b509392505050565b6040516305eff7ef60e21b81526000906001600160a01b038516906317bfdfbc90612555903090600401613634565b602060405180830381600087803b15801561256f57600080fd5b505af1158015612583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a79190613585565b90508085111561262d576001600160a01b038316600080516020613bc6833981519152141561260d576040516001600160a01b0383169082870380156108fc02916000818181858888f19350505050158015612607573d6000803e3d6000fd5b50612629565b6126296001600160a01b0384168383880363ffffffff612e1516565b8094505b6126378385612737565b6001600160a01b038316600080516020613bc683398151915214156126af57836001600160a01b0316634e4d9fea866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561269157600080fd5b505af11580156126a5573d6000803e3d6000fd5b50505050506115c1565b60405163073a938160e11b81526001600160a01b03851690630e752702906126db908890600401613a8d565b602060405180830381600087803b1580156126f557600080fd5b505af1158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d9190613585565b156115c157600080fd5b6001600160a01b038216600080516020613bc683398151915214612771576127716001600160a01b0383168260001963ffffffff612e7016565b5050565b60008161279761278d85670de0b6b3a7640000612e8f565b6002855b04612e05565b8161279e57fe5b049392505050565b80820382811115610bc657600080fd5b60008060006127c361320b565b6127cd8686612eb3565b909250905060008260038111156127e057fe5b146127f15750915060009050612803565b60006127fc82612f12565b9350935050505b9250929050565b60006001600160a01b038216600080516020613bc6833981519152146128305781610bc6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292915050565b6001600160a01b038216600080516020613bc683398151915214612771576127716001600160a01b0383167395e6f48254609a6ee006f7d493c8e5fb97094cef8363ffffffff612e7016565b60008080808460018111156128a857fe5b14156128c7576128c28660e0015160248860400151612f21565b6128db565b6128db8660e0015160248860600151612f21565b60c08601516040516302f5cc7960e11b815273019739e288973f92bdd3c1d87178e206e51fd911916305eb98f2916129169190600401613634565b60206040518083038186803b15801561292e57600080fd5b505afa158015612942573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612966919061345e565b156129d9578560c001516001600160a01b0316858760e0015160405161298c91906135f6565b60006040518083038185875af1925050503d80600081146129c9576040519150601f19603f3d011682016040523d82523d6000602084013e6129ce565b606091505b5050809350506129de565b600092505b60408601516000908415612b0d5787516129f790612d61565b60208901519091506001600160a01b0316600080516020613bc68339815191521415612afd576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a0823190612a5c903090600401613634565b602060405180830381600087803b158015612a7657600080fd5b505af1158015612a8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aae9190613585565b6040518263ffffffff1660e01b8152600401612aca9190613a8d565b600060405180830381600087803b158015612ae457600080fd5b505af1158015612af8573d6000803e3d6000fd5b505050505b612b0a8860200151612d61565b91505b909250905093509350939050565b60a082015160405163e0aa279760e01b81526000917325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d9163e0aa279791612b5891600401613634565b60206040518083038186803b158015612b7057600080fd5b505afa158015612b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba8919061345e565b612bc45760405162461bcd60e51b8152600401611dce90613961565b60a083015160408401518451600092612bee926001600160a01b039092169163ffffffff612e1516565b6000836001811115612bfc57fe5b1415612c9c578360a001516001600160a01b031663cae270b6828660000151876020015188604001516040518563ffffffff1660e01b8152600401612c4393929190613809565b6020604051808303818588803b158015612c5c57600080fd5b505af1158015612c70573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612c959190613585565b9150612d32565b8360a001516001600160a01b031663153e66e6828660000151876020015188606001516040518563ffffffff1660e01b8152600401612cdd93929190613809565b6020604051808303818588803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612d2f9190613585565b91505b5092915050565b6000670de0b6b3a7640000612797612d518585612e8f565b6002670de0b6b3a7640000612791565b60006001600160a01b038216600080516020613bc68339815191521415612d8957504761126d565b6040516370a0823160e01b81526001600160a01b038316906370a0823190612db5903090600401613634565b60206040518083038186803b158015612dcd57600080fd5b505afa158015612de1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc69190613585565b80820182811015610bc657600080fd5b612e6b8363a9059cbb60e01b8484604051602401612e34929190613856565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f4d565b505050565b612e6b8363095ea7b360e01b8484604051602401612e34929190613856565b6000811580612eaa57505080820282828281612ea757fe5b04145b610bc657600080fd5b6000612ebd61320b565b600080612ed2670de0b6b3a764000087612fdc565b90925090506000826003811115612ee557fe5b14612f0457506040805160208101909152600081529092509050612803565b6127fc81866000015161301b565b51670de0b6b3a7640000900490565b8160200183511015612f455760405162461bcd60e51b8152600401611dce906139c6565b910160200152565b6060612fa2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130cc9092919063ffffffff16565b805190915015612e6b5780806020019051810190612fc0919061345e565b612e6b5760405162461bcd60e51b8152600401611dce90613a43565b60008083612fef57506000905080612803565b83830283858281612ffc57fe5b041461301057506002915060009050612803565b600092509050612803565b600061302561320b565b60008061303a86670de0b6b3a7640000612fdc565b9092509050600082600381111561304d57fe5b1461306c57506040805160208101909152600081529092509050612803565b60008061307983886130e3565b9092509050600082600381111561308c57fe5b146130af5781604051806020016040528060008152509550955050505050612803565b604080516020810190915290815260009890975095505050505050565b60606130db848460008561310e565b949350505050565b600080826130f75750600190506000612803565b600083858161310257fe5b04915091509250929050565b6060613119856131d2565b6131355760405162461bcd60e51b8152600401611dce90613a0c565b60006060866001600160a01b0316858760405161315291906135f6565b60006040518083038185875af1925050503d806000811461318f576040519150601f19603f3d011682016040523d82523d6000602084013e613194565b606091505b509150915081156131a85791506130db9050565b8051156131b85780518082602001fd5b8360405162461bcd60e51b8152600401611dce91906138bc565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906130db575050151592915050565b6040518060200160405280600081525090565b8035610bc681613bb0565b600082601f830112613239578081fd5b813567ffffffffffffffff81111561324f578182fd5b613262601f8201601f1916602001613b20565b915080825283602082850101111561327957600080fd5b8060208401602084013760009082016020015292915050565b60006101208083850312156132a5578182fd5b6132ae81613b20565b9150506132bb838361321e565b81526132ca836020840161321e565b60208201526040820135604082015260608201356060820152608082013560808201526132fa8360a0840161321e565b60a082015261330c8360c0840161321e565b60c082015260e082013567ffffffffffffffff81111561332b57600080fd5b61333784828501613229565b60e08301525061010080830135818301525092915050565b600060208284031215613360578081fd5b813561336b81613bb0565b9392505050565b600060208284031215613383578081fd5b815161336b81613bb0565b600080604083850312156133a0578081fd5b82356133ab81613bb0565b915060208301356133bb81613bb0565b809150509250929050565b600060208083850312156133d8578182fd5b825167ffffffffffffffff8111156133ee578283fd5b80840185601f8201126133ff578384fd5b8051915061341461340f83613b64565b613b20565b8281528381019082850185850284018601891015613430578687fd5b8693505b84841015613452578051835260019390930192918501918501613434565b50979650505050505050565b60006020828403121561346f578081fd5b8151801515811461336b578182fd5b60008060408385031215613490578182fd5b8251801515811461349f578283fd5b6020939093015192949293505050565b6000602082840312156134c0578081fd5b813567ffffffffffffffff8111156134d6578182fd5b612d2f84828501613292565b6000806000608084860312156134f6578081fd5b833567ffffffffffffffff81111561350c578182fd5b61351886828701613292565b935050602085603f86011261352b578182fd5b600261353961340f82613b47565b80838801606089018a81111561354d578687fd5b865b85811015613573576135618c8461321e565b8552938601939186019160010161354f565b50979a91995050953596505050505050565b600060208284031215613596578081fd5b5051919050565b6000806000606084860312156135b1578283fd5b8351925060208401519150604084015190509250925092565b600081518084526135e2816020860160208601613b84565b601f01601f19169290920160200192915050565b60008251613608818460208701613b84565b9190910192915050565b756578656375746528616464726573732c62797465732960501b815260160190565b6001600160a01b0391909116815260200190565b6001600160a01b038481168252831660208201526080604082018190526012908201527110dbdb5c1bdd5b99119b185cda109bdbdcdd60721b60a082015260c06060820181905260009061369e908301846135ca565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c10dbdb5c1bdd5b99109bdbdcdd609a1b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c436f6d706f756e64526570617960981b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b0384811682528316602082015260806040820181905260129082015271436f6d706f756e64466c617368526570617960701b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906137d2908301846135ca565b9695505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156138b05783516001600160a01b03168352928401929184019160010161388b565b50909695505050505050565b60006020825261336b60208301846135ca565b600060c082526138e260c08301886135ca565b905060208281018760005b60028110156139135781516001600160a01b0316835291830191908301906001016138ed565b50505050606082019490945291151560808301526001600160a01b031660a09091015292915050565b60006040825261394f60408301856135ca565b828103602084015261369e81856135ca565b60208082526014908201527315dc985c1c195c881a5cc81b9bdd081d985b1a5960621b604082015260600190565b6020808252601a908201527f46696e616c20616d6f756e742069736e277420636f7272656374000000000000604082015260600190565b60208082526026908201527f496e636f7272656e74206c656e6774207768696c65207772697474696e6720626040820152653cba32b9999960d11b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b90815260200190565b8581526001600160a01b0385811660208301528416604082015260a060608201819052600090613ac8908301856135ca565b90508260808301529695505050505050565b92835260208301919091526001600160a01b0316604082015260600190565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60405181810167ffffffffffffffff81118282101715613b3f57600080fd5b604052919050565b600067ffffffffffffffff821115613b5d578081fd5b5060200290565b600067ffffffffffffffff821115613b7a578081fd5b5060209081020190565b60005b83811015613b9f578181015183820152602001613b87565b83811115611b4d5750506000910152565b6001600160a01b03811681146116fe57600080fdfe000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea264697066735822122096282b08366ec04afe322c49cea0b1a6b56e43da324f10dff266e71caf065e3b64736f6c634300060a0033
Deployed Bytecode
0x6080604052600436106101bb5760003560e01c80635f82c67e116100ec578063a734f06e1161008a578063d3661fa511610064578063d3661fa5146102c6578063e074bb47146103ed578063f24ccbfe1461040d578063f708847b14610422576101c2565b8063a734f06e14610247578063c91d59fe146103c3578063d0cc7289146103d8576101c2565b80638823151b116100c65780638823151b146103845780638c8a795814610399578063a46a66c91461036f578063a59a9973146103ae576101c2565b80635f82c67e14610347578063745ce7c11461035c5780637b925ab11461036f576101c2565b806339af24ae116101595780634595f535116101335780634595f535146102db5780634ab45d33146102f057806350c86de514610305578063534859071461031a576101c2565b806339af24ae146102915780633d391f70146102a657806344169752146102c6576101c2565b80631ec18ec0116101955780631ec18ec01461021a57806329f7fc9e146102475780632b6e65811461025c578063314b63321461027c576101c2565b8063040141e5146101c7578063099a8653146101f25780630edec02614610207576101c2565b366101c257005b600080fd5b3480156101d357600080fd5b506101dc610435565b6040516101e99190613634565b60405180910390f35b6102056102003660046134e2565b61044d565b005b6102056102153660046134e2565b610697565b34801561022657600080fd5b5061023a61023536600461338e565b610995565b6040516101e99190613a8d565b34801561025357600080fd5b506101dc610bcc565b34801561026857600080fd5b5061023a61027736600461338e565b610bde565b34801561028857600080fd5b506101dc610f6f565b34801561029d57600080fd5b506101dc610f87565b3480156102b257600080fd5b506102056102c136600461334f565b610f9f565b3480156102d257600080fd5b506101dc61117f565b3480156102e757600080fd5b506101dc611197565b3480156102fc57600080fd5b506101dc6111af565b34801561031157600080fd5b5061023a6111c7565b34801561032657600080fd5b5061033a6103353660046134af565b6111cd565b6040516101e991906138bc565b34801561035357600080fd5b506101dc611272565b61020561036a3660046134e2565b61128a565b34801561037b57600080fd5b506101dc6115c8565b34801561039057600080fd5b506101dc6115e0565b3480156103a557600080fd5b506101dc6115f8565b3480156103ba57600080fd5b506101dc611610565b3480156103cf57600080fd5b506101dc611628565b3480156103e457600080fd5b506101dc61163b565b3480156103f957600080fd5b5061020561040836600461334f565b611653565b34801561041957600080fd5b506101dc611701565b6102056104303660046134e2565b611719565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104668260005b60200201518360016020020151611a4c565b6000610470611b53565b9050600061048584825b602002015130610bde565b905060008186604001511161049e5785604001516104a0565b815b855160405163852a12e360e01b81529192506001600160a01b03169063852a12e3906104d0908490600401613a8d565b602060405180830381600087803b1580156104ea57600080fd5b505af11580156104fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105229190613585565b1561052c57600080fd5b600061053e86825b6020020151611bd0565b9050600061054d876001610534565b905060006001600160a01b038381169083161461058c5761056d89611c86565b915061058590508187898b60015b6020020151611ee8565b90036105a4565b50826105a181888a60015b60200201516122a8565b90035b6105b78189600160200201518489612526565b6040516001600160a01b038716904780156108fc02916000818181858888f193505050501580156105ec573d6000803e3d6000fd5b50735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338c6040015185888860405160200161062d9493929190613af9565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161065a939291906136f8565b600060405180830381600087803b15801561067457600080fd5b505af1158015610688573d6000803e3d6000fd5b50505050505050505050505050565b6106a2826000610454565b60006106ac611b53565b905060006106c28460015b602002015130610995565b90506000818660400151116106db5785604001516106dd565b815b602086015160405163317afabb60e21b81529192506001600160a01b03169063c5ebeaec90610710908490600401613a8d565b602060405180830381600087803b15801561072a57600080fd5b505af115801561073e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107629190613585565b1561076c57600080fd5b60006107788682610534565b90506000610787876001610534565b905060006001600160a01b03838116908316146107c9576107ac8487898b600161057b565b90930360408901819052926107c089611c86565b91506107db9050565b50826107d881888a6001610597565b90035b87516107e8908490612737565b6001600160a01b038316600080516020613bc68339815191521461089657875160405163140e25ad60e31b81526001600160a01b039091169063a0712d6890610835908490600401613a8d565b602060405180830381600087803b15801561084f57600080fd5b505af1158015610863573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108879190613585565b1561089157600080fd5b6108f2565b87600060200201516001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156108d857600080fd5b505af11580156108ec573d6000803e3d6000fd5b50505050505b6040516001600160a01b038716904780156108fc02916000818181858888f19350505050158015610927573d6000803e3d6000fd5b50735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce5030338c604001518588886040516020016109689493929190613af9565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161065a939291906136a7565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c79906109d1908690600401613634565b60606040518083038186803b1580156109e957600080fd5b505afa1580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a21919061359d565b509150506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015610a7457600080fd5b505afa158015610a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aac9190613372565b9050846001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ae957600080fd5b505af1158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b219190613585565b5060405163fc57d4df60e01b81526000906001600160a01b0383169063fc57d4df90610b51908990600401613634565b60206040518083038186803b158015610b6957600080fd5b505afa158015610b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba19190613585565b90506000610baf8483612775565b9050610bbf816064815b046127a6565b9450505050505b92915050565b600080516020613bc683398151915281565b604051635ec88c7960e01b81526000908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90635ec88c7990610c1a908690600401613634565b60606040518083038186803b158015610c3257600080fd5b505afa158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a919061359d565b509150506000846001600160a01b0316633af9e669856040518263ffffffff1660e01b8152600401610c9c9190613634565b602060405180830381600087803b158015610cb657600080fd5b505af1158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee9190613585565b90506000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015610d3f57600080fd5b505afa158015610d53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d779190613372565b905082610d8857509150610bc69050565b856001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610dc357600080fd5b505af1158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190613585565b50604051638e8f294b60e01b8152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b90610e36908a90600401613634565b604080518083038186803b158015610e4d57600080fd5b505afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e85919061347e565b915050610e9061320b565b5060408051602081019091528181526000610eab86836127b6565b9150506000846001600160a01b031663fc57d4df8b6040518263ffffffff1660e01b8152600401610edc9190613634565b60206040518083038186803b158015610ef457600080fd5b505afa158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c9190613585565b90506000610f3a8383612775565b905086811115610f54578698505050505050505050610bc6565b610f6081606481610bb9565b9b9a5050505050505050505050565b7325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d81565b733dd0cdf5ffa28c6847b4b276e2fd256046a44bb781565b6000306001600160a01b031663bf7e214f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fda57600080fd5b505afa158015610fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110129190613372565b9050806001600160a01b03811661110357735a15566417e6c1c9546523066500bddbc53f88c76001600160a01b03166365688cc96040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561107257600080fd5b505af1158015611086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110aa9190613372565b604051637a9e5e4b60e01b81529091503090637a9e5e4b906110d0908490600401613634565b600060405180830381600087803b1580156110ea57600080fd5b505af11580156110fe573d6000803e3d6000fd5b505050505b806001600160a01b031663cbeea68c843060405161112090613612565b6040519081900381206001600160e01b031960e086901b1682526111489392916004016137dc565b600060405180830381600087803b15801561116257600080fd5b505af1158015611176573d6000803e3d6000fd5b50505050505050565b73322d58b9e75a6918f7e7849aee0ff09369977e0881565b730ed294340b6328647a652207aa72902747c84c9481565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b61019081565b60608082600001518360200151846040015185606001516040516020016111f7949392919061382d565b60408051601f1981840301815290829052608085015160a086015160c087015160e08801516101008901519496506060956112359590602001613a96565b6040516020818303038152906040529050818160405160200161125992919061393c565b604051602081830303815290604052925050505b919050565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b6040516370a0823160e01b815260199081906eb3f879cb30fe243b4dfee438691c04906370a08231906112c1903090600401613634565b60206040518083038186803b1580156112d957600080fd5b505afa1580156112ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113119190613585565b1061139c5760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f390611348908490600401613a8d565b602060405180830381600087803b15801561136257600080fd5b505af1158015611376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139a919061345e565b505b60006113a8848261047a565b9050808560400151116113c5576113c085858561044d565b6115c1565b604051730ed294340b6328647a652207aa72902747c84c94903480156108fc02916000818181858888f19350505050158015611405573d6000803e3d6000fd5b5060408501518190036060611419876111cd565b905060608187876001306040516020016114379594939291906138cf565b6040516020818303038152906040529050611465730ed294340b6328647a652207aa72902747c84c94610f9f565b73398ec7346dcd622edc5ae82352f02be94c62d119635cffe9de730ed294340b6328647a652207aa72902747c84c9461149f8a6000610534565b86856040518563ffffffff1660e01b81526004016114c0949392919061379f565b600060405180830381600087803b1580156114da57600080fd5b505af11580156114ee573d6000803e3d6000fd5b5050505061150f730ed294340b6328647a652207aa72902747c84c94611653565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033868c604001518c60006002811061154757fe5b602002015160405160200161155e93929190613ada565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161158b93929190613749565b600060405180830381600087803b1580156115a557600080fd5b505af11580156115b9573d6000803e3d6000fd5b505050505050505b5050505050565b731b14e8d511c9a4395425314f849bd737baf8208f81565b735a15566417e6c1c9546523066500bddbc53f88c781565b73019739e288973f92bdd3c1d87178e206e51fd91181565b73398ec7346dcd622edc5ae82352f02be94c62d11981565b6eb3f879cb30fe243b4dfee438691c0481565b7395e6f48254609a6ee006f7d493c8e5fb97094cef81565b6000306001600160a01b031663bf7e214f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561168e57600080fd5b505afa1580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190613372565b90506001600160a01b0381166116dc57506116fe565b6000819050806001600160a01b0316632bc3217d843060405161112090613612565b50565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040516370a0823160e01b815260149081906eb3f879cb30fe243b4dfee438691c04906370a0823190611750903090600401613634565b60206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190613585565b1061182b5760405163d8ccd0f360e01b81526eb3f879cb30fe243b4dfee438691c049063d8ccd0f3906117d7908490600401613a8d565b602060405180830381600087803b1580156117f157600080fd5b505af1158015611805573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611829919061345e565b505b60006118388460016106b7565b905080856040015111611850576113c0858585610697565b604051730ed294340b6328647a652207aa72902747c84c94903480156108fc02916000818181858888f19350505050158015611890573d6000803e3d6000fd5b50604085015181900360606118a4876111cd565b86866000306040516020016118bd9594939291906138cf565b60405160208183030381529060405290506118eb730ed294340b6328647a652207aa72902747c84c94610f9f565b73398ec7346dcd622edc5ae82352f02be94c62d119635cffe9de730ed294340b6328647a652207aa72902747c84c94611925896001610534565b85856040518563ffffffff1660e01b8152600401611946949392919061379f565b600060405180830381600087803b15801561196057600080fd5b505af1158015611974573d6000803e3d6000fd5b50505050611995730ed294340b6328647a652207aa72902747c84c94611653565b735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033858b604001518b6001600281106119cd57fe5b60200201516040516020016119e493929190613ada565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401611a1193929190613648565b600060405180830381600087803b158015611a2b57600080fd5b505af1158015611a3f573d6000803e3d6000fd5b5050505050505050505050565b60408051600280825260608083018452926020830190803683370190505090508281600081518110611a7a57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508181600181518110611aa857fe5b6001600160a01b0390921660209283029190910190910152604051631853304760e31b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063c299823890611af790849060040161386f565b600060405180830381600087803b158015611b1157600080fd5b505af1158015611b25573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b4d91908101906133c6565b50505050565b600080309050806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9257600080fd5b505afa158015611ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bca9190613372565b91505090565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed51415611c0c5750600080516020613bc683398151915261126d565b816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611c4757600080fd5b505af1158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7f9190613372565b905061126d565b604081015181516000918291829182918291906001600160a01b0316600080516020613bc68339815191521415611d38578651611cc29061280a565b6001600160a01b031687526040808801518151630d0e30db60e41b8152915173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29263d0e30db09291600480830192600092919082900301818588803b158015611d1e57600080fd5b505af1158015611d32573d6000803e3d6000fd5b50505050505b61010087015115611d7757611d558760000151886040015161284b565b611d6187476000612897565b90945090925090508115611d77578660c0015193505b81611d9157611d87876000612b1b565b92508660a0015193505b611da387608001518860400151612d39565b611db08860200151612d61565b1015611dd75760405162461bcd60e51b8152600401611dce9061398f565b60405180910390fd5b6000611df673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d61565b1115611edc576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a0823190611e3b903090600401613634565b602060405180830381600087803b158015611e5557600080fd5b505af1158015611e69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8d9190613585565b6040518263ffffffff1660e01b8152600401611ea99190613a8d565b600060405180830381600087803b158015611ec357600080fd5b505af1158015611ed7573d6000803e3d6000fd5b505050505b50919350915050915091565b600061019081611ef784611bd0565b604051632cdc77ab60e21b8152909150731b14e8d511c9a4395425314f849bd737baf8208f9063b371deac90611f31908990600401613634565b60206040518083038186803b158015611f4957600080fd5b505afa158015611f5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f81919061345e565b1561201057604051636eeb543160e01b8152731b14e8d511c9a4395425314f849bd737baf8208f90636eeb543190611fbd908990600401613634565b60206040518083038186803b158015611fd557600080fd5b505afa158015611fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200d9190613585565b91505b81156120255781878161201f57fe5b04612028565b60005b925084156121f8576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561207f57600080fd5b505afa158015612093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b79190613372565b90506000816001600160a01b031663fc57d4df876040518263ffffffff1660e01b81526004016120e79190613634565b60206040518083038186803b1580156120ff57600080fd5b505afa158015612113573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121379190613585565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b815260040161217b9190613634565b60206040518083038186803b15801561219357600080fd5b505afa1580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613585565b905060006121d98383612775565b90506121e58982612775565b98506121f1878a612e05565b9650505050505b6005870483111561220a576005870492505b6001600160a01b038116600080516020613bc683398151915214156122705760405173322d58b9e75a6918f7e7849aee0ff09369977e089084156108fc029085906000818181858888f1935050505015801561226a573d6000803e3d6000fd5b5061229e565b61229e6001600160a01b03821673322d58b9e75a6918f7e7849aee0ff09369977e088563ffffffff612e1516565b5050949350505050565b6000806122b483611bd0565b90508315612478576000733d9819210a31b4961b30ef54be2aed79b9c9cd3b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561230b57600080fd5b505afa15801561231f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123439190613372565b90506000816001600160a01b031663fc57d4df866040518263ffffffff1660e01b81526004016123739190613634565b60206040518083038186803b15801561238b57600080fd5b505afa15801561239f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c39190613585565b90506000826001600160a01b031663fc57d4df734ddc2d193948926d02f9b1fe9e1daa0718270ed56040518263ffffffff1660e01b81526004016124079190613634565b60206040518083038186803b15801561241f57600080fd5b505afa158015612433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124579190613585565b905060006124658383612775565b90506124718882612775565b9550505050505b6005850482111561248a576005850491505b6001600160a01b038116600080516020613bc683398151915214156124f05760405173322d58b9e75a6918f7e7849aee0ff09369977e089083156108fc029084906000818181858888f193505050501580156124ea573d6000803e3d6000fd5b5061251e565b61251e6001600160a01b03821673322d58b9e75a6918f7e7849aee0ff09369977e088463ffffffff612e1516565b509392505050565b6040516305eff7ef60e21b81526000906001600160a01b038516906317bfdfbc90612555903090600401613634565b602060405180830381600087803b15801561256f57600080fd5b505af1158015612583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a79190613585565b90508085111561262d576001600160a01b038316600080516020613bc6833981519152141561260d576040516001600160a01b0383169082870380156108fc02916000818181858888f19350505050158015612607573d6000803e3d6000fd5b50612629565b6126296001600160a01b0384168383880363ffffffff612e1516565b8094505b6126378385612737565b6001600160a01b038316600080516020613bc683398151915214156126af57836001600160a01b0316634e4d9fea866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561269157600080fd5b505af11580156126a5573d6000803e3d6000fd5b50505050506115c1565b60405163073a938160e11b81526001600160a01b03851690630e752702906126db908890600401613a8d565b602060405180830381600087803b1580156126f557600080fd5b505af1158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d9190613585565b156115c157600080fd5b6001600160a01b038216600080516020613bc683398151915214612771576127716001600160a01b0383168260001963ffffffff612e7016565b5050565b60008161279761278d85670de0b6b3a7640000612e8f565b6002855b04612e05565b8161279e57fe5b049392505050565b80820382811115610bc657600080fd5b60008060006127c361320b565b6127cd8686612eb3565b909250905060008260038111156127e057fe5b146127f15750915060009050612803565b60006127fc82612f12565b9350935050505b9250929050565b60006001600160a01b038216600080516020613bc6833981519152146128305781610bc6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292915050565b6001600160a01b038216600080516020613bc683398151915214612771576127716001600160a01b0383167395e6f48254609a6ee006f7d493c8e5fb97094cef8363ffffffff612e7016565b60008080808460018111156128a857fe5b14156128c7576128c28660e0015160248860400151612f21565b6128db565b6128db8660e0015160248860600151612f21565b60c08601516040516302f5cc7960e11b815273019739e288973f92bdd3c1d87178e206e51fd911916305eb98f2916129169190600401613634565b60206040518083038186803b15801561292e57600080fd5b505afa158015612942573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612966919061345e565b156129d9578560c001516001600160a01b0316858760e0015160405161298c91906135f6565b60006040518083038185875af1925050503d80600081146129c9576040519150601f19603f3d011682016040523d82523d6000602084013e6129ce565b606091505b5050809350506129de565b600092505b60408601516000908415612b0d5787516129f790612d61565b60208901519091506001600160a01b0316600080516020613bc68339815191521415612afd576040516370a0823160e01b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d9082906370a0823190612a5c903090600401613634565b602060405180830381600087803b158015612a7657600080fd5b505af1158015612a8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aae9190613585565b6040518263ffffffff1660e01b8152600401612aca9190613a8d565b600060405180830381600087803b158015612ae457600080fd5b505af1158015612af8573d6000803e3d6000fd5b505050505b612b0a8860200151612d61565b91505b909250905093509350939050565b60a082015160405163e0aa279760e01b81526000917325dd3f51e0c3c3ff164ddc02a8e4d65bb9cbb12d9163e0aa279791612b5891600401613634565b60206040518083038186803b158015612b7057600080fd5b505afa158015612b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba8919061345e565b612bc45760405162461bcd60e51b8152600401611dce90613961565b60a083015160408401518451600092612bee926001600160a01b039092169163ffffffff612e1516565b6000836001811115612bfc57fe5b1415612c9c578360a001516001600160a01b031663cae270b6828660000151876020015188604001516040518563ffffffff1660e01b8152600401612c4393929190613809565b6020604051808303818588803b158015612c5c57600080fd5b505af1158015612c70573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612c959190613585565b9150612d32565b8360a001516001600160a01b031663153e66e6828660000151876020015188606001516040518563ffffffff1660e01b8152600401612cdd93929190613809565b6020604051808303818588803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612d2f9190613585565b91505b5092915050565b6000670de0b6b3a7640000612797612d518585612e8f565b6002670de0b6b3a7640000612791565b60006001600160a01b038216600080516020613bc68339815191521415612d8957504761126d565b6040516370a0823160e01b81526001600160a01b038316906370a0823190612db5903090600401613634565b60206040518083038186803b158015612dcd57600080fd5b505afa158015612de1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc69190613585565b80820182811015610bc657600080fd5b612e6b8363a9059cbb60e01b8484604051602401612e34929190613856565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f4d565b505050565b612e6b8363095ea7b360e01b8484604051602401612e34929190613856565b6000811580612eaa57505080820282828281612ea757fe5b04145b610bc657600080fd5b6000612ebd61320b565b600080612ed2670de0b6b3a764000087612fdc565b90925090506000826003811115612ee557fe5b14612f0457506040805160208101909152600081529092509050612803565b6127fc81866000015161301b565b51670de0b6b3a7640000900490565b8160200183511015612f455760405162461bcd60e51b8152600401611dce906139c6565b910160200152565b6060612fa2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130cc9092919063ffffffff16565b805190915015612e6b5780806020019051810190612fc0919061345e565b612e6b5760405162461bcd60e51b8152600401611dce90613a43565b60008083612fef57506000905080612803565b83830283858281612ffc57fe5b041461301057506002915060009050612803565b600092509050612803565b600061302561320b565b60008061303a86670de0b6b3a7640000612fdc565b9092509050600082600381111561304d57fe5b1461306c57506040805160208101909152600081529092509050612803565b60008061307983886130e3565b9092509050600082600381111561308c57fe5b146130af5781604051806020016040528060008152509550955050505050612803565b604080516020810190915290815260009890975095505050505050565b60606130db848460008561310e565b949350505050565b600080826130f75750600190506000612803565b600083858161310257fe5b04915091509250929050565b6060613119856131d2565b6131355760405162461bcd60e51b8152600401611dce90613a0c565b60006060866001600160a01b0316858760405161315291906135f6565b60006040518083038185875af1925050503d806000811461318f576040519150601f19603f3d011682016040523d82523d6000602084013e613194565b606091505b509150915081156131a85791506130db9050565b8051156131b85780518082602001fd5b8360405162461bcd60e51b8152600401611dce91906138bc565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906130db575050151592915050565b6040518060200160405280600081525090565b8035610bc681613bb0565b600082601f830112613239578081fd5b813567ffffffffffffffff81111561324f578182fd5b613262601f8201601f1916602001613b20565b915080825283602082850101111561327957600080fd5b8060208401602084013760009082016020015292915050565b60006101208083850312156132a5578182fd5b6132ae81613b20565b9150506132bb838361321e565b81526132ca836020840161321e565b60208201526040820135604082015260608201356060820152608082013560808201526132fa8360a0840161321e565b60a082015261330c8360c0840161321e565b60c082015260e082013567ffffffffffffffff81111561332b57600080fd5b61333784828501613229565b60e08301525061010080830135818301525092915050565b600060208284031215613360578081fd5b813561336b81613bb0565b9392505050565b600060208284031215613383578081fd5b815161336b81613bb0565b600080604083850312156133a0578081fd5b82356133ab81613bb0565b915060208301356133bb81613bb0565b809150509250929050565b600060208083850312156133d8578182fd5b825167ffffffffffffffff8111156133ee578283fd5b80840185601f8201126133ff578384fd5b8051915061341461340f83613b64565b613b20565b8281528381019082850185850284018601891015613430578687fd5b8693505b84841015613452578051835260019390930192918501918501613434565b50979650505050505050565b60006020828403121561346f578081fd5b8151801515811461336b578182fd5b60008060408385031215613490578182fd5b8251801515811461349f578283fd5b6020939093015192949293505050565b6000602082840312156134c0578081fd5b813567ffffffffffffffff8111156134d6578182fd5b612d2f84828501613292565b6000806000608084860312156134f6578081fd5b833567ffffffffffffffff81111561350c578182fd5b61351886828701613292565b935050602085603f86011261352b578182fd5b600261353961340f82613b47565b80838801606089018a81111561354d578687fd5b865b85811015613573576135618c8461321e565b8552938601939186019160010161354f565b50979a91995050953596505050505050565b600060208284031215613596578081fd5b5051919050565b6000806000606084860312156135b1578283fd5b8351925060208401519150604084015190509250925092565b600081518084526135e2816020860160208601613b84565b601f01601f19169290920160200192915050565b60008251613608818460208701613b84565b9190910192915050565b756578656375746528616464726573732c62797465732960501b815260160190565b6001600160a01b0391909116815260200190565b6001600160a01b038481168252831660208201526080604082018190526012908201527110dbdb5c1bdd5b99119b185cda109bdbdcdd60721b60a082015260c06060820181905260009061369e908301846135ca565b95945050505050565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c10dbdb5c1bdd5b99109bdbdcdd609a1b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b03848116825283166020820152608060408201819052600d908201526c436f6d706f756e64526570617960981b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b0384811682528316602082015260806040820181905260129082015271436f6d706f756e64466c617368526570617960701b60a082015260c06060820181905260009061369e908301846135ca565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906137d2908301846135ca565b9695505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156138b05783516001600160a01b03168352928401929184019160010161388b565b50909695505050505050565b60006020825261336b60208301846135ca565b600060c082526138e260c08301886135ca565b905060208281018760005b60028110156139135781516001600160a01b0316835291830191908301906001016138ed565b50505050606082019490945291151560808301526001600160a01b031660a09091015292915050565b60006040825261394f60408301856135ca565b828103602084015261369e81856135ca565b60208082526014908201527315dc985c1c195c881a5cc81b9bdd081d985b1a5960621b604082015260600190565b6020808252601a908201527f46696e616c20616d6f756e742069736e277420636f7272656374000000000000604082015260600190565b60208082526026908201527f496e636f7272656e74206c656e6774207768696c65207772697474696e6720626040820152653cba32b9999960d11b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b90815260200190565b8581526001600160a01b0385811660208301528416604082015260a060608201819052600090613ac8908301856135ca565b90508260808301529695505050505050565b92835260208301919091526001600160a01b0316604082015260600190565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60405181810167ffffffffffffffff81118282101715613b3f57600080fd5b604052919050565b600067ffffffffffffffff821115613b5d578081fd5b5060200290565b600067ffffffffffffffff821115613b7a578081fd5b5060209081020190565b60005b83811015613b9f578181015183820152602001613b87565b83811115611b4d5750506000910152565b6001600160a01b03811681146116fe57600080fdfe000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea264697066735822122096282b08366ec04afe322c49cea0b1a6b56e43da324f10dff266e71caf065e3b64736f6c634300060a0033
Deployed Bytecode Sourcemap
61250:3027:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21198:81;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;55943:1352;;;;;;;;;:::i;:::-;;57597:1622;;;;;;;;;:::i;54784:594::-;;;;;;;;;;-1:-1:-1;54784:594:0;;;;;;;;:::i;:::-;;;;;;;;21105:86;;;;;;;;;;;;;:::i;53396:1049::-;;;;;;;;;;-1:-1:-1;53396:1049:0;;;;;;;;:::i;21473:92::-;;;;;;;;;;;;;:::i;47228:84::-;;;;;;;;;;;;;:::i;60036:488::-;;;;;;;;;;-1:-1:-1;60036:488:0;;;;;;;;:::i;46720:88::-;;;;;;;;;;;;;:::i;61447:102::-;;;;;;;;;;;;;:::i;47051:81::-;;;;;;;;;;;;;:::i;46906:38::-;;;;;;;;;;;;;:::i;29347:646::-;;;;;;;;;;-1:-1:-1;29347:646:0;;;;;;;;:::i;:::-;;;;;;;;47139:80;;;;;;;;;;;;;:::i;61838:1094::-;;;;;;;;;:::i;46815:82::-;;;;;;;;;;;;;:::i;59806:84::-;;;;;;;;;;;;;:::i;21664:87::-;;;;;;;;;;;;;:::i;61339:99::-;;;;;;;;;;;;;:::i;1342:106::-;;;;;;;;;;;;;:::i;21574:83::-;;;;;;;;;;;;;:::i;60701:463::-;;;;;;;;;;-1:-1:-1;60701:463:0;;;;;;;;:::i;55535:100::-;;;;;;;;;;;;;:::i;63220:1054::-;;;;;;;;;:::i;21198:81::-;21237:42;21198:81;:::o;55943:1352::-;56128:43;56140:11;56152:1;56140:14;;;;;56156:11;56168:1;56156:14;;;;56128:11;:43::i;:::-;56184:20;56215:16;:14;:16::i;:::-;56184:48;-1:-1:-1;56245:12:0;56260:47;56277:11;56245:12;56277:14;;;;;56301:4;56260:16;:47::i;:::-;56245:62;;56320:15;56359:7;56339;:17;;;:27;56338:59;;56380:7;:17;;;56338:59;;;56370:7;56338:59;56434:14;;56418:60;;-1:-1:-1;;;56418:60:0;;56320:77;;-1:-1:-1;;;;;;56418:48:0;;;;:60;;56320:77;;56418:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:65;56410:74;;;;;;56497:17;56517:33;56535:11;56497:17;56535:14;;;;;56517:17;:33::i;:::-;56497:53;-1:-1:-1;56561:19:0;56583:33;56601:11;56613:1;56601:14;;56583:33;56561:55;-1:-1:-1;56629:15:0;-1:-1:-1;;;;;56665:24:0;;;;;;;56661:300;;56723:14;56729:7;56723:5;:14::i;:::-;56706:31;-1:-1:-1;56766:50:0;;-1:-1:-1;56706:31:0;56785:4;56791:8;56801:11;56813:1;56801:14;;;;;56766:6;:50::i;:::-;56752:64;;56661:300;;;-1:-1:-1;56862:10:0;56901:48;56862:10;56924:8;56934:11;56946:1;56934:14;;;;;56901:10;:48::i;:::-;56887:62;;56661:300;56973:58;56985:10;56997:11;57009:1;56997:14;;;;57013:11;57026:4;56973:11;:58::i;:::-;57070:36;;-1:-1:-1;;;;;57070:13:0;;;57084:21;57070:36;;;;;;;;;57084:21;57070:13;:36;;;;;;;;;;;;;;;;;;;;;55592:42;-1:-1:-1;;;;;57166:10:0;;57185:4;57192:10;57232:7;:17;;;57251:10;57263:9;57274:11;57221:65;;;;;;;;;;;;;;;;;;;;;;;;;57166:121;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55943:1352;;;;;;;;;:::o;57597:1622::-;57782:43;57794:11;57806:1;57794:14;;57782:43;57838:20;57869:16;:14;:16::i;:::-;57838:48;-1:-1:-1;57899:14:0;57916:43;57929:11;57941:1;57929:14;;;;;57953:4;57916:12;:43::i;:::-;57899:60;;57970:17;58011:9;57991:7;:17;;;:29;57990:63;;58036:7;:17;;;57990:63;;;58024:9;57990:63;58090:14;;;;58074:52;;-1:-1:-1;;;58074:52:0;;57970:83;;-1:-1:-1;;;;;;58074:38:0;;;;:52;;57970:83;;58074:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:57;58066:66;;;;;;58145:17;58165:33;58183:11;58145:17;58183:14;;58165:33;58145:53;-1:-1:-1;58209:19:0;58231:33;58249:11;58261:1;58249:14;;58231:33;58209:55;-1:-1:-1;58277:15:0;-1:-1:-1;;;;;58313:24:0;;;;;;;58309:354;;58370:52;58377:12;58391:4;58397:8;58407:11;58419:1;58407:14;;58370:52;58354:68;;;58439:17;;;:32;;;58354:68;58502:14;58439:7;58502:5;:14::i;:::-;58486:30;-1:-1:-1;58309:354:0;;-1:-1:-1;58309:354:0;;-1:-1:-1;58562:12:0;58603:48;58562:12;58626:8;58636:11;58648:1;58636:14;;58603:48;58589:62;;58309:354;58700:14;;58675:40;;58689:9;;58675:13;:40::i;:::-;-1:-1:-1;;;;;58732:24:0;;-1:-1:-1;;;;;;;;;;;58732:24:0;58728:228;;58797:14;;58781:48;;-1:-1:-1;;;58781:48:0;;-1:-1:-1;;;;;58781:36:0;;;;;;:48;;58818:10;;58781:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:53;58773:62;;;;;;58728:228;;;58884:11;58896:1;58884:14;;;;-1:-1:-1;;;;;58868:36:0;;58912:10;58868:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58728:228;58994:36;;-1:-1:-1;;;;;58994:13:0;;;59008:21;58994:36;;;;;;;;;59008:21;58994:13;:36;;;;;;;;;;;;;;;;;;;;;55592:42;-1:-1:-1;;;;;59090:10:0;;59109:4;59116:10;59156:7;:17;;;59175:10;59187:9;59198:11;59145:65;;;;;;;;;;;;;;;;;;;;;;;;;59090:121;;;;;;;;;;;;;;;;;;54784:594;54910:63;;-1:-1:-1;;;54910:63:0;;54865:4;;;;47177:42;;54910:53;;:63;;54964:8;;54910:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54882:91;;;;54984:14;47177:42;-1:-1:-1;;;;;55001:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54984:59;;55072:15;-1:-1:-1;;;;;55056:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55134:67:0;;-1:-1:-1;;;55134:67:0;;55118:13;;-1:-1:-1;;;;;55134:50:0;;;;;:67;;55185:15;;55134:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55118:83;;55212:21;55236:30;55241:14;55257:8;55236:4;:30::i;:::-;55212:54;-1:-1:-1;55286:47:0;55212:54;55328:3;55212:54;55309:22;;55286:3;:47::i;:::-;55279:54;;;;;;54784:594;;;;;:::o;21105:86::-;-1:-1:-1;;;;;;;;;;;21105:86:0;:::o;53396:1049::-;53524:63;;-1:-1:-1;;;53524:63:0;;53479:4;;;;47177:42;;53524:53;;:63;;53578:8;;53524:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53496:91;;;;53598:17;53634:13;-1:-1:-1;;;;;53618:50:0;;53669:8;53618:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53598:80;;53689:14;47177:42;-1:-1:-1;;;;;53706:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53689:59;-1:-1:-1;53765:19:0;53761:44;;-1:-1:-1;53793:12:0;-1:-1:-1;53786:19:0;;-1:-1:-1;53786:19:0;53761:44;53834:13;-1:-1:-1;;;;;53818:45:0;;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;53908:56:0;;-1:-1:-1;;;53908:56:0;;53881:23;;47177:42;;53908:41;;:56;;53950:13;;53908:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53878:86;;;53975:27;;:::i;:::-;-1:-1:-1;54005:35:0;;;;;;;;;;;;-1:-1:-1;54076:56:0;54099:14;54005:35;54076:22;:56::i;:::-;54053:79;;;54145:13;54185:6;-1:-1:-1;;;;;54161:50:0;;54212:13;54161:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54145:81;;54237:15;54255:27;54260:11;54273:8;54255:4;:27::i;:::-;54237:45;;54312:12;54299:10;:25;54295:50;;;54333:12;54326:19;;;;;;;;;;;;54295:50;54365:35;54369:10;54395:3;54369:10;54382:16;;54365:35;54358:42;53396:1049;-1:-1:-1;;;;;;;;;;;53396:1049:0:o;21473:92::-;21523:42;21473:92;:::o;47228:84::-;47270:42;47228:84;:::o;60036:488::-;60101:21;60148:4;-1:-1:-1;;;;;60133:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60101:66;-1:-1:-1;60101:66:0;-1:-1:-1;;;;;60233:27:0;;60229:188;;59848:42;-1:-1:-1;;;;;60285:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60342:63;;-1:-1:-1;;;60342:63:0;;60277:50;;-1:-1:-1;60357:4:0;;60342:34;;:63;;60277:50;;60342:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60229:188;60429:5;-1:-1:-1;;;;;60429:12:0;;60442:13;60465:4;60479:35;;;;;;;;;;;;;;;-1:-1:-1;;;;;;60429:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60036:488;;;:::o;46720:88::-;46766:42;46720:88;:::o;61447:102::-;61507:42;61447:102;:::o;47051:81::-;47090:42;47051:81;:::o;46906:38::-;46941:3;46906:38;:::o;29347:646::-;29422:12;29559:18;29605:7;:15;;;29635:7;:16;;;29666:7;:17;;;29698:7;:18;;;29580:147;;;;;;;;;;;;;;;;-1:-1:-1;;29580:147:0;;;;;;;;;;29786:16;;;;29817:15;;;;29847:20;;;;29882:16;;;;29913:15;;;;29580:147;;-1:-1:-1;29740:18:0;;29761:178;;29913:15;29580:147;29761:178;;;;;;;;;;;;;;;;29740:199;;29972:5;29979;29961:24;;;;;;;;;;;;;;;;;;;;;;;29954:31;;;;29347:646;;;;:::o;47139:80::-;47177:42;47139:80;:::o;61838:1094::-;1503:33;;-1:-1:-1;;;1503:33:0;;62028:2;;;;1405:42;;1503:18;;:33;;1530:4;;1503:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;1499:99;;1564:22;;-1:-1:-1;;;1564:22:0;;1405:42;;1564:13;;:22;;1578:7;;1564:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1499:99;62043:12:::1;62058:47;62075:11:::0;62043:12;62075:14:::1;::::0;62058:47:::1;62043:62;;62143:7;62122;:17;;;:28;62118:807;;62167:37;62173:7;62182:11;62195:8;62167:5;:37::i;:::-;62118:807;;;62260:45;::::0;61507:42:::1;::::0;62295:9:::1;62260:45:::0;::::1;;;::::0;::::1;::::0;;;62295:9;61507:42;62260:45;::::1;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;62341:17:0::1;::::0;::::1;::::0;:27;;::::1;62384:20;62407:25;62341:7:::0;62407:16:::1;:25::i;:::-;62384:48;;62447:23;62484:7;62493:11;62506:8;62516:4;62530;62473:63;;;;;;;;;;;;;;;;;;;;;;;;;;62447:89;;62553:41;61507:42;62553:14;:41::i;:::-;61395:42;62611:21;61507:42;62660:33;62678:11:::0;62690:1:::1;62678:14;::::0;62660:33:::1;62695:10;62707;62611:107;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;62735:43;61507:42;62735:16;:43::i;:::-;55592:42;-1:-1:-1::0;;;;;62795:10:0::1;;62814:4;62821:10;62866;62878:7;:17;;;62897:11;62909:1;62897:14;;;;;;;;;;;62855:57;;;;;;;;;;;;;;;;;;;;;;;;62795:118;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;62118:807;;;;1610:1;61838:1094:::0;;;;:::o;46815:82::-;46855:42;46815:82;:::o;59806:84::-;59848:42;59806:84;:::o;21664:87::-;21709:42;21664:87;:::o;61339:99::-;61395:42;61339:99;:::o;1342:106::-;1405:42;1342:106;:::o;21574:83::-;21615:42;21574:83;:::o;60701:463::-;60768:21;60815:4;-1:-1:-1;;;;;60800:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60768:66;-1:-1:-1;;;;;;60946:27:0;;60942:66;;60990:7;;;60942:66;61020:13;61044;61020:38;;61069:5;-1:-1:-1;;;;;61069:12:0;;61082:13;61105:4;61119:35;;;;;;60701:463;;:::o;55535:100::-;55592:42;55535:100;:::o;63220:1054::-;1503:33;;-1:-1:-1;;;1503:33:0;;63410:2;;;;1405:42;;1503:18;;:33;;1530:4;;1503:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:44;1499:99;;1564:22;;-1:-1:-1;;;1564:22:0;;1405:42;;1564:13;;:22;;1578:7;;1564:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1499:99;63425:14:::1;63442:43;63455:11:::0;63467:1:::1;63455:14;::::0;63442:43:::1;63425:60;;63523:9;63502:7;:17;;;:30;63498:767;;63549:37;63555:7;63564:11;63577:8;63549:5;:37::i;63498:767::-;63642:45;::::0;61507:42:::1;::::0;63677:9:::1;63642:45:::0;::::1;;;::::0;::::1;::::0;;;63677:9;61507:42;63642:45;::::1;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;63723:17:0::1;::::0;::::1;::::0;:29;;::::1;63768:23;63805:25;63723:7:::0;63805:16:::1;:25::i;:::-;63832:11;63845:8;63855:5;63870:4;63794:82;;;;;;;;;;;;;;;;;;;;;;;;;;63768:108;;63893:41;61507:42;63893:14;:41::i;:::-;61395:42;63951:21;61507:42;64000:33;64018:11:::0;64030:1:::1;64018:14;::::0;64000:33:::1;64035:10;64047;63951:107;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;64075:43;61507:42;64075:16;:43::i;:::-;55592:42;-1:-1:-1::0;;;;;64135:10:0::1;;64154:4;64161:10;64206;64218:7;:17;;;64237:11;64249:1;64237:14;;;;;;;;;;;64195:57;;;;;;;;;;;;;;;;;;;;;;;;64135:118;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;63498:767;;1610:1;63220:1054:::0;;;;:::o;51661:292::-;51781:16;;;51795:1;51781:16;;;51754:24;51781:16;;;;;51754:24;51781:16;;;;;;;;;;-1:-1:-1;51781:16:0;51754:43;;51821:15;51808:7;51816:1;51808:10;;;;;;;;;;;;;:28;-1:-1:-1;;;;;51808:28:0;;;-1:-1:-1;;;;;51808:28:0;;;;;51860:17;51847:7;51855:1;51847:10;;;;;;;;-1:-1:-1;;;;;51847:30:0;;;:10;;;;;;;;;;;:30;51890:55;;-1:-1:-1;;;51890:55:0;;47177:42;;51890:46;;:55;;51937:7;;51890:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;51890:55:0;;;;;;;;;;;;;;;51661:292;;;:::o;52891:157::-;52940:7;52960:13;53000:4;52960:47;;53027:5;-1:-1:-1;;;;;53027:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53020:20;;;52891:157;:::o;52547:261::-;52616:7;-1:-1:-1;;;;;52640:30:0;;47090:42;52640:30;52636:165;;;-1:-1:-1;;;;;;;;;;;;52687:18:0;;52636:165;52761:14;-1:-1:-1;;;;;52745:42:0;;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52738:51;;;;24633:1466;24817:16;;;;24894:14;;24694:7;;;;;;;;;;24817:16;-1:-1:-1;;;;;24894:35:0;-1:-1:-1;;;;;;;;;;;24894:35:0;24890:191;;;24977:14;;24963:29;;:13;:29::i;:::-;-1:-1:-1;;;;;24946:46:0;;;25050:16;;;;;25007:62;;-1:-1:-1;;;25007:62:0;;;;21237:42;;25007:36;;25050:16;25007:62;;;;;24946:14;;25007:62;;;;;;;25050:16;21237:42;25007:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24890:191;25160:14;;;;:18;25156:304;;25195:48;25210:6;:14;;;25226:6;:16;;;25195:14;:48::i;:::-;25298:57;25308:6;25316:21;25339:15;25298:9;:57::i;:::-;25260:95;;-1:-1:-1;25260:95:0;;-1:-1:-1;25260:95:0;-1:-1:-1;25372:77:0;;;;25414:6;:19;;;25404:29;;25372:77;25530:7;25525:129;;25569:34;25579:6;25587:15;25569:9;:34::i;:::-;25554:49;;25628:6;:14;;;25618:24;;25525:129;25705:39;25710:6;:15;;;25727:6;:16;;;25705:4;:39::i;:::-;25674:27;25685:6;:15;;;25674:10;:27::i;:::-;:70;;25666:109;;;;-1:-1:-1;;;25666:109:0;;;;;;;;;;;;;;;;;25883:1;25856:24;21237:42;25856:10;:24::i;:::-;:28;25852:185;;;25957:53;;-1:-1:-1;;;25957:53:0;;21237:42;;25901:37;;21237:42;;25957:38;;:53;;26004:4;;25957:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25901:124;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25852:185;-1:-1:-1;26069:7:0;;-1:-1:-1;26078:12:0;-1:-1:-1;;24633:1466:0;;;:::o;48887:1249::-;48986:14;46941:3;48986:14;49068:30;49086:11;49068:17;:30::i;:::-;49115:45;;-1:-1:-1;;;49115:45:0;;49048:50;;-1:-1:-1;46855:42:0;;49115:38;;:45;;49154:5;;49115:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49111:134;;;49183:50;;-1:-1:-1;;;49183:50:0;;46855:42;;49183:43;;:50;;49227:5;;49183:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49177:56;;49111:134;49270:8;;49269:32;;49297:3;49287:7;:13;;;;;;49269:32;;;49282:1;49269:32;49257:44;-1:-1:-1;49318:13:0;;49314:482;;49348:14;47177:42;-1:-1:-1;;;;;49365:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49348:59;;49424:18;49469:6;-1:-1:-1;;;;;49445:50:0;;49496:11;49445:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49424:84;;49523:13;49563:6;-1:-1:-1;;;;;49539:50:0;;47090:42;49539:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49523:80;;49620:20;49643:29;49648:13;49663:8;49643:4;:29::i;:::-;49620:52;;49700:31;49705:8;49715:15;49700:4;:31::i;:::-;49689:42;;49760:24;49764:9;49775:8;49760:3;:24::i;:::-;49748:36;;49314:482;;;;;49889:1;49879:7;:11;49866:9;:25;49862:81;;;49930:1;49920:7;:11;49908:23;;49862:81;-1:-1:-1;;;;;49959:24:0;;-1:-1:-1;;;;;;;;;;;49959:24:0;49955:174;;;50000:31;;46766:42;;50000:31;;;;;50021:9;;50000:31;;;;50021:9;46766:42;50000:31;;;;;;;;;;;;;;;;;;;;;49955:174;;;50064:53;-1:-1:-1;;;;;50064:29:0;;46766:42;50107:9;50064:53;:29;:53;:::i;:::-;48887:1249;;;;;;;;:::o;50474:948::-;50562:14;50589:17;50609:30;50627:11;50609:17;:30::i;:::-;50589:50;-1:-1:-1;50656:13:0;;50652:430;;50686:14;47177:42;-1:-1:-1;;;;;50703:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50686:59;;50762:18;50807:6;-1:-1:-1;;;;;50783:50:0;;50834:11;50783:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50762:84;;50861:13;50901:6;-1:-1:-1;;;;;50877:50:0;;47090:42;50877:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50861:80;;50958:20;50981:29;50986:13;51001:8;50981:4;:29::i;:::-;50958:52;;51039:31;51044:8;51054:15;51039:4;:31::i;:::-;51027:43;;50652:430;;;;;51175:1;51165:7;:11;51152:9;:25;51148:81;;;51216:1;51206:7;:11;51194:23;;51148:81;-1:-1:-1;;;;;51245:24:0;;-1:-1:-1;;;;;;;;;;;51245:24:0;51241:174;;;51286:31;;46766:42;;51286:31;;;;;51307:9;;51286:31;;;;51307:9;46766:42;51286:31;;;;;;;;;;;;;;;;;;;;;51241:174;;;51350:53;-1:-1:-1;;;;;51350:29:0;;46766:42;51393:9;51350:53;:29;:53;:::i;:::-;50474:948;;;;;;:::o;47726:806::-;47866:66;;-1:-1:-1;;;47866:66:0;;47849:14;;-1:-1:-1;;;;;47866:51:0;;;;;:66;;47926:4;;47866:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47849:83;;47959:9;47949:7;:19;47945:295;;;-1:-1:-1;;;;;47989:27:0;;-1:-1:-1;;;;;;;;;;;47989:27:0;47985:208;;;48037:37;;-1:-1:-1;;;;;48037:14:0;;;48053:19;;;48037:37;;;;;;;;;48053:19;48037:14;:37;;;;;;;;;;;;;;;;;;;;;47985:208;;;48115:62;-1:-1:-1;;;;;48115:32:0;;48148:5;48156:19;;;48115:62;:32;:62;:::i;:::-;48219:9;48209:19;;47945:295;48252:42;48266:12;48280:13;48252;:42::i;:::-;-1:-1:-1;;;;;48311:27:0;;-1:-1:-1;;;;;;;;;;;48311:27:0;48307:218;;;48371:13;-1:-1:-1;;;;;48355:42:0;;48405:7;48355:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48307:218;;;48456:51;;-1:-1:-1;;;48456:51:0;;-1:-1:-1;;;;;48456:42:0;;;;;:51;;48499:7;;48456:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:56;48448:65;;;;;52169:201;-1:-1:-1;;;;;52257:25:0;;-1:-1:-1;;;;;;;;;;;52257:25:0;52253:110;;52299:52;-1:-1:-1;;;;;52299:29:0;;52329:11;-1:-1:-1;;52299:52:0;:29;:52;:::i;:::-;52169:201;;:::o;9377:120::-;9436:9;9488:1;9462:23;9466:11;9470:1;9066:6;9466:3;:11::i;:::-;9483:1;9479;:5;;9462:3;:23::i;:::-;:27;;;;;;;9377:120;-1:-1:-1;;;9377:120:0:o;8215:113::-;8308:5;;;8303:16;;;;8295:25;;;;;42744:337;42832:9;42843:4;42861:13;42876:19;;:::i;:::-;42899:31;42914:6;42922:7;42899:14;:31::i;:::-;42860:70;;-1:-1:-1;42860:70:0;-1:-1:-1;42952:18:0;42945:3;:25;;;;;;;;;42941:73;;-1:-1:-1;42995:3:0;-1:-1:-1;43000:1:0;;-1:-1:-1;42987:15:0;;42941:73;43034:18;43054;43063:8;43054;:18::i;:::-;43026:47;;;;;;42744:337;;;;;;:::o;29197:142::-;29257:7;-1:-1:-1;;;;;29284:25:0;;-1:-1:-1;;;;;;;;;;;29284:25:0;:47;;29327:4;29284:47;;;21237:42;29277:54;29197:142;-1:-1:-1;;29197:142:0:o;22227:212::-;-1:-1:-1;;;;;22309:31:0;;-1:-1:-1;;;;;;;;;;;22309:31:0;22305:127;;22357:63;-1:-1:-1;;;;;22357:29:0;;21615:42;22412:7;22357:63;:29;:63;:::i;26287:1393::-;26424:12;;;;26544:5;:24;;;;;;;;;26540:197;;;26585:53;26598:7;:16;;;26616:2;26620:7;:17;;;26585:12;:53::i;:::-;26540:197;;;26671:54;26684:7;:16;;;26702:2;26706:7;:18;;;26671:12;:54::i;:::-;26796:20;;;;26753:64;;-1:-1:-1;;;26753:64:0;;21709:42;;26753;;:64;;26796:20;26753:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26749:221;;;26848:7;:20;;;-1:-1:-1;;;;;26848:25:0;26881:10;26893:7;:16;;;26848:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26834:76;;;;;26749:221;;;26953:5;26943:15;;26749:221;27038:17;;;;26982:20;;27068:550;;;;27197:15;;27186:27;;:10;:27::i;:::-;27280:16;;;;27173:40;;-1:-1:-1;;;;;;27280:37:0;-1:-1:-1;;;;;;;;;;;27280:37:0;27276:210;;;27398:53;;-1:-1:-1;;;27398:53:0;;21237:42;;27338:37;;21237:42;;27398:38;;:53;;27445:4;;27398:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27338:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27276:210;27578:28;27589:7;:16;;;27578:10;:28::i;:::-;27563:43;;27068:550;27647:12;;-1:-1:-1;27661:10:0;-1:-1:-1;26287:1393:0;;;;;;;:::o;27946:750::-;28125:15;;;;28068:73;;-1:-1:-1;;;28068:73:0;;28030:17;;21523:42;;28068:56;;:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28060:106;;;;-1:-1:-1;;;28060:106:0;;;;;;;;;28245:15;;;;28262:17;;;;28215:15;;28179:13;;28209:71;;-1:-1:-1;;;;;28209:35:0;;;;:71;:35;:71;:::i;:::-;28314:15;28305:5;:24;;;;;;;;;28301:388;;;28381:7;:15;;;-1:-1:-1;;;;;28361:63:0;;28432:8;28442:7;:15;;;28459:7;:16;;;28477:7;:17;;;28361:134;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28346:149;;28301:388;;;28563:7;:15;;;-1:-1:-1;;;;;28543:62:0;;28613:8;28623:7;:15;;;28640:7;:16;;;28658:7;:18;;;28543:134;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28528:149;;28301:388;27946:750;;;;;:::o;9117:122::-;9176:9;9066:6;9202:23;9206:9;9210:1;9213;9206:3;:9::i;:::-;9223:1;9066:6;9217:7;;21944:275;22007:12;-1:-1:-1;;;;;22036:31:0;;-1:-1:-1;;;;;;;;;;;22036:31:0;22032:180;;;-1:-1:-1;22094:21:0;22032:180;;;22158:42;;-1:-1:-1;;;22158:42:0;;-1:-1:-1;;;;;22158:27:0;;;;;:42;;22194:4;;22158:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8094:113;8187:5;;;8182:16;;;;8174:25;;;;;16323:176;16405:86;16425:5;16455:23;;;16480:2;16484:5;16432:58;;;;;;;;;;;;;;-1:-1:-1;;16432:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;16432:58:0;-1:-1:-1;;;;;;16432:58:0;;;;;;;;;;16405:19;:86::i;:::-;16323:176;;;:::o;16872:184::-;16958:90;16978:5;17008:22;;;17032:7;17041:5;16985:62;;;;;;;;;;8336:127;8394:9;8424:6;;;:30;;-1:-1:-1;;8439:5:0;;;8453:1;8448;8439:5;8448:1;8434:15;;;;;:20;8424:30;8416:39;;;;;42013:620;42093:9;42104:10;;:::i;:::-;42411:14;42427;42445:25;38635:4;42463:6;42445:7;:25::i;:::-;42410:60;;-1:-1:-1;42410:60:0;-1:-1:-1;42493:18:0;42485:4;:26;;;;;;;;;42481:92;;-1:-1:-1;42542:18:0;;;;;;;;;-1:-1:-1;42542:18:0;;42536:4;;-1:-1:-1;42542:18:0;-1:-1:-1;42528:33:0;;42481:92;42590:35;42597:9;42608:7;:16;;;42590:6;:35::i;45509:213::-;45691:12;38635:4;45691:23;;;45509:213::o;28704:397::-;28813:6;28822:2;28813:11;28801:2;:9;:23;28797:104;;;28841:48;;-1:-1:-1;;;28841:48:0;;;;;;;;28797:104;29060:15;;28967:2;29060:15;29053:30;29038:56::o;17695:419::-;17777:23;17803:69;17831:4;17803:69;;;;;;;;;;;;;;;;;17811:5;-1:-1:-1;;;;;17803:27:0;;;:69;;;;;:::i;:::-;17887:17;;17777:95;;-1:-1:-1;17887:21:0;17883:224;;18029:10;18018:30;;;;;;;;;;;;;;18010:85;;;;-1:-1:-1;;;18010:85:0;;;;;;;;36856:343;36912:9;;36944:6;36940:69;;-1:-1:-1;36975:18:0;;-1:-1:-1;36975:18:0;36967:30;;36940:69;37030:5;;;37034:1;37030;:5;:1;37052:5;;;;;:10;37048:144;;-1:-1:-1;37087:26:0;;-1:-1:-1;37115:1:0;;-1:-1:-1;37079:38:0;;37048:144;37158:18;;-1:-1:-1;37178:1:0;-1:-1:-1;37150:30:0;;38989:515;39050:9;39061:10;;:::i;:::-;39085:14;39101:20;39125:22;39133:3;38635:4;39125:7;:22::i;:::-;39084:63;;-1:-1:-1;39084:63:0;-1:-1:-1;39170:18:0;39162:4;:26;;;;;;;;;39158:92;;-1:-1:-1;39219:18:0;;;;;;;;;-1:-1:-1;39219:18:0;;39213:4;;-1:-1:-1;39219:18:0;-1:-1:-1;39205:33:0;;39158:92;39263:14;39279:13;39296:31;39304:15;39321:5;39296:7;:31::i;:::-;39262:65;;-1:-1:-1;39262:65:0;-1:-1:-1;39350:18:0;39342:4;:26;;;;;;;;;39338:92;;39393:4;39399:18;;;;;;;;39414:1;39399:18;;;39385:33;;;;;;;;;;39338:92;39470:25;;;;;;;;;;;;-1:-1:-1;;39470:25:0;;-1:-1:-1;38989:515:0;-1:-1:-1;;;;;;38989:515:0:o;12694:196::-;12797:12;12829:53;12852:6;12860:4;12866:1;12869:12;12829:22;:53::i;:::-;12822:60;12694:196;-1:-1:-1;;;;12694:196:0:o;37294:215::-;37350:9;;37382:6;37378:77;;-1:-1:-1;37413:26:0;;-1:-1:-1;37441:1:0;37405:38;;37378:77;37475:18;37499:1;37495;:5;;;;;;37467:34;;;;37294:215;;;;;:::o;13456:979::-;13586:12;13619:18;13630:6;13619:10;:18::i;:::-;13611:60;;;;-1:-1:-1;;;13611:60:0;;;;;;;;;13745:12;13759:23;13786:6;-1:-1:-1;;;;;13786:11:0;13806:8;13817:4;13786:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13744:78;;;;13837:7;13833:595;;;13868:10;-1:-1:-1;13861:17:0;;-1:-1:-1;13861:17:0;13833:595;13982:17;;:21;13978:439;;14245:10;14239:17;14306:15;14293:10;14289:2;14285:19;14278:44;14193:148;14388:12;14381:20;;-1:-1:-1;;;14381:20:0;;;;;;;;;11481:619;11541:4;12009:20;;11852:66;12049:23;;;;;;:42;;-1:-1:-1;;12076:15:0;;;12041:51;-1:-1:-1;;11481:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;;1810:440;;1911:3;1904:4;1896:6;1892:17;1888:27;1878:2;;-1:-1;;1919:12;1878:2;1966:6;1953:20;32684:18;32676:6;32673:30;32670:2;;;-1:-1;;32706:12;32670:2;1988:64;32779:9;32760:17;;-1:-1;;32756:33;32847:4;32837:15;1988:64;;;1979:73;;2072:6;2065:5;2058:21;2176:3;32847:4;2167:6;2100;2158:16;;2155:25;2152:2;;;2193:1;;2183:12;2152:2;37560:6;32847:4;2100:6;2096:17;32847:4;2134:5;2130:16;37537:30;37616:1;37598:16;;;32847:4;37598:16;37591:27;2134:5;1871:379;-1:-1;;1871:379;2656:1626;;2775:6;;2763:9;2758:3;2754:19;2750:32;2747:2;;;-1:-1;;2785:12;2747:2;2813:22;2775:6;2813:22;;;2804:31;;;2920:49;2965:3;2941:22;2920:49;;;2902:16;2895:75;3068:49;3113:3;3035:2;3093:9;3089:22;3068:49;;;3035:2;3054:5;3050:16;3043:75;3184:2;3242:9;3238:22;4356:20;3184:2;3203:5;3199:16;3192:75;3334:2;3392:9;3388:22;4356:20;3334:2;3353:5;3349:16;3342:75;3482:3;3541:9;3537:22;4356:20;3482:3;3502:5;3498:16;3491:75;3664:49;3709:3;3630;3689:9;3685:22;3664:49;;;3630:3;3650:5;3646:16;3639:75;3817:49;3862:3;3783;3842:9;3838:22;3817:49;;;3783:3;3803:5;3799:16;3792:75;3960:3;3949:9;3945:19;3932:33;3985:18;3977:6;3974:30;3971:2;;;2888:1;;4007:12;3971:2;4052:58;4106:3;4097:6;4086:9;4082:22;4052:58;;;3960:3;4038:5;4034:16;4027:84;;4175:3;;4236:9;4232:22;4356:20;4175:3;4195:5;4191:18;4184:77;;2741:1541;;;;;4567:241;;4671:2;4659:9;4650:7;4646:23;4642:32;4639:2;;;-1:-1;;4677:12;4639:2;85:6;72:20;97:33;124:5;97:33;;;4729:63;4633:175;-1:-1;;;4633:175;4815:263;;4930:2;4918:9;4909:7;4905:23;4901:32;4898:2;;;-1:-1;;4936:12;4898:2;226:6;220:13;238:33;265:5;238:33;;5085:366;;;5206:2;5194:9;5185:7;5181:23;5177:32;5174:2;;;-1:-1;;5212:12;5174:2;85:6;72:20;97:33;124:5;97:33;;;5264:63;-1:-1;5364:2;5403:22;;72:20;97:33;72:20;97:33;;;5372:63;;;;5168:283;;;;;;5458:392;;5598:2;;5586:9;5577:7;5573:23;5569:32;5566:2;;;-1:-1;;5604:12;5566:2;5655:17;5649:24;5693:18;5685:6;5682:30;5679:2;;;-1:-1;;5715:12;5679:2;5817:6;5806:9;5802:22;1072:3;1065:4;1057:6;1053:17;1049:27;1039:2;;-1:-1;;1080:12;1039:2;1120:6;1114:13;1100:27;;1142:80;1157:64;1214:6;1157:64;;;1142:80;;;1250:21;;;1307:14;;;;1282:17;;;1396;;;1387:27;;;;1384:36;-1:-1;1381:2;;;-1:-1;;1423:12;1381:2;-1:-1;1449:10;;1443:217;1468:6;1465:1;1462:13;1443:217;;;4504:13;;1536:61;;1490:1;1483:9;;;;;1611:14;;;;1639;;1443:217;;;-1:-1;5735:99;5560:290;-1:-1;;;;;;;5560:290;5857:257;;5969:2;5957:9;5948:7;5944:23;5940:32;5937:2;;;-1:-1;;5975:12;5937:2;1755:6;1749:13;38219:5;35131:13;35124:21;38197:5;38194:32;38184:2;;-1:-1;;38230:12;6121:393;;;6250:2;6238:9;6229:7;6225:23;6221:32;6218:2;;;-1:-1;;6256:12;6218:2;1755:6;1749:13;38219:5;35131:13;35124:21;38197:5;38194:32;38184:2;;-1:-1;;38230:12;38184:2;6416;6466:22;;;;4504:13;6308:71;;4504:13;;-1:-1;;;6212:302;7133:387;;7267:2;7255:9;7246:7;7242:23;7238:32;7235:2;;;-1:-1;;7273:12;7235:2;7331:17;7318:31;7369:18;7361:6;7358:30;7355:2;;;-1:-1;;7391:12;7355:2;7421:83;7496:7;7487:6;7476:9;7472:22;7421:83;;7527:684;;;;7718:3;7706:9;7697:7;7693:23;7689:33;7686:2;;;-1:-1;;7725:12;7686:2;7783:17;7770:31;7821:18;7813:6;7810:30;7807:2;;;-1:-1;;7843:12;7807:2;7873:83;7948:7;7939:6;7928:9;7924:22;7873:83;;;7863:93;;;7993:2;417:3;398:17;8059:9;398:17;394:27;384:2;;-1:-1;;425:12;384:2;459:4;478:78;493:62;459:4;493:62;;478:78;562:16;7993:2;8059:9;8055:22;650:27;8059:9;650:27;679:3;650:27;647:36;644:2;;;-1:-1;;686:12;644:2;-1:-1;706:206;459:4;728:1;725:13;706:206;;;811:37;844:3;832:10;811:37;;;799:50;;863:14;;;;891;;;;753:1;746:9;706:206;;;-1:-1;7680:531;;8001:86;;-1:-1;;4356:20;;;-1:-1;;;;;;7680:531;8218:263;;8333:2;8321:9;8312:7;8308:23;8304:32;8301:2;;;-1:-1;;8339:12;8301:2;-1:-1;4504:13;;8295:186;-1:-1;8295:186;8488:535;;;;8637:2;8625:9;8616:7;8612:23;8608:32;8605:2;;;-1:-1;;8643:12;8605:2;4510:6;4504:13;8695:74;;8806:2;8860:9;8856:22;4504:13;8814:74;;8925:2;8979:9;8975:22;4504:13;8933:74;;8599:424;;;;;;11407:343;;11549:5;33349:12;34155:6;34150:3;34143:19;11642:52;11687:6;34192:4;34187:3;34183:14;34192:4;11668:5;11664:16;11642:52;;;32779:9;37977:14;-1:-1;;37973:28;11706:39;;;;34192:4;11706:39;;11497:253;-1:-1;;11497:253;16743:271;;11917:5;33349:12;12028:52;12073:6;12068:3;12061:4;12054:5;12050:16;12028:52;;;12092:16;;;;;16877:137;-1:-1;;16877:137;17021:381;-1:-1;;;13461:45;;13445:2;13525:12;;17210:192;17409:222;-1:-1;;;;;35602:54;;;;9448:45;;17536:2;17521:18;;17507:124;18144:866;-1:-1;;;;;35602:54;;;9291:58;;35602:54;;18643:2;18628:18;;9291:58;18462:3;18680:2;18665:18;;18658:48;;;13776:2;18447:19;;;34143;-1:-1;;;35613:42;34183:14;;13792:41;13852:12;18884:2;18869:18;;18862:48;;;18144:866;;18924:76;;13852:12;;18986:6;18924:76;;;18916:84;18433:577;-1:-1;;;;;18433:577;19017:866;-1:-1;;;;;35602:54;;;9291:58;;35602:54;;19516:2;19501:18;;9291:58;19335:3;19553:2;19538:18;;19531:48;;;14103:2;19320:19;;;34143;-1:-1;;;35613:42;34183:14;;14119:36;14174:12;19757:2;19742:18;;19735:48;;;19017:866;;19797:76;;14174:12;;19859:6;19797:76;;19890:866;-1:-1;;;;;35602:54;;;9291:58;;35602:54;;20389:2;20374:18;;9291:58;20208:3;20426:2;20411:18;;20404:48;;;15089:2;20193:19;;;34143;-1:-1;;;35613:42;34183:14;;15105:36;15160:12;20630:2;20615:18;;20608:48;;;19890:866;;20670:76;;15160:12;;20732:6;20670:76;;20763:866;-1:-1;;;;;35602:54;;;9291:58;;35602:54;;21262:2;21247:18;;9291:58;21081:3;21299:2;21284:18;;21277:48;;;16521:2;21066:19;;;34143;-1:-1;;;35613:42;34183:14;;16537:41;16597:12;21503:2;21488:18;;21481:48;;;20763:866;;21543:76;;16597:12;;21605:6;21543:76;;21636:672;-1:-1;;;;;35602:54;;;9448:45;;35602:54;;22062:2;22047:18;;9448:45;22145:2;22130:18;;16694:37;;;21881:3;22182:2;22167:18;;22160:48;;;21636:672;;22222:76;;21866:19;;22284:6;22222:76;;;22214:84;21852:456;-1:-1;;;;;;21852:456;22315:442;-1:-1;;;;;35602:54;;;9448:45;;35602:54;;;;22661:2;22646:18;;9448:45;-1:-1;;;;;;35218:78;;;22743:2;22728:18;;11346:49;22497:2;22482:18;;22468:289;22764:444;-1:-1;;;;;35602:54;;;9448:45;;35602:54;;;;23111:2;23096:18;;9448:45;23194:2;23179:18;;16694:37;;;;22947:2;22932:18;;22918:290;23215:556;-1:-1;;;;;35602:54;;;9448:45;;35602:54;;;;23591:2;23576:18;;9448:45;23674:2;23659:18;;16694:37;23757:2;23742:18;;16694:37;;;;23426:3;23411:19;;23397:374;23778:333;-1:-1;;;;;35602:54;;;;9448:45;;24097:2;24082:18;;16694:37;23933:2;23918:18;;23904:207;24118:370;24295:2;24309:47;;;33349:12;;24280:18;;;34143:19;;;24118:370;;24295:2;33088:14;;;;34183;;;;24118:370;10875:260;10900:6;10897:1;10894:13;10875:260;;;10961:13;;-1:-1;;;;;35602:54;9448:45;;33734:14;;;;9184;;;;32684:18;10915:9;10875:260;;;-1:-1;24362:116;;24266:222;-1:-1;;;;;;24266:222;24495:306;;24640:2;24661:17;24654:47;24715:76;24640:2;24629:9;24625:18;24777:6;24715:76;;24808:865;;25121:3;25143:17;25136:47;25197:76;25121:3;25110:9;25106:19;25259:6;25197:76;;;25189:84;-1:-1;25398:2;25383:18;;;10131:21;10173:1;10158:258;33225:4;10180:1;10177:13;10158:258;;;10244:13;;-1:-1;;;;;35602:54;9448:45;;9184:14;;;;33734;;;;32684:18;10198:9;10158:258;;;-1:-1;;;;25481:2;25466:18;;16694:37;;;;35131:13;;35124:21;25558:3;25543:19;;11230:34;-1:-1;;;;;35602:54;35613:42;25643:19;;;9448:45;25092:581;;-1:-1;;25092:581;25680:501;;25871:2;25892:17;25885:47;25946:76;25871:2;25860:9;25856:18;26008:6;25946:76;;;26070:9;26064:4;26060:20;26055:2;26044:9;26040:18;26033:48;26095:76;26166:4;26157:6;26095:76;;27599:416;27799:2;27813:47;;;14425:2;27784:18;;;34143:19;-1:-1;;;34183:14;;;14441:43;14503:12;;;27770:245;28022:416;28222:2;28236:47;;;14754:2;28207:18;;;34143:19;14790:28;34183:14;;;14770:49;14838:12;;;28193:245;28445:416;28645:2;28659:47;;;15411:2;28630:18;;;34143:19;15447:34;34183:14;;;15427:55;-1:-1;;;15502:12;;;15495:30;15544:12;;;28616:245;28868:416;29068:2;29082:47;;;15795:2;29053:18;;;34143:19;15831:31;34183:14;;;15811:52;15882:12;;;29039:245;29291:416;29491:2;29505:47;;;16133:2;29476:18;;;34143:19;16169:34;34183:14;;;16149:55;-1:-1;;;16224:12;;;16217:34;16270:12;;;29462:245;29714:222;16694:37;;;29841:2;29826:18;;29812:124;29943:752;16694:37;;;-1:-1;;;;;35602:54;;;30365:2;30350:18;;9448:45;35602:54;;30448:2;30433:18;;9448:45;35613:42;30485:2;30470:18;;30463:48;;;29943:752;;30525:76;;30185:19;;30587:6;30525:76;;;30517:84;;16724:5;30680:3;30669:9;30665:19;16694:37;30171:524;;;;;;;;;30702:444;16694:37;;;31049:2;31034:18;;16694:37;;;;-1:-1;;;;;35602:54;31132:2;31117:18;;9448:45;30885:2;30870:18;;30856:290;31153:556;16694:37;;;31529:2;31514:18;;16694:37;;;;-1:-1;;;;;35602:54;;;31612:2;31597:18;;9448:45;35602:54;31695:2;31680:18;;9448:45;31364:3;31349:19;;31335:374;31716:256;31778:2;31772:9;31804:17;;;31879:18;31864:34;;31900:22;;;31861:62;31858:2;;;31936:1;;31926:12;31858:2;31778;31945:22;31756:216;;-1:-1;31756:216;31979:244;;32136:18;32128:6;32125:30;32122:2;;;-1:-1;;32158:12;32122:2;-1:-1;32203:4;32191:17;;32059:164;32230:304;;32389:18;32381:6;32378:30;32375:2;;;-1:-1;;32411:12;32375:2;-1:-1;32456:4;32444:17;;;32509:15;;32312:222;37633:268;37698:1;37705:101;37719:6;37716:1;37713:13;37705:101;;;37786:11;;;37780:18;37767:11;;;37760:39;37741:2;37734:10;37705:101;;;37821:6;37818:1;37815:13;37812:2;;;-1:-1;;37698:1;37868:16;;37861:27;37682:219;38014:117;-1:-1;;;;;35602:54;;38073:35;;38063:2;;38122:1;;38112:12
Swarm Source
ipfs://96282b08366ec04afe322c49cea0b1a6b56e43da324f10dff266e71caf065e3b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 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.