Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
TrueFiPool2
Compiler Version
v0.6.10+commit.00c0fcaf
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import {SafeMath} from "SafeMath.sol"; import {SafeERC20} from "SafeERC20.sol"; import {ERC20} from "UpgradeableERC20.sol"; import {UpgradeableClaimable} from "UpgradeableClaimable.sol"; import {ITrueStrategy} from "ITrueStrategy.sol"; import {ITrueFiPool2, ITrueFiPoolOracle} from "ITrueFiPool2.sol"; import {ITrueLender2, ILoanToken2} from "ITrueLender2.sol"; import {IPauseableContract} from "IPauseableContract.sol"; import {ISAFU} from "ISAFU.sol"; import {IDeficiencyToken} from "IDeficiencyToken.sol"; import {ITrueCreditAgency} from "ITrueCreditAgency.sol"; import {ABDKMath64x64} from "Log.sol"; import {OneInchExchange} from "OneInchExchange.sol"; import {PoolExtensions} from "PoolExtensions.sol"; /** * @title TrueFiPool2 * @dev Lending pool which may use a strategy to store idle funds * Earn high interest rates on currency deposits through uncollateralized loans * * Funds deposited in this pool are not fully liquid. * Exiting incurs an exit penalty depending on pool liquidity * After exiting, an account will need to wait for LoanTokens to expire and burn them * It is recommended to perform a zap or swap tokens on Uniswap for increased liquidity * * Funds are managed through an external function to save gas on deposits */ contract TrueFiPool2 is ITrueFiPool2, IPauseableContract, ERC20, UpgradeableClaimable { using SafeMath for uint256; using SafeERC20 for ERC20; using SafeERC20 for IDeficiencyToken; uint256 private constant BASIS_PRECISION = 10000; // max slippage on liquidation token swaps // Measured in basis points, e.g. 10000 = 100% uint16 public constant TOLERATED_SLIPPAGE = 100; // 1% // tolerance difference between // expected and actual transaction results // when dealing with strategies // Measured in basis points, e.g. 10000 = 100% uint16 public constant TOLERATED_STRATEGY_LOSS = 10; // 0.1% // ================ WARNING ================== // ===== THIS CONTRACT IS INITIALIZABLE ====== // === STORAGE VARIABLES ARE DECLARED BELOW == // REMOVAL OR REORDER OF VARIABLES WILL RESULT // ========= IN STORAGE CORRUPTION =========== uint8 public constant VERSION = 1; ERC20 public override token; ITrueStrategy public strategy; ITrueLender2 public lender; // fee for deposits // fee precision: 10000 = 100% uint256 public joiningFee; // track claimable fees uint256 public claimableFees; mapping(address => uint256) latestJoinBlock; address private DEPRECATED__liquidationToken; ITrueFiPoolOracle public override oracle; // allow pausing of deposits bool public pauseStatus; // cache values during sync for gas optimization bool private inSync; uint256 private strategyValueCache; uint256 private loansValueCache; // who gets all fees address public beneficiary; address private DEPRECATED__1Inch; ISAFU public safu; ITrueCreditAgency public creditAgency; // ======= STORAGE DECLARATION END =========== /** * @dev Helper function to concatenate two strings * @param a First part of string to concat * @param b Second part of string to concat * @return Concatenated string of `a` and `b` */ function concat(string memory a, string memory b) internal pure returns (string memory) { return string(abi.encodePacked(a, b)); } function initialize( ERC20 _token, ITrueLender2 _lender, ISAFU _safu, address __owner ) external override initializer { ERC20.__ERC20_initialize(concat("TrueFi ", _token.name()), concat("tf", _token.symbol())); UpgradeableClaimable.initialize(__owner); token = _token; lender = _lender; safu = _safu; } /** * @dev Initializer for single borrower pools */ function singleBorrowerInitialize( ERC20 _token, ITrueLender2 _lender, ISAFU _safu, address __owner, string memory borrowerName, string memory borrowerSymbol ) external override initializer { ERC20.__ERC20_initialize( concat(concat("TrueFi ", borrowerName), concat(" ", _token.name())), concat(concat("tf", borrowerSymbol), _token.symbol()) ); UpgradeableClaimable.initialize(__owner); token = _token; lender = _lender; safu = _safu; } /** * @dev Emitted when fee is changed * @param newFee New fee */ event JoiningFeeChanged(uint256 newFee); /** * @dev Emitted when beneficiary is changed * @param newBeneficiary New beneficiary */ event BeneficiaryChanged(address newBeneficiary); /** * @dev Emitted when oracle is changed * @param newOracle New oracle */ event OracleChanged(ITrueFiPoolOracle newOracle); /** * @dev Emitted when someone joins the pool * @param staker Account staking * @param deposited Amount deposited * @param minted Amount of pool tokens minted */ event Joined(address indexed staker, uint256 deposited, uint256 minted); /** * @dev Emitted when someone exits the pool * @param staker Account exiting * @param amount Amount unstaking */ event Exited(address indexed staker, uint256 amount); /** * @dev Emitted when funds are flushed into the strategy * @param currencyAmount Amount of tokens deposited */ event Flushed(uint256 currencyAmount); /** * @dev Emitted when funds are pulled from the strategy * @param minTokenAmount Minimal expected amount received tokens */ event Pulled(uint256 minTokenAmount); /** * @dev Emitted when funds are borrowed from pool * @param borrower Borrower address * @param amount Amount of funds borrowed from pool */ event Borrow(address borrower, uint256 amount); /** * @dev Emitted when borrower repays the pool * @param payer Address of borrower * @param amount Amount repaid */ event Repaid(address indexed payer, uint256 amount); /** * @dev Emitted when fees are collected * @param beneficiary Account to receive fees * @param amount Amount of fees collected */ event Collected(address indexed beneficiary, uint256 amount); /** * @dev Emitted when strategy is switched * @param newStrategy Strategy to switch to */ event StrategySwitched(ITrueStrategy newStrategy); /** * @dev Emitted when joining is paused or unpaused * @param pauseStatus New pausing status */ event PauseStatusChanged(bool pauseStatus); /** * @dev Emitted when SAFU address is changed * @param newSafu New SAFU address */ event SafuChanged(ISAFU newSafu); /** * @dev Emitted when pool reclaims deficit from SAFU * @param loan Loan for which the deficit was reclaimed * @param deficit Amount reclaimed */ event DeficitReclaimed(ILoanToken2 loan, uint256 deficit); /** * @dev Emitted when Credit Agency address is changed * @param newCreditAgency New Credit Agency address */ event CreditAgencyChanged(ITrueCreditAgency newCreditAgency); /** * @dev only TrueLender of CreditAgency can perform borrowing or repaying */ modifier onlyLenderOrTrueCreditAgency() { require( msg.sender == address(lender) || msg.sender == address(creditAgency), "TrueFiPool: Caller is not the lender or creditAgency" ); _; } /** * @dev pool can only be joined when it's unpaused */ modifier joiningNotPaused() { require(!pauseStatus, "TrueFiPool: Joining the pool is paused"); _; } /** * Sync values to avoid making expensive calls multiple times * Will set inSync to true, allowing getter functions to return cached values * Wipes cached values to save gas */ modifier sync() { // sync strategyValueCache = strategyValue(); loansValueCache = loansValue(); inSync = true; _; // wipe inSync = false; strategyValueCache = 0; loansValueCache = 0; } /** * @dev Allow pausing of deposits in case of emergency * @param status New deposit status */ function setPauseStatus(bool status) external override onlyOwner { pauseStatus = status; emit PauseStatusChanged(status); } /** * @dev Change SAFU address */ function setSafuAddress(ISAFU _safu) external onlyOwner { safu = _safu; emit SafuChanged(_safu); } function setCreditAgency(ITrueCreditAgency _creditAgency) external onlyOwner { creditAgency = _creditAgency; emit CreditAgencyChanged(_creditAgency); } /** * @dev Number of decimals for user-facing representations. * Delegates to the underlying pool token. */ function decimals() public override view returns (uint8) { return token.decimals(); } /** * @dev Virtual value of liquid assets in the pool * @return Virtual liquid value of pool assets */ function liquidValue() public view returns (uint256) { return currencyBalance().add(strategyValue()); } /** * @dev Value of funds deposited into the strategy denominated in underlying token * @return Virtual value of strategy */ function strategyValue() public view returns (uint256) { if (address(strategy) == address(0)) { return 0; } if (inSync) { return strategyValueCache; } return strategy.value(); } /** * @dev Calculate pool value in underlying token * "virtual price" of entire pool - LoanTokens, UnderlyingTokens, strategy value * @return pool value denominated in underlying token */ function poolValue() public override view returns (uint256) { // this assumes defaulted loans are worth their full value return liquidValue().add(loansValue()).add(deficitValue()).add(creditValue()); } /** * @dev Return pool deficiency value, to be returned by safu * @return pool deficiency value */ function deficitValue() public view returns (uint256) { if (address(safu) == address(0)) { return 0; } return safu.poolDeficit(address(this)); } /** * @dev Return pool credit line value * @return pool credit value */ function creditValue() public view returns (uint256) { if (address(creditAgency) == address(0)) { return 0; } return creditAgency.poolCreditValue(ITrueFiPool2(this)); } /** * @dev Virtual value of loan assets in the pool * Will return cached value if inSync * @return Value of loans in pool */ function loansValue() public view returns (uint256) { if (inSync) { return loansValueCache; } return lender.value(this); } /** * @dev ensure enough tokens are available * Check if current available amount of `token` is enough and * withdraw remainder from strategy * @param neededAmount amount required */ function ensureSufficientLiquidity(uint256 neededAmount) internal { uint256 currentlyAvailableAmount = currencyBalance(); if (currentlyAvailableAmount < neededAmount) { require(address(strategy) != address(0), "TrueFiPool: Pool has no strategy to withdraw from"); strategy.withdraw(neededAmount.sub(currentlyAvailableAmount)); require(currencyBalance() >= neededAmount, "TrueFiPool: Not enough funds taken from the strategy"); } } /** * @dev set pool join fee * @param fee new fee */ function setJoiningFee(uint256 fee) external onlyOwner { require(fee <= BASIS_PRECISION, "TrueFiPool: Fee cannot exceed transaction value"); joiningFee = fee; emit JoiningFeeChanged(fee); } /** * @dev set beneficiary * @param newBeneficiary new beneficiary */ function setBeneficiary(address newBeneficiary) external onlyOwner { require(newBeneficiary != address(0), "TrueFiPool: Beneficiary address cannot be set to 0"); beneficiary = newBeneficiary; emit BeneficiaryChanged(newBeneficiary); } /** * @dev Join the pool by depositing tokens * @param amount amount of token to deposit */ function join(uint256 amount) external override joiningNotPaused { uint256 fee = amount.mul(joiningFee).div(BASIS_PRECISION); uint256 mintedAmount = mint(amount.sub(fee)); claimableFees = claimableFees.add(fee); // TODO: tx.origin will be depricated in a future ethereum upgrade latestJoinBlock[tx.origin] = block.number; token.safeTransferFrom(msg.sender, address(this), amount); emit Joined(msg.sender, amount, mintedAmount); } /** * @dev Exit pool only with liquid tokens * This function will only transfer underlying token but with a small penalty * Uses the sync() modifier to reduce gas costs of using strategy and lender * @param amount amount of pool liquidity tokens to redeem for underlying tokens */ function liquidExit(uint256 amount) external sync { require(block.number != latestJoinBlock[tx.origin], "TrueFiPool: Cannot join and exit in same block"); require(amount <= balanceOf(msg.sender), "TrueFiPool: Insufficient funds"); uint256 amountToWithdraw = poolValue().mul(amount).div(totalSupply()); amountToWithdraw = amountToWithdraw.mul(liquidExitPenalty(amountToWithdraw)).div(BASIS_PRECISION); require(amountToWithdraw <= liquidValue(), "TrueFiPool: Not enough liquidity in pool"); // burn tokens sent _burn(msg.sender, amount); ensureSufficientLiquidity(amountToWithdraw); token.safeTransfer(msg.sender, amountToWithdraw); emit Exited(msg.sender, amountToWithdraw); } /** * @dev Penalty (in % * 100) applied if liquid exit is performed with this amount * returns BASIS_PRECISION (10000) if no penalty */ function liquidExitPenalty(uint256 amount) public view returns (uint256) { uint256 lv = liquidValue(); uint256 pv = poolValue(); if (amount == pv) { return BASIS_PRECISION; } uint256 liquidRatioBefore = lv.mul(BASIS_PRECISION).div(pv); uint256 liquidRatioAfter = lv.sub(amount).mul(BASIS_PRECISION).div(pv.sub(amount)); return BASIS_PRECISION.sub(averageExitPenalty(liquidRatioAfter, liquidRatioBefore)); } /** * @dev Calculates integral of 5/(x+50)dx times 10000 */ function integrateAtPoint(uint256 x) public pure returns (uint256) { return uint256(ABDKMath64x64.ln(ABDKMath64x64.fromUInt(x.add(50)))).mul(50000).div(2**64); } /** * @dev Calculates average penalty on interval [from; to] * @return average exit penalty */ function averageExitPenalty(uint256 from, uint256 to) public pure returns (uint256) { require(from <= to, "TrueFiPool: To precedes from"); if (from == BASIS_PRECISION) { // When all liquid, don't penalize return 0; } if (from == to) { return uint256(50000).div(from.add(50)); } return integrateAtPoint(to).sub(integrateAtPoint(from)).div(to.sub(from)); } /** * @dev Deposit idle funds into strategy * @param amount Amount of funds to deposit into strategy */ function flush(uint256 amount) external { require(address(strategy) != address(0), "TrueFiPool: Pool has no strategy set up"); require(amount <= currencyBalance(), "TrueFiPool: Insufficient currency balance"); uint256 expectedMinStrategyValue = strategy.value().add(withToleratedStrategyLoss(amount)); token.safeApprove(address(strategy), amount); strategy.deposit(amount); require(strategy.value() >= expectedMinStrategyValue, "TrueFiPool: Strategy value expected to be higher"); emit Flushed(amount); } /** * @dev Remove liquidity from strategy * @param minTokenAmount minimum amount of tokens to withdraw */ function pull(uint256 minTokenAmount) external onlyOwner { require(address(strategy) != address(0), "TrueFiPool: Pool has no strategy set up"); uint256 expectedCurrencyBalance = currencyBalance().add(minTokenAmount); strategy.withdraw(minTokenAmount); require(currencyBalance() >= expectedCurrencyBalance, "TrueFiPool: Currency balance expected to be higher"); emit Pulled(minTokenAmount); } /** * @dev Remove liquidity from strategy if necessary and transfer to lender * @param amount amount for lender to withdraw */ function borrow(uint256 amount) external override onlyLenderOrTrueCreditAgency { require(amount <= liquidValue(), "TrueFiPool: Insufficient liquidity"); if (amount > 0) { ensureSufficientLiquidity(amount); } token.safeTransfer(msg.sender, amount); emit Borrow(msg.sender, amount); } /** * @dev repay debt by transferring tokens to the contract * @param currencyAmount amount to repay */ function repay(uint256 currencyAmount) external override onlyLenderOrTrueCreditAgency { token.safeTransferFrom(msg.sender, address(this), currencyAmount); emit Repaid(msg.sender, currencyAmount); } /** * @dev Claim fees from the pool */ function collectFees() external { require(beneficiary != address(0), "TrueFiPool: Beneficiary is not set"); uint256 amount = claimableFees; claimableFees = 0; if (amount > 0) { token.safeTransfer(beneficiary, amount); } emit Collected(beneficiary, amount); } /** * @dev Switches current strategy to a new strategy * @param newStrategy strategy to switch to */ function switchStrategy(ITrueStrategy newStrategy) external onlyOwner { require(strategy != newStrategy, "TrueFiPool: Cannot switch to the same strategy"); ITrueStrategy previousStrategy = strategy; strategy = newStrategy; if (address(previousStrategy) != address(0)) { uint256 expectedMinCurrencyBalance = currencyBalance().add(withToleratedStrategyLoss(previousStrategy.value())); previousStrategy.withdrawAll(); require(currencyBalance() >= expectedMinCurrencyBalance, "TrueFiPool: All funds should be withdrawn to pool"); require(previousStrategy.value() == 0, "TrueFiPool: Switched strategy should be depleted"); } emit StrategySwitched(newStrategy); } /** * @dev Function called by SAFU when liquidation happens. It will transfer all tokens of this loan the SAFU */ function liquidate(ILoanToken2 loan) external override { PoolExtensions._liquidate(safu, loan, lender); } /** * @dev Function called when loan's debt is repaid to SAFU, pool has a deficit value towards that loan */ function reclaimDeficit(ILoanToken2 loan) external { IDeficiencyToken dToken = safu.deficiencyToken(loan); require(address(dToken) != address(0), "TrueFiPool2: No deficiency token found for loan"); uint256 deficit = dToken.balanceOf(address(this)); dToken.safeApprove(address(safu), deficit); safu.reclaim(loan, deficit); emit DeficitReclaimed(loan, deficit); } /** * @dev Change oracle, can only be called by owner */ function setOracle(ITrueFiPoolOracle newOracle) external onlyOwner { oracle = newOracle; emit OracleChanged(newOracle); } /** * @dev Currency token balance * @return Currency token balance */ function currencyBalance() public view returns (uint256) { return token.balanceOf(address(this)).sub(claimableFees); } /** * @dev Utilization of the pool * @return Utilization in basis points */ function utilization() public view returns (uint256) { uint256 pv = poolValue(); return pv.sub(liquidValue()).mul(BASIS_PRECISION).div(pv); } /** * @dev Ratio of liquid assets in the pool to the pool value. * Equals to 1 - utilization. * @return Calculated ratio in basis points */ function liquidRatio() public override view returns (uint256) { uint256 _poolValue = poolValue(); if (_poolValue == 0) { return 0; } return liquidValue().mul(BASIS_PRECISION).div(_poolValue); } /** * @dev Ratio of liquid assets in the pool after lending * @param amount Amount of asset being lent * @return Calculated ratio in basis points */ function proFormaLiquidRatio(uint256 amount) external override view returns (uint256) { uint256 _poolValue = poolValue(); if (_poolValue == 0) { return 0; } return (liquidValue().sub(amount)).mul(BASIS_PRECISION).div(_poolValue); } /** * @param depositedAmount Amount of currency deposited * @return amount minted from this transaction */ function mint(uint256 depositedAmount) internal returns (uint256) { if (depositedAmount == 0) { return depositedAmount; } uint256 mintedAmount = depositedAmount; // first staker mints same amount as deposited if (totalSupply() > 0) { mintedAmount = totalSupply().mul(depositedAmount).div(poolValue()); } // mint pool liquidity tokens _mint(msg.sender, mintedAmount); return mintedAmount; } /** * @dev Decrease provided amount percentwise by error * @param amount Amount to decrease * @return Calculated value */ function withToleratedSlippage(uint256 amount) internal pure returns (uint256) { return amount.mul(BASIS_PRECISION - TOLERATED_SLIPPAGE).div(BASIS_PRECISION); } /** * @dev Decrease provided amount percentwise by error * @param amount Amount to decrease * @return Calculated value */ function withToleratedStrategyLoss(uint256 amount) internal pure returns (uint256) { return amount.mul(BASIS_PRECISION - TOLERATED_STRATEGY_LOSS).div(BASIS_PRECISION); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ 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; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be 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; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ 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"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ 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"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ 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); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "IERC20.sol"; import "SafeMath.sol"; import "Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 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. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 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(IERC20 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)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. 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"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/v3.0.0/contracts/Initializable.sol // Added public isInitialized() view of private initialized bool. // SPDX-License-Identifier: MIT pragma solidity 0.6.10; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } /** * @dev Return true if and only if the contract has been initialized * @return whether the contract has been initialized */ function isInitialized() public view returns (bool) { return initialized; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {Address} from "Address.sol"; import {Context} from "Context.sol"; import {IERC20} from "IERC20.sol"; import {SafeMath} from "SafeMath.sol"; import {Initializable} from "Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; using Address for address; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_initialize(string memory name, string memory symbol) internal initializer { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public virtual view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public override view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public override view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public virtual override view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero") ); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} function updateNameAndSymbol(string memory __name, string memory __symbol) internal { _name = __name; _symbol = __symbol; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {Context} from "Context.sol"; import {Initializable} from "Initializable.sol"; /** * @title UpgradeableClaimable * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. Since * this contract combines Claimable and UpgradableOwnable contracts, ownership * can be later change via 2 step method {transferOwnership} and {claimOwnership} * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract UpgradeableClaimable is Initializable, Context { address private _owner; address private _pendingOwner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting a custom initial owner of choice. * @param __owner Initial owner of contract to be set. */ function initialize(address __owner) internal initializer { _owner = __owner; emit OwnershipTransferred(address(0), __owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view returns (address) { return _pendingOwner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Modifier throws if called by any account other than the pendingOwner. */ modifier onlyPendingOwner() { require(msg.sender == _pendingOwner, "Ownable: caller is not the pending owner"); _; } /** * @dev Allows the current owner to set the pendingOwner address. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _pendingOwner = newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() public onlyPendingOwner { emit OwnershipTransferred(_owner, _pendingOwner); _owner = _pendingOwner; _pendingOwner = address(0); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; interface ITrueStrategy { /** * @dev put `amount` of tokens into the strategy * As a result of the deposit value of the strategy should increase by at least 98% of amount */ function deposit(uint256 amount) external; /** * @dev pull at least `minAmount` of tokens from strategy and transfer to the pool */ function withdraw(uint256 minAmount) external; /** * @dev withdraw everything from strategy * As a result of calling withdrawAll(),at least 98% of strategy's value should be transferred to the pool * Value must become 0 */ function withdrawAll() external; /// @dev value evaluated to Pool's tokens function value() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {IERC20} from "IERC20.sol"; import {ERC20} from "UpgradeableERC20.sol"; import {ITrueFiPool2} from "ITrueFiPool2.sol"; interface ILoanToken2 is IERC20 { enum Status {Awaiting, Funded, Withdrawn, Settled, Defaulted, Liquidated} function borrower() external view returns (address); function amount() external view returns (uint256); function term() external view returns (uint256); function apy() external view returns (uint256); function start() external view returns (uint256); function lender() external view returns (address); function debt() external view returns (uint256); function pool() external view returns (ITrueFiPool2); function profit() external view returns (uint256); function status() external view returns (Status); function getParameters() external view returns ( uint256, uint256, uint256 ); function fund() external; function withdraw(address _beneficiary) external; function settle() external; function enterDefault() external; function liquidate() external; function redeem(uint256 _amount) external; function repay(address _sender, uint256 _amount) external; function repayInFull(address _sender) external; function reclaim() external; function allowTransfer(address account, bool _status) external; function repaid() external view returns (uint256); function isRepaid() external view returns (bool); function balance() external view returns (uint256); function value(uint256 _balance) external view returns (uint256); function token() external view returns (ERC20); function version() external pure returns (uint8); } //interface IContractWithPool { // function pool() external view returns (ITrueFiPool2); //} // //// Had to be split because of multiple inheritance problem //interface ILoanToken2 is ILoanToken, IContractWithPool { // //}
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {ITrueFiPool2} from "ITrueFiPool2.sol"; import {ILoanToken2} from "ILoanToken2.sol"; interface ITrueLender2 { // @dev calculate overall value of the pools function value(ITrueFiPool2 pool) external view returns (uint256); // @dev distribute a basket of tokens for exiting user function distribute( address recipient, uint256 numerator, uint256 denominator ) external; function transferAllLoanTokens(ILoanToken2 loan, address recipient) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {IERC20} from "IERC20.sol"; interface IERC20WithDecimals is IERC20 { function decimals() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {IERC20WithDecimals} from "IERC20WithDecimals.sol"; /** * @dev Oracle that converts any token to and from TRU * Used for liquidations and valuing of liquidated TRU in the pool */ interface ITrueFiPoolOracle { // token address function token() external view returns (IERC20WithDecimals); // amount of tokens 1 TRU is worth function truToToken(uint256 truAmount) external view returns (uint256); // amount of TRU 1 token is worth function tokenToTru(uint256 tokenAmount) external view returns (uint256); // USD price of token with 18 decimals function tokenToUsd(uint256 tokenAmount) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; pragma experimental ABIEncoderV2; interface I1Inch3 { struct SwapDescription { address srcToken; address dstToken; address srcReceiver; address dstReceiver; uint256 amount; uint256 minReturnAmount; uint256 flags; bytes permit; } function swap( address caller, SwapDescription calldata desc, bytes calldata data ) external returns ( uint256 returnAmount, uint256 gasLeft, uint256 chiSpent ); function unoswap( address srcToken, uint256 amount, uint256 minReturn, bytes32[] calldata /* pools */ ) external payable returns (uint256 returnAmount); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {IERC20} from "IERC20.sol"; import {ILoanToken2} from "ILoanToken2.sol"; interface IDeficiencyToken is IERC20 { function loan() external view returns (ILoanToken2); function burnFrom(address account, uint256 amount) external; function version() external pure returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {IDeficiencyToken} from "IDeficiencyToken.sol"; import {ILoanToken2} from "ILoanToken2.sol"; interface ISAFU { function poolDeficit(address pool) external view returns (uint256); function deficiencyToken(ILoanToken2 loan) external view returns (IDeficiencyToken); function reclaim(ILoanToken2 loan, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {ERC20, IERC20} from "UpgradeableERC20.sol"; import {ITrueLender2, ILoanToken2} from "ITrueLender2.sol"; import {ITrueFiPoolOracle} from "ITrueFiPoolOracle.sol"; import {I1Inch3} from "I1Inch3.sol"; import {ISAFU} from "ISAFU.sol"; interface ITrueFiPool2 is IERC20 { function initialize( ERC20 _token, ITrueLender2 _lender, ISAFU safu, address __owner ) external; function singleBorrowerInitialize( ERC20 _token, ITrueLender2 _lender, ISAFU safu, address __owner, string memory borrowerName, string memory borrowerSymbol ) external; function token() external view returns (ERC20); function oracle() external view returns (ITrueFiPoolOracle); function poolValue() external view returns (uint256); /** * @dev Ratio of liquid assets in the pool to the pool value */ function liquidRatio() external view returns (uint256); /** * @dev Ratio of liquid assets in the pool after lending * @param amount Amount of asset being lent */ function proFormaLiquidRatio(uint256 amount) external view returns (uint256); /** * @dev Join the pool by depositing tokens * @param amount amount of tokens to deposit */ function join(uint256 amount) external; /** * @dev borrow from pool * 1. Transfer TUSD to sender * 2. Only lending pool should be allowed to call this */ function borrow(uint256 amount) external; /** * @dev pay borrowed money back to pool * 1. Transfer TUSD from sender * 2. Only lending pool should be allowed to call this */ function repay(uint256 currencyAmount) external; /** * @dev SAFU buys LoanTokens from the pool */ function liquidate(ILoanToken2 loan) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; /** * @dev interface to allow standard pause function */ interface IPauseableContract { function setPauseStatus(bool pauseStatus) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {ITrueFiPool2} from "ITrueFiPool2.sol"; interface ITrueCreditAgency { function poolCreditValue(ITrueFiPool2 pool) external view returns (uint256); }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity 0.6.10; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt(uint256 x) internal pure returns (int128) { require(x <= 0x7FFFFFFFFFFFFFFF); return int128(x << 64); } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2(int128 x) internal pure returns (int128) { require(x > 0); int256 msb = 0; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = (msb - 64) << 64; uint256 ux = uint256(x) << uint256(127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256(b); } return int128(result); } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln(int128 x) internal pure returns (int128) { require(x > 0); return int128((uint256(log_2(x)) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import {SafeMath} from "SafeMath.sol"; import {I1Inch3} from "I1Inch3.sol"; import {IERC20} from "IERC20.sol"; import {SafeERC20} from "SafeERC20.sol"; interface IUniRouter { function token0() external view returns (address); function token1() external view returns (address); } library OneInchExchange { using SafeERC20 for IERC20; using SafeMath for uint256; uint256 constant ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; uint256 constant REVERSE_MASK = 0x8000000000000000000000000000000000000000000000000000000000000000; event Swapped(I1Inch3.SwapDescription description, uint256 returnedAmount); /** * @dev Forward data to 1Inch contract * @param _1inchExchange address of 1Inch (currently 0x11111112542d85b3ef69ae05771c2dccff4faa26 for mainnet) * @param data Data that is forwarded into the 1inch exchange contract. Can be acquired from 1Inch API https://api.1inch.exchange/v3.0/1/swap * [See more](https://docs.1inch.exchange/api/quote-swap#swap) * * @return description - description of the swap */ function exchange(I1Inch3 _1inchExchange, bytes calldata data) internal returns (I1Inch3.SwapDescription memory description, uint256 returnedAmount) { if (data[0] == 0x7c) { // call `swap()` (, description, ) = abi.decode(data[4:], (address, I1Inch3.SwapDescription, bytes)); } else { // call `unoswap()` (address srcToken, uint256 amount, uint256 minReturn, bytes32[] memory pathData) = abi.decode( data[4:], (address, uint256, uint256, bytes32[]) ); description.srcToken = srcToken; description.amount = amount; description.minReturnAmount = minReturn; description.flags = 0; uint256 lastPath = uint256(pathData[pathData.length - 1]); IUniRouter uniRouter = IUniRouter(address(lastPath & ADDRESS_MASK)); bool isReverse = lastPath & REVERSE_MASK > 0; description.dstToken = isReverse ? uniRouter.token0() : uniRouter.token1(); description.dstReceiver = address(this); } IERC20(description.srcToken).safeApprove(address(_1inchExchange), description.amount); uint256 balanceBefore = IERC20(description.dstToken).balanceOf(description.dstReceiver); // solhint-disable-next-line avoid-low-level-calls (bool success, ) = address(_1inchExchange).call(data); if (!success) { // Revert with original error message assembly { let ptr := mload(0x40) let size := returndatasize() returndatacopy(ptr, 0, size) revert(ptr, size) } } uint256 balanceAfter = IERC20(description.dstToken).balanceOf(description.dstReceiver); returnedAmount = balanceAfter.sub(balanceBefore); emit Swapped(description, returnedAmount); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.10; import {ILoanToken2} from "ILoanToken2.sol"; import {ITrueLender2} from "ITrueLender2.sol"; import {ISAFU} from "ISAFU.sol"; /** * @dev Library that has shared functions between legacy TrueFi Pool and Pool2 */ library PoolExtensions { function _liquidate( ISAFU safu, ILoanToken2 loan, ITrueLender2 lender ) internal { require(msg.sender == address(safu), "TrueFiPool: Should be called by SAFU"); lender.transferAllLoanTokens(loan, address(safu)); } }
{ "optimizer": { "enabled": true, "runs": 20000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBeneficiary","type":"address"}],"name":"BeneficiaryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Collected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ITrueCreditAgency","name":"newCreditAgency","type":"address"}],"name":"CreditAgencyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ILoanToken2","name":"loan","type":"address"},{"indexed":false,"internalType":"uint256","name":"deficit","type":"uint256"}],"name":"DeficitReclaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Exited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"Flushed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"deposited","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minted","type":"uint256"}],"name":"Joined","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"JoiningFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ITrueFiPoolOracle","name":"newOracle","type":"address"}],"name":"OracleChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"pauseStatus","type":"bool"}],"name":"PauseStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minTokenAmount","type":"uint256"}],"name":"Pulled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISAFU","name":"newSafu","type":"address"}],"name":"SafuChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ITrueStrategy","name":"newStrategy","type":"address"}],"name":"StrategySwitched","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"TOLERATED_SLIPPAGE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOLERATED_STRATEGY_LOSS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"averageExitPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beneficiary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimableFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creditAgency","outputs":[{"internalType":"contract ITrueCreditAgency","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currencyBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deficitValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flush","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"_token","type":"address"},{"internalType":"contract ITrueLender2","name":"_lender","type":"address"},{"internalType":"contract ISAFU","name":"_safu","type":"address"},{"internalType":"address","name":"__owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"integrateAtPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"join","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"joiningFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lender","outputs":[{"internalType":"contract ITrueLender2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"liquidExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"liquidExitPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILoanToken2","name":"loan","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"loansValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract ITrueFiPoolOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"proFormaLiquidRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minTokenAmount","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILoanToken2","name":"loan","type":"address"}],"name":"reclaimDeficit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"currencyAmount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"safu","outputs":[{"internalType":"contract ISAFU","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBeneficiary","type":"address"}],"name":"setBeneficiary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITrueCreditAgency","name":"_creditAgency","type":"address"}],"name":"setCreditAgency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setJoiningFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITrueFiPoolOracle","name":"newOracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setPauseStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISAFU","name":"_safu","type":"address"}],"name":"setSafuAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"_token","type":"address"},{"internalType":"contract ITrueLender2","name":"_lender","type":"address"},{"internalType":"contract ISAFU","name":"_safu","type":"address"},{"internalType":"address","name":"__owner","type":"address"},{"internalType":"string","name":"borrowerName","type":"string"},{"internalType":"string","name":"borrowerSymbol","type":"string"}],"name":"singleBorrowerInitialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract ITrueStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITrueStrategy","name":"newStrategy","type":"address"}],"name":"switchStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"utilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614850806100206000396000f3fe608060405234801561001057600080fd5b50600436106103a45760003560e01c80637adbf973116101e9578063c3192f141161010f578063e7847a4b116100ad578063f2fde38b1161007c578063f2fde38b146106eb578063f8c8765e146106fe578063fc0c546a14610711578063ffa1ad7414610719576103a4565b8063e7847a4b146106c0578063ea21cd92146106c8578063efbfd847146106d0578063f2fa12d2146106e3576103a4565b8063c8796572116100e9578063c87965721461068a578063d065835a14610692578063dd62ed3e146106a5578063e30c3978146106b8576103a4565b8063c3192f141461065c578063c38bb53714610664578063c5ebeaec14610677576103a4565b8063a36bc25a11610187578063b3d1958d11610156578063b3d1958d14610631578063b861507114610644578063b94f59821461064c578063bcead63e14610654576103a4565b8063a36bc25a146105fb578063a457c2d714610603578063a8c62e7614610616578063a9059cbb1461061e576103a4565b80638714332a116101c35780638714332a146105d05780638da5cb5b146105d8578063931173a3146105e057806395d89b41146105f3576103a4565b80637adbf973146105a25780637c7be2fa146105b55780637dc0d1d0146105c8576103a4565b806337573609116102ce5780634d0392a81161026c5780636787785c1161023b5780636787785c1461057757806367b26af71461057f5780636eeeaaa51461058757806370a082311461058f576103a4565b80634d0392a81461053f5780634e71e0c8146105525780635c75347a1461055a578063653a1c8114610562576103a4565b806339509351116102a857806339509351146104fe578063438292f914610511578063466916ca14610524578063490c54271461052c576103a4565b806337573609146104db57806338af3eed146104ee578063392e53cd146104f6576103a4565b80631ac589b41161034657806327a513711161031557806327a513711461048d5780632f865568146104a0578063313ce567146104b3578063371fd8e6146104c8576103a4565b80631ac589b4146104415780631c31f7101461045457806323b872dd14610467578063265bf8e51461047a576103a4565b8063095ea7b311610382578063095ea7b3146103f15780630fc494901461041157806314d45f381461042657806318160ddd14610439576103a4565b8063026ae76f146103a9578063049878f3146103c757806306fdde03146103dc575b600080fd5b6103b1610721565b6040516103be9190613a01565b60405180910390f35b6103da6103d5366004613945565b610730565b005b6103e461084a565b6040516103be9190613a77565b6104046103ff36600461374b565b6108ff565b6040516103be9190613a6c565b61041961091d565b6040516103be91906146a8565b610419610434366004613945565b6109eb565b610419610a3e565b6103da61044f366004613945565b610a44565b6103da6104623660046136b7565b610ae0565b61040461047536600461370b565b610ba3565b6103da6104883660046136b7565b610c30565b6103da61049b366004613809565b610e68565b6103da6104ae3660046136b7565b61113d565b6104bb61115e565b6040516103be91906146bf565b6103da6104d6366004613945565b6111f4565b6104196104e9366004613945565b611295565b6103b16112da565b6104046112e9565b61040461050c36600461374b565b6112f2565b6103da61051f366004613945565b611346565b6104046114fd565b6103da61053a3660046136b7565b61151e565b6103da61054d366004613945565b61179c565b6103da6118de565b6104196119ae565b61056a611a53565b6040516103be9190614699565b610419611a58565b6103b1611abc565b610419611acb565b61041961059d3660046136b7565b611ad1565b6103da6105b03660046136b7565b611aec565b6103da6105c33660046136b7565b611b89565b6103b1611c26565b610419611c35565b6103b1611ccb565b6103da6105ee3660046136b7565b611cdf565b6103e4611d7c565b610419611dfb565b61040461061136600461374b565b611e5f565b6103b1611ecd565b61040461062c36600461374b565b611edc565b6103da61063f366004613945565b611ef0565b610419612148565b61056a612173565b6103b1612178565b610419612187565b6103da610672366004613776565b61218d565b6103da610685366004613945565b61223a565b6103da6122fd565b6104196106a0366004613945565b612396565b6104196106b33660046136d3565b612430565b6103b161245b565b61041961246a565b61041961249e565b6104196106de366004613975565b6124cd565b610419612562565b6103da6106f93660046136b7565b61256f565b6103da61070c3660046137ae565b6125e3565b6103b1612807565b6104bb612816565b6047546001600160a01b031681565b60415474010000000000000000000000000000000000000000900460ff16156107745760405162461bcd60e51b815260040161076b90613ac8565b60405180910390fd5b600061079d612710610791603d548561281b90919063ffffffff16565b9063ffffffff61285516565b905060006107b96107b4848463ffffffff61289716565b6128d9565b603e549091506107cf908363ffffffff61291c16565b603e55326000908152603f60205260409020439055603a54610802906001600160a01b031633308663ffffffff61294116565b336001600160a01b03167f16a5410c80ce4d4082839ea17ff9fae01b3924da3e586c0e4ba3cdb1c9f7dae2848360405161083d9291906146b1565b60405180910390a2505050565b60368054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108f45780601f106108c9576101008083540402835291602001916108f4565b820191906000526020600020905b8154815290600101906020018083116108d757829003601f168201915b505050505090505b90565b600061091361090c6129ea565b84846129ee565b5060015b92915050565b6041546000907501000000000000000000000000000000000000000000900460ff161561094d57506043546108fc565b603c546040517f69f9d91c0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906369f9d91c90610996903090600401613a01565b60206040518083038186803b1580156109ae57600080fd5b505afa1580156109c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e6919061395d565b905090565b6000806109f6612148565b905080610a07576000915050610a39565b610a3581610791612710610a2987610a1d612562565b9063ffffffff61289716565b9063ffffffff61281b16565b9150505b919050565b60355490565b610a4c6129ea565b60385461010090046001600160a01b03908116911614610a7e5760405162461bcd60e51b815260040161076b9061412c565b612710811115610aa05760405162461bcd60e51b815260040161076b90614278565b603d8190556040517f77cccc0e13b273cbabeb37486a9c051ceb1884a027690fe90997e824daaa67de90610ad59083906146a8565b60405180910390a150565b610ae86129ea565b60385461010090046001600160a01b03908116911614610b1a5760405162461bcd60e51b815260040161076b9061412c565b6001600160a01b038116610b405760405162461bcd60e51b815260040161076b90614015565b604480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f373c72efabe4ef3e552ff77838be729f3bc3d8c586df0012902d1baa2377fa1d90610ad5908390613a01565b6000610bb0848484612aa2565b610c2684610bbc6129ea565b610c21856040518060600160405280602881526020016147ce602891396001600160a01b038a16600090815260346020526040812090610bfa6129ea565b6001600160a01b03168152602081019190915260400160002054919063ffffffff612bc316565b6129ee565b5060019392505050565b6046546040517f14114c370000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906314114c3790610c7a908590600401613a01565b60206040518083038186803b158015610c9257600080fd5b505afa158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca91906138b3565b90506001600160a01b038116610cf25760405162461bcd60e51b815260040161076b90613d2d565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526000906001600160a01b038316906370a0823190610d3a903090600401613a01565b60206040518083038186803b158015610d5257600080fd5b505afa158015610d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8a919061395d565b604654909150610dad906001600160a01b0384811691168363ffffffff612bef16565b6046546040517f8bd317eb0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690638bd317eb90610df89086908590600401613a15565b600060405180830381600087803b158015610e1257600080fd5b505af1158015610e26573d6000803e3d6000fd5b505050507f8b5812114e0c2f352737507d60c8f752d5d65b8fd157007d572b6f32b02e756b8382604051610e5b929190613a15565b60405180910390a1505050565b600054610100900460ff1680610e815750610e81612cd0565b80610e8f575060005460ff16155b610eab5760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015610f1157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b6110a7611027610f566040518060400160405280600781526020017f547275654669200000000000000000000000000000000000000000000000000081525086612cd6565b6110226040518060400160405280600181526020017f20000000000000000000000000000000000000000000000000000000000000008152508b6001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b505afa158015610fdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261102291908101906138cf565b612cd6565b6110a26110696040518060400160405280600281526020017f746600000000000000000000000000000000000000000000000000000000000081525086612cd6565b8a6001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b612d02565b6110b084612e31565b603a80546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603c80548984169083161790556046805492881692909116919091179055801561113457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50505050505050565b604654603c5461115b916001600160a01b0390811691849116612f75565b50565b603a54604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163313ce567916004808301926020929190829003018186803b1580156111bc57600080fd5b505afa1580156111d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e69190613996565b603c546001600160a01b031633148061121757506047546001600160a01b031633145b6112335760405162461bcd60e51b815260040161076b90613efe565b603a54611251906001600160a01b031633308463ffffffff61294116565b336001600160a01b03167f0516911bcc3a0a7412a44601057c0a0a1ec628bde049a84284bc4288665344888260405161128a91906146a8565b60405180910390a250565b60006109176801000000000000000061079161c3506112cb6112c66112c188603263ffffffff61291c16565b613012565b613030565b600f0b9063ffffffff61281b16565b6044546001600160a01b031681565b60005460ff1690565b60006109136112ff6129ea565b84610c2185603460006113106129ea565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff61291c16565b61134e611c35565b60425561135961091d565b604355604180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055326000908152603f60205260409020544314156113cb5760405162461bcd60e51b815260040161076b90613d8a565b6113d433611ad1565b8111156113f35760405162461bcd60e51b815260040161076b906143ec565b600061140c611400610a3e565b61079184610a29612148565b905061142d61271061079161142084612396565b849063ffffffff61281b16565b9050611437612562565b8111156114565760405162461bcd60e51b815260040161076b906140cf565b611460338361306a565b61146981613158565b603a54611486906001600160a01b0316338363ffffffff61322a16565b336001600160a01b03167f920bb94eb3842a728db98228c375ff6b00c5bc5a54fac6736155517a0a20a61a826040516114bf91906146a8565b60405180910390a25050604180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905560006042819055604355565b60415474010000000000000000000000000000000000000000900460ff1681565b6115266129ea565b60385461010090046001600160a01b039081169116146115585760405162461bcd60e51b815260040161076b9061412c565b603b546001600160a01b03828116911614156115865760405162461bcd60e51b815260040161076b9061445a565b603b80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831617909255168015611761576000611655611641836001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b15801561160457600080fd5b505afa158015611618573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163c919061395d565b613249565b6116496119ae565b9063ffffffff61291c16565b9050816001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561169257600080fd5b505af11580156116a6573d6000803e3d6000fd5b50505050806116b36119ae565b10156116d15760405162461bcd60e51b815260040161076b90613de7565b816001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b15801561170a57600080fd5b505afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611742919061395d565b1561175f5760405162461bcd60e51b815260040161076b90613f5b565b505b7f982b8f280f8805bd99904005ce8f6c26f7502664b6468c99088f289b8d1fbe74826040516117909190613a01565b60405180910390a15050565b6117a46129ea565b60385461010090046001600160a01b039081169116146117d65760405162461bcd60e51b815260040161076b9061412c565b603b546001600160a01b03166117fe5760405162461bcd60e51b815260040161076b90614072565b600061180c826116496119ae565b603b546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081529192506001600160a01b031690632e1a7d4d906118569085906004016146a8565b600060405180830381600087803b15801561187057600080fd5b505af1158015611884573d6000803e3d6000fd5b50505050806118916119ae565b10156118af5760405162461bcd60e51b815260040161076b9061463c565b7f55a76f9c7a3527853720e31b0e3aa3d696b4125d0b6f2f52ed7fdc028fe3a2ee8260405161179091906146a8565b6039546001600160a01b031633146119085760405162461bcd60e51b815260040161076b906144b7565b6039546038546040516001600160a01b0392831692610100909204909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360398054603880547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038416021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b603e54603a546040517f70a082310000000000000000000000000000000000000000000000000000000081526000926109e69290916001600160a01b03909116906370a0823190611a03903090600401613a01565b60206040518083038186803b158015611a1b57600080fd5b505afa158015611a2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d919061395d565b600a81565b6047546000906001600160a01b0316611a73575060006108fc565b6047546040517f453152ef0000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063453152ef90610996903090600401613a01565b6046546001600160a01b031681565b603d5481565b6001600160a01b031660009081526033602052604090205490565b611af46129ea565b60385461010090046001600160a01b03908116911614611b265760405162461bcd60e51b815260040161076b9061412c565b604180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f0e05ae75e8b926552cf6fcd744d19f422561e3ced1e426868730852702dbe41890610ad5908390613a01565b611b916129ea565b60385461010090046001600160a01b03908116911614611bc35760405162461bcd60e51b815260040161076b9061412c565b604680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f8f08260e8f1b62daec5af6dcfba6b43396e87645bc9b1373e632d0214782d8cd90610ad5908390613a01565b6041546001600160a01b031681565b603b546000906001600160a01b0316611c50575060006108fc565b6041547501000000000000000000000000000000000000000000900460ff1615611c7d57506042546108fc565b603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b1580156109ae57600080fd5b60385461010090046001600160a01b031690565b611ce76129ea565b60385461010090046001600160a01b03908116911614611d195760405162461bcd60e51b815260040161076b9061412c565b604780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517fa3b7c37094bf89b6d0651a093211a836579c59059fa7a793de706a534127e5d890610ad5908390613a01565b60378054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108f45780601f106108c9576101008083540402835291602001916108f4565b6046546000906001600160a01b0316611e16575060006108fc565b6046546040517f76fd6a430000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906376fd6a4390610996903090600401613a01565b6000610913611e6c6129ea565b84610c21856040518060600160405280602581526020016147f66025913960346000611e966129ea565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff612bc316565b603b546001600160a01b031681565b6000610913611ee96129ea565b8484612aa2565b603b546001600160a01b0316611f185760405162461bcd60e51b815260040161076b90614072565b611f206119ae565b811115611f3f5760405162461bcd60e51b815260040161076b906142d5565b6000611fd3611f4d83613249565b603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b158015611f9b57600080fd5b505afa158015611faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611649919061395d565b603b54603a54919250611ff9916001600160a01b0390811691168463ffffffff612bef16565b603b546040517fb6b55f250000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063b6b55f25906120429085906004016146a8565b600060405180830381600087803b15801561205c57600080fd5b505af1158015612070573d6000803e3d6000fd5b5050505080603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b1580156120c357600080fd5b505afa1580156120d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fb919061395d565b10156121195760405162461bcd60e51b815260040161076b90613e44565b7fed1eeda1fde9cc22a2ecf41efc0d6cf519c1d95184b36b93b4cd4877881488ee8260405161179091906146a8565b60006109e6612155611a58565b611649612160611dfb565b61164961216b61091d565b611649612562565b606481565b603c546001600160a01b031681565b603e5481565b6121956129ea565b60385461010090046001600160a01b039081169116146121c75760405162461bcd60e51b815260040161076b9061412c565b604180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000831515021790556040517fef37df9624f797913e7585c7f7b5d004ba6704be3c64b0561c157728ccc8698590610ad5908390613a6c565b603c546001600160a01b031633148061225d57506047546001600160a01b031633145b6122795760405162461bcd60e51b815260040161076b90613efe565b612281612562565b8111156122a05760405162461bcd60e51b815260040161076b90613cd0565b80156122af576122af81613158565b603a546122cc906001600160a01b0316338363ffffffff61322a16565b7fcbc04eca7e9da35cb1393a6135a199ca52e450d5e9251cbd99f7847d33a367503382604051610ad5929190613a15565b6044546001600160a01b03166123255760405162461bcd60e51b815260040161076b90613b82565b603e80546000909155801561235757604454603a54612357916001600160a01b0391821691168363ffffffff61322a16565b6044546040516001600160a01b03909116907f8c22f554c81b54107cd95e734e4ef45767214974a540f34ea4a4f8c3fc7b13c39061128a9084906146a8565b6000806123a1612562565b905060006123ad612148565b9050808414156123c35761271092505050610a39565b60006123db826107918561271063ffffffff61281b16565b905060006124086123f2848863ffffffff61289716565b610791612710610a29888b63ffffffff61289716565b905061242661241782846124cd565b6127109063ffffffff61289716565b9695505050505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6039546001600160a01b031690565b600080612475612148565b9050806124865760009150506108fc565b61249881610791612710610a29612562565b91505090565b6000806124a9612148565b905061249881610791612710610a296124c0612562565b869063ffffffff61289716565b6000818311156124ef5760405162461bcd60e51b815260040161076b90614571565b61271083141561250157506000610917565b818314156125335761252c61251d84603263ffffffff61291c16565b61c3509063ffffffff61285516565b9050610917565b61255b612546838563ffffffff61289716565b61079161255286611295565b610a1d86611295565b9392505050565b60006109e6611641611c35565b6125776129ea565b60385461010090046001600160a01b039081169116146125a95760405162461bcd60e51b815260040161076b9061412c565b603980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600054610100900460ff16806125fc57506125fc612cd0565b8061260a575060005460ff16155b6126265760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff1615801561268c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b6127736127016040518060400160405280600781526020017f5472756546692000000000000000000000000000000000000000000000000000815250876001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b6110a26040518060400160405280600281526020017f7466000000000000000000000000000000000000000000000000000000000000815250886001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b61277c82612e31565b603a80546001600160a01b038088167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603c80548784169083161790556046805492861692909116919091179055801561280057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050505050565b603a546001600160a01b031681565b600181565b60008261282a57506000610917565b8282028284828161283757fe5b041461255b5760405162461bcd60e51b815260040161076b90613fb8565b600061255b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613263565b600061255b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612bc3565b6000816128e7575080610a39565b8160006128f2610a3e565b11156129125761290f612903612148565b61079185610a29610a3e565b90505b610917338261329a565b60008282018381101561255b5760405162461bcd60e51b815260040161076b90613c99565b6129e4846323b872dd60e01b85858560405160240161296293929190613a48565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261335a565b50505050565b3390565b6001600160a01b038316612a145760405162461bcd60e51b815260040161076b9061438f565b6001600160a01b038216612a3a5760405162461bcd60e51b815260040161076b90613bdf565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612a959085906146a8565b60405180910390a3505050565b6001600160a01b038316612ac85760405162461bcd60e51b815260040161076b90614332565b6001600160a01b038216612aee5760405162461bcd60e51b815260040161076b90613b25565b612af9838383612ccb565b612b3c816040518060600160405280602681526020016147a8602691396001600160a01b038616600090815260336020526040902054919063ffffffff612bc316565b6001600160a01b038085166000908152603360205260408082209390935590841681522054612b71908263ffffffff61291c16565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612a959085906146a8565b60008184841115612be75760405162461bcd60e51b815260040161076b9190613a77565b505050900390565b801580612c9057506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063dd62ed3e90612c3e9030908690600401613a2e565b60206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e919061395d565b155b612cac5760405162461bcd60e51b815260040161076b906145a8565b612ccb8363095ea7b360e01b8484604051602401612962929190613a15565b505050565b303b1590565b60608282604051602001612ceb9291906139d3565b604051602081830303815290604052905092915050565b600054610100900460ff1680612d1b5750612d1b612cd0565b80612d29575060005460ff16155b612d455760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015612dab57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b8251612dbe9060369060208601906135cc565b508151612dd29060379060208501906135cc565b50603880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660121790558015612ccb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b600054610100900460ff1680612e4a5750612e4a612cd0565b80612e58575060005460ff16155b612e745760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015612eda57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b603880547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038516908102919091179091556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015612f7157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b336001600160a01b03841614612f9d5760405162461bcd60e51b815260040161076b906141be565b6040517f0c305a130000000000000000000000000000000000000000000000000000000081526001600160a01b03821690630c305a1390612fe49085908790600401613a2e565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015611134573d6000803e3d6000fd5b6000677fffffffffffffff82111561302957600080fd5b5060401b90565b60008082600f0b1361304157600080fd5b608061304c836133e9565b600f0b6fb17217f7d1cf79abc9e3b39803f2f6af02901c9050919050565b6001600160a01b0382166130905760405162461bcd60e51b815260040161076b9061421b565b61309c82600083612ccb565b6130df81604051806060016040528060228152602001614786602291396001600160a01b038516600090815260336020526040902054919063ffffffff612bc316565b6001600160a01b03831660009081526033602052604090205560355461310b908263ffffffff61289716565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061314c9085906146a8565b60405180910390a35050565b60006131626119ae565b905081811015612f7157603b546001600160a01b03166131945760405162461bcd60e51b815260040161076b90613ea1565b603b546001600160a01b0316632e1a7d4d6131b5848463ffffffff61289716565b6040518263ffffffff1660e01b81526004016131d191906146a8565b600060405180830381600087803b1580156131eb57600080fd5b505af11580156131ff573d6000803e3d6000fd5b505050508161320c6119ae565b1015612f715760405162461bcd60e51b815260040161076b90613c3c565b612ccb8363a9059cbb60e01b8484604051602401612962929190613a15565b60006109176127106107918461270663ffffffff61281b16565b600081836132845760405162461bcd60e51b815260040161076b9190613a77565b50600083858161329057fe5b0495945050505050565b6001600160a01b0382166132c05760405162461bcd60e51b815260040161076b90614605565b6132cc60008383612ccb565b6035546132df908263ffffffff61291c16565b6035556001600160a01b03821660009081526033602052604090205461330b908263ffffffff61291c16565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061314c9085906146a8565b60606133af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134eb9092919063ffffffff16565b805190915015612ccb57808060200190518101906133cd9190613792565b612ccb5760405162461bcd60e51b815260040161076b90614514565b60008082600f0b136133fa57600080fd5b6000600f83900b680100000000000000008112613419576040918201911d5b640100000000811261342d576020918201911d5b62010000811261343f576010918201911d5b6101008112613450576008918201911d5b60108112613460576004918201911d5b60048112613470576002918201911d5b6002811261347f576001820191505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160401b600f85900b607f8490031b6780000000000000005b60008113156134e05790800260ff81901c8281029390930192607f011c9060011d6134ba565b509095945050505050565b60606134fa8484600085613502565b949350505050565b606061350d856135c6565b6135295760405162461bcd60e51b815260040161076b90614423565b60006060866001600160a01b0316858760405161354691906139b7565b60006040518083038185875af1925050503d8060008114613583576040519150601f19603f3d011682016040523d82523d6000602084013e613588565b606091505b5091509150811561359c5791506134fa9050565b8051156135ac5780518082602001fd5b8360405162461bcd60e51b815260040161076b9190613a77565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061360d57805160ff191683800117855561363a565b8280016001018555821561363a579182015b8281111561363a57825182559160200191906001019061361f565b5061364692915061364a565b5090565b6108fc91905b808211156136465760008155600101613650565b600082601f830112613674578081fd5b8135613687613682826146f4565b6146cd565b915080825283602082850101111561369e57600080fd5b8060208401602084013760009082016020015292915050565b6000602082840312156136c8578081fd5b813561255b81614762565b600080604083850312156136e5578081fd5b82356136f081614762565b9150602083013561370081614762565b809150509250929050565b60008060006060848603121561371f578081fd5b833561372a81614762565b9250602084013561373a81614762565b929592945050506040919091013590565b6000806040838503121561375d578182fd5b823561376881614762565b946020939093013593505050565b600060208284031215613787578081fd5b813561255b81614777565b6000602082840312156137a3578081fd5b815161255b81614777565b600080600080608085870312156137c3578081fd5b84356137ce81614762565b935060208501356137de81614762565b925060408501356137ee81614762565b915060608501356137fe81614762565b939692955090935050565b60008060008060008060c08789031215613821578182fd5b863561382c81614762565b9550602087013561383c81614762565b9450604087013561384c81614762565b9350606087013561385c81614762565b9250608087013567ffffffffffffffff80821115613878578384fd5b6138848a838b01613664565b935060a0890135915080821115613899578283fd5b506138a689828a01613664565b9150509295509295509295565b6000602082840312156138c4578081fd5b815161255b81614762565b6000602082840312156138e0578081fd5b815167ffffffffffffffff8111156138f6578182fd5b80830184601f820112613907578283fd5b80519150613917613682836146f4565b82815285602084840101111561392b578384fd5b61393c836020830160208501614736565b95945050505050565b600060208284031215613956578081fd5b5035919050565b60006020828403121561396e578081fd5b5051919050565b60008060408385031215613987578182fd5b50508035926020909101359150565b6000602082840312156139a7578081fd5b815160ff8116811461255b578182fd5b600082516139c9818460208701614736565b9190910192915050565b600083516139e5818460208801614736565b83519083016139f8828260208801614736565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b901515815260200190565b6000602082528251806020840152613a96816040850160208701614736565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60208082526026908201527f547275654669506f6f6c3a204a6f696e696e672074686520706f6f6c2069732060408201527f7061757365640000000000000000000000000000000000000000000000000000606082015260800190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201527f6573730000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f547275654669506f6f6c3a2042656e6566696369617279206973206e6f74207360408201527f6574000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560408201527f7373000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526034908201527f547275654669506f6f6c3a204e6f7420656e6f7567682066756e64732074616b60408201527f656e2066726f6d20746865207374726174656779000000000000000000000000606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f547275654669506f6f6c3a20496e73756666696369656e74206c69717569646960408201527f7479000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f547275654669506f6f6c323a204e6f20646566696369656e637920746f6b656e60408201527f20666f756e6420666f72206c6f616e0000000000000000000000000000000000606082015260800190565b6020808252602e908201527f547275654669506f6f6c3a2043616e6e6f74206a6f696e20616e64206578697460408201527f20696e2073616d6520626c6f636b000000000000000000000000000000000000606082015260800190565b60208082526031908201527f547275654669506f6f6c3a20416c6c2066756e64732073686f756c642062652060408201527f77697468647261776e20746f20706f6f6c000000000000000000000000000000606082015260800190565b60208082526030908201527f547275654669506f6f6c3a2053747261746567792076616c756520657870656360408201527f74656420746f2062652068696768657200000000000000000000000000000000606082015260800190565b60208082526031908201527f547275654669506f6f6c3a20506f6f6c20686173206e6f20737472617465677960408201527f20746f2077697468647261772066726f6d000000000000000000000000000000606082015260800190565b60208082526034908201527f547275654669506f6f6c3a2043616c6c6572206973206e6f7420746865206c6560408201527f6e646572206f72206372656469744167656e6379000000000000000000000000606082015260800190565b60208082526030908201527f547275654669506f6f6c3a20537769746368656420737472617465677920736860408201527f6f756c64206265206465706c6574656400000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526032908201527f547275654669506f6f6c3a2042656e656669636961727920616464726573732060408201527f63616e6e6f742062652073657420746f20300000000000000000000000000000606082015260800190565b60208082526027908201527f547275654669506f6f6c3a20506f6f6c20686173206e6f20737472617465677960408201527f2073657420757000000000000000000000000000000000000000000000000000606082015260800190565b60208082526028908201527f547275654669506f6f6c3a204e6f7420656e6f756768206c697175696469747960408201527f20696e20706f6f6c000000000000000000000000000000000000000000000000606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201527f656e20696e697469616c697a6564000000000000000000000000000000000000606082015260800190565b60208082526024908201527f547275654669506f6f6c3a2053686f756c642062652063616c6c65642062792060408201527f5341465500000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360408201527f7300000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f547275654669506f6f6c3a204665652063616e6e6f742065786365656420747260408201527f616e73616374696f6e2076616c75650000000000000000000000000000000000606082015260800190565b60208082526029908201527f547275654669506f6f6c3a20496e73756666696369656e742063757272656e6360408201527f792062616c616e63650000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460408201527f6472657373000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460408201527f7265737300000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f547275654669506f6f6c3a20496e73756666696369656e742066756e64730000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602e908201527f547275654669506f6f6c3a2043616e6e6f742073776974636820746f2074686560408201527f2073616d65207374726174656779000000000000000000000000000000000000606082015260800190565b60208082526028908201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652070656e646960408201527f6e67206f776e6572000000000000000000000000000000000000000000000000606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f547275654669506f6f6c3a20546f2070726563656465732066726f6d00000000604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b60208082526032908201527f547275654669506f6f6c3a2043757272656e63792062616c616e63652065787060408201527f656374656420746f206265206869676865720000000000000000000000000000606082015260800190565b61ffff91909116815260200190565b90815260200190565b918252602082015260400190565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146ec57600080fd5b604052919050565b600067ffffffffffffffff82111561470a578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015614751578181015183820152602001614739565b838111156129e45750506000910152565b6001600160a01b038116811461115b57600080fd5b801515811461115b57600080fdfe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220b2af177ba35c19f99a7a9226a3710d3fa1341e30a12408f6d7404259efde17ae64736f6c634300060a0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103a45760003560e01c80637adbf973116101e9578063c3192f141161010f578063e7847a4b116100ad578063f2fde38b1161007c578063f2fde38b146106eb578063f8c8765e146106fe578063fc0c546a14610711578063ffa1ad7414610719576103a4565b8063e7847a4b146106c0578063ea21cd92146106c8578063efbfd847146106d0578063f2fa12d2146106e3576103a4565b8063c8796572116100e9578063c87965721461068a578063d065835a14610692578063dd62ed3e146106a5578063e30c3978146106b8576103a4565b8063c3192f141461065c578063c38bb53714610664578063c5ebeaec14610677576103a4565b8063a36bc25a11610187578063b3d1958d11610156578063b3d1958d14610631578063b861507114610644578063b94f59821461064c578063bcead63e14610654576103a4565b8063a36bc25a146105fb578063a457c2d714610603578063a8c62e7614610616578063a9059cbb1461061e576103a4565b80638714332a116101c35780638714332a146105d05780638da5cb5b146105d8578063931173a3146105e057806395d89b41146105f3576103a4565b80637adbf973146105a25780637c7be2fa146105b55780637dc0d1d0146105c8576103a4565b806337573609116102ce5780634d0392a81161026c5780636787785c1161023b5780636787785c1461057757806367b26af71461057f5780636eeeaaa51461058757806370a082311461058f576103a4565b80634d0392a81461053f5780634e71e0c8146105525780635c75347a1461055a578063653a1c8114610562576103a4565b806339509351116102a857806339509351146104fe578063438292f914610511578063466916ca14610524578063490c54271461052c576103a4565b806337573609146104db57806338af3eed146104ee578063392e53cd146104f6576103a4565b80631ac589b41161034657806327a513711161031557806327a513711461048d5780632f865568146104a0578063313ce567146104b3578063371fd8e6146104c8576103a4565b80631ac589b4146104415780631c31f7101461045457806323b872dd14610467578063265bf8e51461047a576103a4565b8063095ea7b311610382578063095ea7b3146103f15780630fc494901461041157806314d45f381461042657806318160ddd14610439576103a4565b8063026ae76f146103a9578063049878f3146103c757806306fdde03146103dc575b600080fd5b6103b1610721565b6040516103be9190613a01565b60405180910390f35b6103da6103d5366004613945565b610730565b005b6103e461084a565b6040516103be9190613a77565b6104046103ff36600461374b565b6108ff565b6040516103be9190613a6c565b61041961091d565b6040516103be91906146a8565b610419610434366004613945565b6109eb565b610419610a3e565b6103da61044f366004613945565b610a44565b6103da6104623660046136b7565b610ae0565b61040461047536600461370b565b610ba3565b6103da6104883660046136b7565b610c30565b6103da61049b366004613809565b610e68565b6103da6104ae3660046136b7565b61113d565b6104bb61115e565b6040516103be91906146bf565b6103da6104d6366004613945565b6111f4565b6104196104e9366004613945565b611295565b6103b16112da565b6104046112e9565b61040461050c36600461374b565b6112f2565b6103da61051f366004613945565b611346565b6104046114fd565b6103da61053a3660046136b7565b61151e565b6103da61054d366004613945565b61179c565b6103da6118de565b6104196119ae565b61056a611a53565b6040516103be9190614699565b610419611a58565b6103b1611abc565b610419611acb565b61041961059d3660046136b7565b611ad1565b6103da6105b03660046136b7565b611aec565b6103da6105c33660046136b7565b611b89565b6103b1611c26565b610419611c35565b6103b1611ccb565b6103da6105ee3660046136b7565b611cdf565b6103e4611d7c565b610419611dfb565b61040461061136600461374b565b611e5f565b6103b1611ecd565b61040461062c36600461374b565b611edc565b6103da61063f366004613945565b611ef0565b610419612148565b61056a612173565b6103b1612178565b610419612187565b6103da610672366004613776565b61218d565b6103da610685366004613945565b61223a565b6103da6122fd565b6104196106a0366004613945565b612396565b6104196106b33660046136d3565b612430565b6103b161245b565b61041961246a565b61041961249e565b6104196106de366004613975565b6124cd565b610419612562565b6103da6106f93660046136b7565b61256f565b6103da61070c3660046137ae565b6125e3565b6103b1612807565b6104bb612816565b6047546001600160a01b031681565b60415474010000000000000000000000000000000000000000900460ff16156107745760405162461bcd60e51b815260040161076b90613ac8565b60405180910390fd5b600061079d612710610791603d548561281b90919063ffffffff16565b9063ffffffff61285516565b905060006107b96107b4848463ffffffff61289716565b6128d9565b603e549091506107cf908363ffffffff61291c16565b603e55326000908152603f60205260409020439055603a54610802906001600160a01b031633308663ffffffff61294116565b336001600160a01b03167f16a5410c80ce4d4082839ea17ff9fae01b3924da3e586c0e4ba3cdb1c9f7dae2848360405161083d9291906146b1565b60405180910390a2505050565b60368054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108f45780601f106108c9576101008083540402835291602001916108f4565b820191906000526020600020905b8154815290600101906020018083116108d757829003601f168201915b505050505090505b90565b600061091361090c6129ea565b84846129ee565b5060015b92915050565b6041546000907501000000000000000000000000000000000000000000900460ff161561094d57506043546108fc565b603c546040517f69f9d91c0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906369f9d91c90610996903090600401613a01565b60206040518083038186803b1580156109ae57600080fd5b505afa1580156109c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e6919061395d565b905090565b6000806109f6612148565b905080610a07576000915050610a39565b610a3581610791612710610a2987610a1d612562565b9063ffffffff61289716565b9063ffffffff61281b16565b9150505b919050565b60355490565b610a4c6129ea565b60385461010090046001600160a01b03908116911614610a7e5760405162461bcd60e51b815260040161076b9061412c565b612710811115610aa05760405162461bcd60e51b815260040161076b90614278565b603d8190556040517f77cccc0e13b273cbabeb37486a9c051ceb1884a027690fe90997e824daaa67de90610ad59083906146a8565b60405180910390a150565b610ae86129ea565b60385461010090046001600160a01b03908116911614610b1a5760405162461bcd60e51b815260040161076b9061412c565b6001600160a01b038116610b405760405162461bcd60e51b815260040161076b90614015565b604480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f373c72efabe4ef3e552ff77838be729f3bc3d8c586df0012902d1baa2377fa1d90610ad5908390613a01565b6000610bb0848484612aa2565b610c2684610bbc6129ea565b610c21856040518060600160405280602881526020016147ce602891396001600160a01b038a16600090815260346020526040812090610bfa6129ea565b6001600160a01b03168152602081019190915260400160002054919063ffffffff612bc316565b6129ee565b5060019392505050565b6046546040517f14114c370000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906314114c3790610c7a908590600401613a01565b60206040518083038186803b158015610c9257600080fd5b505afa158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca91906138b3565b90506001600160a01b038116610cf25760405162461bcd60e51b815260040161076b90613d2d565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526000906001600160a01b038316906370a0823190610d3a903090600401613a01565b60206040518083038186803b158015610d5257600080fd5b505afa158015610d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8a919061395d565b604654909150610dad906001600160a01b0384811691168363ffffffff612bef16565b6046546040517f8bd317eb0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690638bd317eb90610df89086908590600401613a15565b600060405180830381600087803b158015610e1257600080fd5b505af1158015610e26573d6000803e3d6000fd5b505050507f8b5812114e0c2f352737507d60c8f752d5d65b8fd157007d572b6f32b02e756b8382604051610e5b929190613a15565b60405180910390a1505050565b600054610100900460ff1680610e815750610e81612cd0565b80610e8f575060005460ff16155b610eab5760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015610f1157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b6110a7611027610f566040518060400160405280600781526020017f547275654669200000000000000000000000000000000000000000000000000081525086612cd6565b6110226040518060400160405280600181526020017f20000000000000000000000000000000000000000000000000000000000000008152508b6001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b505afa158015610fdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261102291908101906138cf565b612cd6565b6110a26110696040518060400160405280600281526020017f746600000000000000000000000000000000000000000000000000000000000081525086612cd6565b8a6001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b612d02565b6110b084612e31565b603a80546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603c80548984169083161790556046805492881692909116919091179055801561113457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50505050505050565b604654603c5461115b916001600160a01b0390811691849116612f75565b50565b603a54604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163313ce567916004808301926020929190829003018186803b1580156111bc57600080fd5b505afa1580156111d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e69190613996565b603c546001600160a01b031633148061121757506047546001600160a01b031633145b6112335760405162461bcd60e51b815260040161076b90613efe565b603a54611251906001600160a01b031633308463ffffffff61294116565b336001600160a01b03167f0516911bcc3a0a7412a44601057c0a0a1ec628bde049a84284bc4288665344888260405161128a91906146a8565b60405180910390a250565b60006109176801000000000000000061079161c3506112cb6112c66112c188603263ffffffff61291c16565b613012565b613030565b600f0b9063ffffffff61281b16565b6044546001600160a01b031681565b60005460ff1690565b60006109136112ff6129ea565b84610c2185603460006113106129ea565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff61291c16565b61134e611c35565b60425561135961091d565b604355604180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055326000908152603f60205260409020544314156113cb5760405162461bcd60e51b815260040161076b90613d8a565b6113d433611ad1565b8111156113f35760405162461bcd60e51b815260040161076b906143ec565b600061140c611400610a3e565b61079184610a29612148565b905061142d61271061079161142084612396565b849063ffffffff61281b16565b9050611437612562565b8111156114565760405162461bcd60e51b815260040161076b906140cf565b611460338361306a565b61146981613158565b603a54611486906001600160a01b0316338363ffffffff61322a16565b336001600160a01b03167f920bb94eb3842a728db98228c375ff6b00c5bc5a54fac6736155517a0a20a61a826040516114bf91906146a8565b60405180910390a25050604180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905560006042819055604355565b60415474010000000000000000000000000000000000000000900460ff1681565b6115266129ea565b60385461010090046001600160a01b039081169116146115585760405162461bcd60e51b815260040161076b9061412c565b603b546001600160a01b03828116911614156115865760405162461bcd60e51b815260040161076b9061445a565b603b80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831617909255168015611761576000611655611641836001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b15801561160457600080fd5b505afa158015611618573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163c919061395d565b613249565b6116496119ae565b9063ffffffff61291c16565b9050816001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561169257600080fd5b505af11580156116a6573d6000803e3d6000fd5b50505050806116b36119ae565b10156116d15760405162461bcd60e51b815260040161076b90613de7565b816001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b15801561170a57600080fd5b505afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611742919061395d565b1561175f5760405162461bcd60e51b815260040161076b90613f5b565b505b7f982b8f280f8805bd99904005ce8f6c26f7502664b6468c99088f289b8d1fbe74826040516117909190613a01565b60405180910390a15050565b6117a46129ea565b60385461010090046001600160a01b039081169116146117d65760405162461bcd60e51b815260040161076b9061412c565b603b546001600160a01b03166117fe5760405162461bcd60e51b815260040161076b90614072565b600061180c826116496119ae565b603b546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081529192506001600160a01b031690632e1a7d4d906118569085906004016146a8565b600060405180830381600087803b15801561187057600080fd5b505af1158015611884573d6000803e3d6000fd5b50505050806118916119ae565b10156118af5760405162461bcd60e51b815260040161076b9061463c565b7f55a76f9c7a3527853720e31b0e3aa3d696b4125d0b6f2f52ed7fdc028fe3a2ee8260405161179091906146a8565b6039546001600160a01b031633146119085760405162461bcd60e51b815260040161076b906144b7565b6039546038546040516001600160a01b0392831692610100909204909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360398054603880547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038416021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b603e54603a546040517f70a082310000000000000000000000000000000000000000000000000000000081526000926109e69290916001600160a01b03909116906370a0823190611a03903090600401613a01565b60206040518083038186803b158015611a1b57600080fd5b505afa158015611a2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d919061395d565b600a81565b6047546000906001600160a01b0316611a73575060006108fc565b6047546040517f453152ef0000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063453152ef90610996903090600401613a01565b6046546001600160a01b031681565b603d5481565b6001600160a01b031660009081526033602052604090205490565b611af46129ea565b60385461010090046001600160a01b03908116911614611b265760405162461bcd60e51b815260040161076b9061412c565b604180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f0e05ae75e8b926552cf6fcd744d19f422561e3ced1e426868730852702dbe41890610ad5908390613a01565b611b916129ea565b60385461010090046001600160a01b03908116911614611bc35760405162461bcd60e51b815260040161076b9061412c565b604680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f8f08260e8f1b62daec5af6dcfba6b43396e87645bc9b1373e632d0214782d8cd90610ad5908390613a01565b6041546001600160a01b031681565b603b546000906001600160a01b0316611c50575060006108fc565b6041547501000000000000000000000000000000000000000000900460ff1615611c7d57506042546108fc565b603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b1580156109ae57600080fd5b60385461010090046001600160a01b031690565b611ce76129ea565b60385461010090046001600160a01b03908116911614611d195760405162461bcd60e51b815260040161076b9061412c565b604780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517fa3b7c37094bf89b6d0651a093211a836579c59059fa7a793de706a534127e5d890610ad5908390613a01565b60378054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108f45780601f106108c9576101008083540402835291602001916108f4565b6046546000906001600160a01b0316611e16575060006108fc565b6046546040517f76fd6a430000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906376fd6a4390610996903090600401613a01565b6000610913611e6c6129ea565b84610c21856040518060600160405280602581526020016147f66025913960346000611e966129ea565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff612bc316565b603b546001600160a01b031681565b6000610913611ee96129ea565b8484612aa2565b603b546001600160a01b0316611f185760405162461bcd60e51b815260040161076b90614072565b611f206119ae565b811115611f3f5760405162461bcd60e51b815260040161076b906142d5565b6000611fd3611f4d83613249565b603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b158015611f9b57600080fd5b505afa158015611faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611649919061395d565b603b54603a54919250611ff9916001600160a01b0390811691168463ffffffff612bef16565b603b546040517fb6b55f250000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063b6b55f25906120429085906004016146a8565b600060405180830381600087803b15801561205c57600080fd5b505af1158015612070573d6000803e3d6000fd5b5050505080603b60009054906101000a90046001600160a01b03166001600160a01b0316633fa4f2456040518163ffffffff1660e01b815260040160206040518083038186803b1580156120c357600080fd5b505afa1580156120d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fb919061395d565b10156121195760405162461bcd60e51b815260040161076b90613e44565b7fed1eeda1fde9cc22a2ecf41efc0d6cf519c1d95184b36b93b4cd4877881488ee8260405161179091906146a8565b60006109e6612155611a58565b611649612160611dfb565b61164961216b61091d565b611649612562565b606481565b603c546001600160a01b031681565b603e5481565b6121956129ea565b60385461010090046001600160a01b039081169116146121c75760405162461bcd60e51b815260040161076b9061412c565b604180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000831515021790556040517fef37df9624f797913e7585c7f7b5d004ba6704be3c64b0561c157728ccc8698590610ad5908390613a6c565b603c546001600160a01b031633148061225d57506047546001600160a01b031633145b6122795760405162461bcd60e51b815260040161076b90613efe565b612281612562565b8111156122a05760405162461bcd60e51b815260040161076b90613cd0565b80156122af576122af81613158565b603a546122cc906001600160a01b0316338363ffffffff61322a16565b7fcbc04eca7e9da35cb1393a6135a199ca52e450d5e9251cbd99f7847d33a367503382604051610ad5929190613a15565b6044546001600160a01b03166123255760405162461bcd60e51b815260040161076b90613b82565b603e80546000909155801561235757604454603a54612357916001600160a01b0391821691168363ffffffff61322a16565b6044546040516001600160a01b03909116907f8c22f554c81b54107cd95e734e4ef45767214974a540f34ea4a4f8c3fc7b13c39061128a9084906146a8565b6000806123a1612562565b905060006123ad612148565b9050808414156123c35761271092505050610a39565b60006123db826107918561271063ffffffff61281b16565b905060006124086123f2848863ffffffff61289716565b610791612710610a29888b63ffffffff61289716565b905061242661241782846124cd565b6127109063ffffffff61289716565b9695505050505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6039546001600160a01b031690565b600080612475612148565b9050806124865760009150506108fc565b61249881610791612710610a29612562565b91505090565b6000806124a9612148565b905061249881610791612710610a296124c0612562565b869063ffffffff61289716565b6000818311156124ef5760405162461bcd60e51b815260040161076b90614571565b61271083141561250157506000610917565b818314156125335761252c61251d84603263ffffffff61291c16565b61c3509063ffffffff61285516565b9050610917565b61255b612546838563ffffffff61289716565b61079161255286611295565b610a1d86611295565b9392505050565b60006109e6611641611c35565b6125776129ea565b60385461010090046001600160a01b039081169116146125a95760405162461bcd60e51b815260040161076b9061412c565b603980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600054610100900460ff16806125fc57506125fc612cd0565b8061260a575060005460ff16155b6126265760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff1615801561268c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b6127736127016040518060400160405280600781526020017f5472756546692000000000000000000000000000000000000000000000000000815250876001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b6110a26040518060400160405280600281526020017f7466000000000000000000000000000000000000000000000000000000000000815250886001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610fc857600080fd5b61277c82612e31565b603a80546001600160a01b038088167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603c80548784169083161790556046805492861692909116919091179055801561280057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050505050565b603a546001600160a01b031681565b600181565b60008261282a57506000610917565b8282028284828161283757fe5b041461255b5760405162461bcd60e51b815260040161076b90613fb8565b600061255b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613263565b600061255b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612bc3565b6000816128e7575080610a39565b8160006128f2610a3e565b11156129125761290f612903612148565b61079185610a29610a3e565b90505b610917338261329a565b60008282018381101561255b5760405162461bcd60e51b815260040161076b90613c99565b6129e4846323b872dd60e01b85858560405160240161296293929190613a48565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261335a565b50505050565b3390565b6001600160a01b038316612a145760405162461bcd60e51b815260040161076b9061438f565b6001600160a01b038216612a3a5760405162461bcd60e51b815260040161076b90613bdf565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612a959085906146a8565b60405180910390a3505050565b6001600160a01b038316612ac85760405162461bcd60e51b815260040161076b90614332565b6001600160a01b038216612aee5760405162461bcd60e51b815260040161076b90613b25565b612af9838383612ccb565b612b3c816040518060600160405280602681526020016147a8602691396001600160a01b038616600090815260336020526040902054919063ffffffff612bc316565b6001600160a01b038085166000908152603360205260408082209390935590841681522054612b71908263ffffffff61291c16565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612a959085906146a8565b60008184841115612be75760405162461bcd60e51b815260040161076b9190613a77565b505050900390565b801580612c9057506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063dd62ed3e90612c3e9030908690600401613a2e565b60206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e919061395d565b155b612cac5760405162461bcd60e51b815260040161076b906145a8565b612ccb8363095ea7b360e01b8484604051602401612962929190613a15565b505050565b303b1590565b60608282604051602001612ceb9291906139d3565b604051602081830303815290604052905092915050565b600054610100900460ff1680612d1b5750612d1b612cd0565b80612d29575060005460ff16155b612d455760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015612dab57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b8251612dbe9060369060208601906135cc565b508151612dd29060379060208501906135cc565b50603880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660121790558015612ccb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b600054610100900460ff1680612e4a5750612e4a612cd0565b80612e58575060005460ff16155b612e745760405162461bcd60e51b815260040161076b90614161565b600054610100900460ff16158015612eda57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b603880547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038516908102919091179091556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015612f7157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b336001600160a01b03841614612f9d5760405162461bcd60e51b815260040161076b906141be565b6040517f0c305a130000000000000000000000000000000000000000000000000000000081526001600160a01b03821690630c305a1390612fe49085908790600401613a2e565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015611134573d6000803e3d6000fd5b6000677fffffffffffffff82111561302957600080fd5b5060401b90565b60008082600f0b1361304157600080fd5b608061304c836133e9565b600f0b6fb17217f7d1cf79abc9e3b39803f2f6af02901c9050919050565b6001600160a01b0382166130905760405162461bcd60e51b815260040161076b9061421b565b61309c82600083612ccb565b6130df81604051806060016040528060228152602001614786602291396001600160a01b038516600090815260336020526040902054919063ffffffff612bc316565b6001600160a01b03831660009081526033602052604090205560355461310b908263ffffffff61289716565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061314c9085906146a8565b60405180910390a35050565b60006131626119ae565b905081811015612f7157603b546001600160a01b03166131945760405162461bcd60e51b815260040161076b90613ea1565b603b546001600160a01b0316632e1a7d4d6131b5848463ffffffff61289716565b6040518263ffffffff1660e01b81526004016131d191906146a8565b600060405180830381600087803b1580156131eb57600080fd5b505af11580156131ff573d6000803e3d6000fd5b505050508161320c6119ae565b1015612f715760405162461bcd60e51b815260040161076b90613c3c565b612ccb8363a9059cbb60e01b8484604051602401612962929190613a15565b60006109176127106107918461270663ffffffff61281b16565b600081836132845760405162461bcd60e51b815260040161076b9190613a77565b50600083858161329057fe5b0495945050505050565b6001600160a01b0382166132c05760405162461bcd60e51b815260040161076b90614605565b6132cc60008383612ccb565b6035546132df908263ffffffff61291c16565b6035556001600160a01b03821660009081526033602052604090205461330b908263ffffffff61291c16565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061314c9085906146a8565b60606133af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134eb9092919063ffffffff16565b805190915015612ccb57808060200190518101906133cd9190613792565b612ccb5760405162461bcd60e51b815260040161076b90614514565b60008082600f0b136133fa57600080fd5b6000600f83900b680100000000000000008112613419576040918201911d5b640100000000811261342d576020918201911d5b62010000811261343f576010918201911d5b6101008112613450576008918201911d5b60108112613460576004918201911d5b60048112613470576002918201911d5b6002811261347f576001820191505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160401b600f85900b607f8490031b6780000000000000005b60008113156134e05790800260ff81901c8281029390930192607f011c9060011d6134ba565b509095945050505050565b60606134fa8484600085613502565b949350505050565b606061350d856135c6565b6135295760405162461bcd60e51b815260040161076b90614423565b60006060866001600160a01b0316858760405161354691906139b7565b60006040518083038185875af1925050503d8060008114613583576040519150601f19603f3d011682016040523d82523d6000602084013e613588565b606091505b5091509150811561359c5791506134fa9050565b8051156135ac5780518082602001fd5b8360405162461bcd60e51b815260040161076b9190613a77565b3b151590565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061360d57805160ff191683800117855561363a565b8280016001018555821561363a579182015b8281111561363a57825182559160200191906001019061361f565b5061364692915061364a565b5090565b6108fc91905b808211156136465760008155600101613650565b600082601f830112613674578081fd5b8135613687613682826146f4565b6146cd565b915080825283602082850101111561369e57600080fd5b8060208401602084013760009082016020015292915050565b6000602082840312156136c8578081fd5b813561255b81614762565b600080604083850312156136e5578081fd5b82356136f081614762565b9150602083013561370081614762565b809150509250929050565b60008060006060848603121561371f578081fd5b833561372a81614762565b9250602084013561373a81614762565b929592945050506040919091013590565b6000806040838503121561375d578182fd5b823561376881614762565b946020939093013593505050565b600060208284031215613787578081fd5b813561255b81614777565b6000602082840312156137a3578081fd5b815161255b81614777565b600080600080608085870312156137c3578081fd5b84356137ce81614762565b935060208501356137de81614762565b925060408501356137ee81614762565b915060608501356137fe81614762565b939692955090935050565b60008060008060008060c08789031215613821578182fd5b863561382c81614762565b9550602087013561383c81614762565b9450604087013561384c81614762565b9350606087013561385c81614762565b9250608087013567ffffffffffffffff80821115613878578384fd5b6138848a838b01613664565b935060a0890135915080821115613899578283fd5b506138a689828a01613664565b9150509295509295509295565b6000602082840312156138c4578081fd5b815161255b81614762565b6000602082840312156138e0578081fd5b815167ffffffffffffffff8111156138f6578182fd5b80830184601f820112613907578283fd5b80519150613917613682836146f4565b82815285602084840101111561392b578384fd5b61393c836020830160208501614736565b95945050505050565b600060208284031215613956578081fd5b5035919050565b60006020828403121561396e578081fd5b5051919050565b60008060408385031215613987578182fd5b50508035926020909101359150565b6000602082840312156139a7578081fd5b815160ff8116811461255b578182fd5b600082516139c9818460208701614736565b9190910192915050565b600083516139e5818460208801614736565b83519083016139f8828260208801614736565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b901515815260200190565b6000602082528251806020840152613a96816040850160208701614736565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60208082526026908201527f547275654669506f6f6c3a204a6f696e696e672074686520706f6f6c2069732060408201527f7061757365640000000000000000000000000000000000000000000000000000606082015260800190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201527f6573730000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f547275654669506f6f6c3a2042656e6566696369617279206973206e6f74207360408201527f6574000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560408201527f7373000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526034908201527f547275654669506f6f6c3a204e6f7420656e6f7567682066756e64732074616b60408201527f656e2066726f6d20746865207374726174656779000000000000000000000000606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f547275654669506f6f6c3a20496e73756666696369656e74206c69717569646960408201527f7479000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f547275654669506f6f6c323a204e6f20646566696369656e637920746f6b656e60408201527f20666f756e6420666f72206c6f616e0000000000000000000000000000000000606082015260800190565b6020808252602e908201527f547275654669506f6f6c3a2043616e6e6f74206a6f696e20616e64206578697460408201527f20696e2073616d6520626c6f636b000000000000000000000000000000000000606082015260800190565b60208082526031908201527f547275654669506f6f6c3a20416c6c2066756e64732073686f756c642062652060408201527f77697468647261776e20746f20706f6f6c000000000000000000000000000000606082015260800190565b60208082526030908201527f547275654669506f6f6c3a2053747261746567792076616c756520657870656360408201527f74656420746f2062652068696768657200000000000000000000000000000000606082015260800190565b60208082526031908201527f547275654669506f6f6c3a20506f6f6c20686173206e6f20737472617465677960408201527f20746f2077697468647261772066726f6d000000000000000000000000000000606082015260800190565b60208082526034908201527f547275654669506f6f6c3a2043616c6c6572206973206e6f7420746865206c6560408201527f6e646572206f72206372656469744167656e6379000000000000000000000000606082015260800190565b60208082526030908201527f547275654669506f6f6c3a20537769746368656420737472617465677920736860408201527f6f756c64206265206465706c6574656400000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526032908201527f547275654669506f6f6c3a2042656e656669636961727920616464726573732060408201527f63616e6e6f742062652073657420746f20300000000000000000000000000000606082015260800190565b60208082526027908201527f547275654669506f6f6c3a20506f6f6c20686173206e6f20737472617465677960408201527f2073657420757000000000000000000000000000000000000000000000000000606082015260800190565b60208082526028908201527f547275654669506f6f6c3a204e6f7420656e6f756768206c697175696469747960408201527f20696e20706f6f6c000000000000000000000000000000000000000000000000606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201527f656e20696e697469616c697a6564000000000000000000000000000000000000606082015260800190565b60208082526024908201527f547275654669506f6f6c3a2053686f756c642062652063616c6c65642062792060408201527f5341465500000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360408201527f7300000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f547275654669506f6f6c3a204665652063616e6e6f742065786365656420747260408201527f616e73616374696f6e2076616c75650000000000000000000000000000000000606082015260800190565b60208082526029908201527f547275654669506f6f6c3a20496e73756666696369656e742063757272656e6360408201527f792062616c616e63650000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460408201527f6472657373000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460408201527f7265737300000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f547275654669506f6f6c3a20496e73756666696369656e742066756e64730000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602e908201527f547275654669506f6f6c3a2043616e6e6f742073776974636820746f2074686560408201527f2073616d65207374726174656779000000000000000000000000000000000000606082015260800190565b60208082526028908201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652070656e646960408201527f6e67206f776e6572000000000000000000000000000000000000000000000000606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f547275654669506f6f6c3a20546f2070726563656465732066726f6d00000000604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b60208082526032908201527f547275654669506f6f6c3a2043757272656e63792062616c616e63652065787060408201527f656374656420746f206265206869676865720000000000000000000000000000606082015260800190565b61ffff91909116815260200190565b90815260200190565b918252602082015260400190565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146ec57600080fd5b604052919050565b600067ffffffffffffffff82111561470a578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015614751578181015183820152602001614739565b838111156129e45750506000910152565b6001600160a01b038116811461115b57600080fd5b801515811461115b57600080fdfe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220b2af177ba35c19f99a7a9226a3710d3fa1341e30a12408f6d7404259efde17ae64736f6c634300060a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.