Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 12677101 | 1147 days ago | IN | 0 ETH | 0.13741473 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Fund
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-06-21 */ // SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // Part: IFund interface IFund { function underlying() external view returns (address); function relayer() external view returns (address); function deposit(uint256 amountWei) external; function depositFor(uint256 amountWei, address holder) external; function withdraw(uint256 numberOfShares) external; function getPricePerShare() external view returns (uint256); function totalValueLocked() external view returns (uint256); function underlyingBalanceWithInvestmentForHolder(address holder) external view returns (uint256); } // Part: IStrategy interface IStrategy { function name() external pure returns (string memory); function version() external pure returns (string memory); function underlying() external view returns (address); function fund() external view returns (address); function creator() external view returns (address); function withdrawAllToFund() external; function withdrawToFund(uint256 amount) external; function investedUnderlyingBalance() external view returns (uint256); function doHardWork() external; function depositArbCheck() external view returns (bool); } // Part: IUpgradeSource interface IUpgradeSource { function shouldUpgrade() external view returns (bool, address); function finalizeUpgrade() external; } // Part: OpenZeppelin/[email protected]/AddressUpgradeable /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 on 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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { 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); } } } } // Part: OpenZeppelin/[email protected]/IERC20Upgradeable /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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); } // Part: OpenZeppelin/[email protected]/MathUpgradeable /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // Part: OpenZeppelin/[email protected]/SafeMathUpgradeable /** * @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 SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @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) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @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) { 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, reverting 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) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting 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) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * 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); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * 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); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * 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; } } // Part: OpenZeppelin/[email protected]/Address /** * @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 on 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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { 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); } } } } // Part: OpenZeppelin/[email protected]/IERC20 /** * @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); } // Part: OpenZeppelin/[email protected]/SafeMath /** * @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, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @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) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @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) { 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, reverting 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) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting 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) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * 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); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * 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); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * 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; } } // Part: SetGetAssembly contract SetGetAssembly { // solhint-disable-next-line no-empty-blocks constructor() public {} function setAddress(bytes32 slot, address _address) internal { // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, _address) } } function setUint256(bytes32 slot, uint256 _value) internal { // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, _value) } } function setUint8(bytes32 slot, uint8 _value) internal { // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, _value) } } function setBool(bytes32 slot, bool _value) internal { setUint256(slot, _value ? 1 : 0); } function getBool(bytes32 slot) internal view returns (bool) { return (getUint256(slot) == 1); } function getAddress(bytes32 slot) internal view returns (address str) { // solhint-disable-next-line no-inline-assembly assembly { str := sload(slot) } } function getUint256(bytes32 slot) internal view returns (uint256 str) { // solhint-disable-next-line no-inline-assembly assembly { str := sload(slot) } } function getUint8(bytes32 slot) internal view returns (uint8 str) { // solhint-disable-next-line no-inline-assembly assembly { str := sload(slot) } } } // Part: OpenZeppelin/[email protected]/Initializable /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract 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 protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already 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) { return !AddressUpgradeable.isContract(address(this)); } } // Part: OpenZeppelin/[email protected]/SafeERC20 /** * @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"); } } } // Part: FundStorage contract FundStorage is Initializable, SetGetAssembly { bytes32 internal constant _UNDERLYING_SLOT = 0xe0dc1d429ff8628e5936b3d6a6546947e1cc9ea7415a59d46ce95b3cfa4442b9; bytes32 internal constant _UNDERLYING_UNIT_SLOT = 0x4840b03aa097a422092d99dc6875c2b69e8f48c9af2563a0447f3b4e4928d962; bytes32 internal constant _DECIMALS_SLOT = 0x15b9fa1072bc4b2cdb762a49a2c7917b8b3af02283e37ffd41d0fccd4eef0d48; bytes32 internal constant _FUND_MANAGER_SLOT = 0x670552e214026020a9e6caa820519c7f879b21bd75b5571387d6a9cf8f94bd18; bytes32 internal constant _RELAYER_SLOT = 0x84e8c6b8f2281d51d9f683d351409724c3caa7848051aeb9d92c106ab36cc24c; bytes32 internal constant _PLATFORM_REWARDS_SLOT = 0x92260bfe68dd0f8a9f5439b75466781ba1ce44523ed1a3026a73eada49072e65; bytes32 internal constant _DEPOSIT_LIMIT_SLOT = 0xca2f8a3e9ea81335bcce793cde55fc0c38129b594f53052d2bb18099ffa72613; bytes32 internal constant _DEPOSIT_LIMIT_TX_MAX_SLOT = 0x769f312c3790719cf1ea5f75303393f080fd62be88d75fa86726a6be00bb5a24; bytes32 internal constant _DEPOSIT_LIMIT_TX_MIN_SLOT = 0x9027949576d185c74d79ad3b8a8dbff32126f3a3ee140b346f146beb18234c85; bytes32 internal constant _PERFORMANCE_FEE_FUND_SLOT = 0x5b8979500398f8fbeb42c36d18f31a76fd0ab30f4338d864e7d8734b340e9bb9; bytes32 internal constant _PLATFORM_FEE_SLOT = 0x2084059f3bff3cc3fd204df32325dcb05f47c2f590aba5d103ec584523738e7a; bytes32 internal constant _WITHDRAWAL_FEE_SLOT = 0x0fa90db0cd58feef247d70d3b21f64c03d0e3ec10eb297f015da0cc09eb3412c; bytes32 internal constant _MAX_INVESTMENT_IN_STRATEGIES_SLOT = 0xe3b5969c9426551aa8f16dbc7b25042b9b9c9869b759c77a85f0b097ac363475; bytes32 internal constant _TOTAL_WEIGHT_IN_STRATEGIES_SLOT = 0x63177e03c47ab825f04f5f8f2334e312239890e7588db78cabe10d7aec327fd2; bytes32 internal constant _TOTAL_ACCOUNTED_SLOT = 0xa19f3b8a62465676ae47ab811ee15e3d2b68d88869cb38686d086a11d382f6bb; bytes32 internal constant _TOTAL_INVESTED_SLOT = 0x49c84685200b42972f845832b2c3da3d71def653c151340801aeae053ce104e9; bytes32 internal constant _DEPOSITS_PAUSED_SLOT = 0x3cefcfe9774096ac956c0d63992ea27a01fb3884a22b8765ad63c8366f90a9c8; bytes32 internal constant _SHOULD_REBALANCE_SLOT = 0x7f8e3dfb98485aa419c1d05b6ea089a8cddbafcfcf4491db33f5d0b5fe4f32c7; bytes32 internal constant _LAST_HARDWORK_TIMESTAMP_SLOT = 0x0260c2bf5555cd32cedf39c0fcb0eab8029c67b3d5137faeb3e24a500db80bc9; bytes32 internal constant _NEXT_IMPLEMENTATION_SLOT = 0xa7ae0fa763ec3009113ccc5eb9089e1f0028607f5b8198c52cd42366c1ddb17b; constructor() public { assert( _UNDERLYING_SLOT == bytes32( uint256( keccak256("eip1967.mesh.finance.fundStorage.underlying") ) - 1 ) ); assert( _UNDERLYING_UNIT_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.underlyingUnit" ) ) - 1 ) ); assert( _DECIMALS_SLOT == bytes32( uint256( keccak256("eip1967.mesh.finance.fundStorage.decimals") ) - 1 ) ); assert( _FUND_MANAGER_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.fundManager" ) ) - 1 ) ); assert( _RELAYER_SLOT == bytes32( uint256( keccak256("eip1967.mesh.finance.fundStorage.relayer") ) - 1 ) ); assert( _PLATFORM_REWARDS_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.platformRewards" ) ) - 1 ) ); assert( _DEPOSIT_LIMIT_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.depositLimit" ) ) - 1 ) ); assert( _DEPOSIT_LIMIT_TX_MAX_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.depositLimitTxMax" ) ) - 1 ) ); assert( _DEPOSIT_LIMIT_TX_MIN_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.depositLimitTxMin" ) ) - 1 ) ); assert( _PERFORMANCE_FEE_FUND_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.performanceFeeFund" ) ) - 1 ) ); assert( _PLATFORM_FEE_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.platformFee" ) ) - 1 ) ); assert( _WITHDRAWAL_FEE_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.withdrawalFee" ) ) - 1 ) ); assert( _MAX_INVESTMENT_IN_STRATEGIES_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.maxInvestmentInStrategies" ) ) - 1 ) ); assert( _TOTAL_WEIGHT_IN_STRATEGIES_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.totalWeightInStrategies" ) ) - 1 ) ); assert( _TOTAL_ACCOUNTED_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.totalAccounted" ) ) - 1 ) ); assert( _TOTAL_INVESTED_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.totalInvested" ) ) - 1 ) ); assert( _DEPOSITS_PAUSED_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.depositsPaused" ) ) - 1 ) ); assert( _SHOULD_REBALANCE_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.shouldRebalance" ) ) - 1 ) ); assert( _LAST_HARDWORK_TIMESTAMP_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.lastHardworkTimestamp" ) ) - 1 ) ); assert( _NEXT_IMPLEMENTATION_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.fundStorage.nextImplementation" ) ) - 1 ) ); } function initializeFundStorage( address _underlying, uint256 _underlyingUnit, uint8 _decimals, address _fundManager, address _relayer, address _platformRewards ) public initializer { _setUnderlying(_underlying); _setUnderlyingUnit(_underlyingUnit); _setDecimals(_decimals); _setFundManager(_fundManager); _setRelayer(_relayer); _setPlatformRewards(_platformRewards); _setDepositLimit(0); _setDepositLimitTxMax(0); _setDepositLimitTxMin(0); _setPerformanceFeeFund(0); _setPlatformFee(0); _setWithdrawalFee(0); _setMaxInvestmentInStrategies(9000); // 9000 BPS (90%) can be accessed by the strategies. This is to keep something in fund for withdrawal. _setTotalWeightInStrategies(0); _setTotalAccounted(0); _setTotalInvested(0); _setDepositsPaused(false); _setShouldRebalance(false); _setLastHardworkTimestamp(0); _setNextImplementation(address(0)); } function _setUnderlying(address _address) internal { setAddress(_UNDERLYING_SLOT, _address); } function _underlying() internal view returns (address) { return getAddress(_UNDERLYING_SLOT); } function _setUnderlyingUnit(uint256 _value) internal { setUint256(_UNDERLYING_UNIT_SLOT, _value); } function _underlyingUnit() internal view returns (uint256) { return getUint256(_UNDERLYING_UNIT_SLOT); } function _setDecimals(uint8 _value) internal { setUint8(_DECIMALS_SLOT, _value); } function _decimals() internal view returns (uint8) { return getUint8(_DECIMALS_SLOT); } function _setFundManager(address _fundManager) internal { setAddress(_FUND_MANAGER_SLOT, _fundManager); } function _fundManager() internal view returns (address) { return getAddress(_FUND_MANAGER_SLOT); } function _setRelayer(address _relayer) internal { setAddress(_RELAYER_SLOT, _relayer); } function _relayer() internal view returns (address) { return getAddress(_RELAYER_SLOT); } function _setPlatformRewards(address _rewards) internal { setAddress(_PLATFORM_REWARDS_SLOT, _rewards); } function _platformRewards() internal view returns (address) { return getAddress(_PLATFORM_REWARDS_SLOT); } function _setDepositLimit(uint256 _value) internal { setUint256(_DEPOSIT_LIMIT_SLOT, _value); } function _depositLimit() internal view returns (uint256) { return getUint256(_DEPOSIT_LIMIT_SLOT); } function _setDepositLimitTxMax(uint256 _value) internal { setUint256(_DEPOSIT_LIMIT_TX_MAX_SLOT, _value); } function _depositLimitTxMax() internal view returns (uint256) { return getUint256(_DEPOSIT_LIMIT_TX_MAX_SLOT); } function _setDepositLimitTxMin(uint256 _value) internal { setUint256(_DEPOSIT_LIMIT_TX_MIN_SLOT, _value); } function _depositLimitTxMin() internal view returns (uint256) { return getUint256(_DEPOSIT_LIMIT_TX_MIN_SLOT); } function _setPerformanceFeeFund(uint256 _value) internal { setUint256(_PERFORMANCE_FEE_FUND_SLOT, _value); } function _performanceFeeFund() internal view returns (uint256) { return getUint256(_PERFORMANCE_FEE_FUND_SLOT); } function _setPlatformFee(uint256 _value) internal { setUint256(_PLATFORM_FEE_SLOT, _value); } function _platformFee() internal view returns (uint256) { return getUint256(_PLATFORM_FEE_SLOT); } function _setWithdrawalFee(uint256 _value) internal { setUint256(_WITHDRAWAL_FEE_SLOT, _value); } function _withdrawalFee() internal view returns (uint256) { return getUint256(_WITHDRAWAL_FEE_SLOT); } function _setMaxInvestmentInStrategies(uint256 _value) internal { setUint256(_MAX_INVESTMENT_IN_STRATEGIES_SLOT, _value); } function _maxInvestmentInStrategies() internal view returns (uint256) { return getUint256(_MAX_INVESTMENT_IN_STRATEGIES_SLOT); } function _setTotalWeightInStrategies(uint256 _value) internal { setUint256(_TOTAL_WEIGHT_IN_STRATEGIES_SLOT, _value); } function _totalWeightInStrategies() internal view returns (uint256) { return getUint256(_TOTAL_WEIGHT_IN_STRATEGIES_SLOT); } function _setTotalAccounted(uint256 _value) internal { setUint256(_TOTAL_ACCOUNTED_SLOT, _value); } function _totalAccounted() internal view returns (uint256) { return getUint256(_TOTAL_ACCOUNTED_SLOT); } function _setTotalInvested(uint256 _value) internal { setUint256(_TOTAL_INVESTED_SLOT, _value); } function _totalInvested() internal view returns (uint256) { return getUint256(_TOTAL_INVESTED_SLOT); } function _setDepositsPaused(bool _value) internal { setBool(_DEPOSITS_PAUSED_SLOT, _value); } function _depositsPaused() internal view returns (bool) { return getBool(_DEPOSITS_PAUSED_SLOT); } function _setShouldRebalance(bool _value) internal { setBool(_SHOULD_REBALANCE_SLOT, _value); } function _shouldRebalance() internal view returns (bool) { return getBool(_SHOULD_REBALANCE_SLOT); } function _setLastHardworkTimestamp(uint256 _value) internal { setUint256(_LAST_HARDWORK_TIMESTAMP_SLOT, _value); } function _lastHardworkTimestamp() internal view returns (uint256) { return getUint256(_LAST_HARDWORK_TIMESTAMP_SLOT); } function _setNextImplementation(address _newImplementation) internal { setAddress(_NEXT_IMPLEMENTATION_SLOT, _newImplementation); } function _nextImplementation() internal view returns (address) { return getAddress(_NEXT_IMPLEMENTATION_SLOT); } uint256[50] private bigEmptySlot; } // Part: Governable contract Governable is Initializable, SetGetAssembly { event GovernanceUpdated(address newGovernance, address oldGovernance); bytes32 internal constant _GOVERNANCE_SLOT = 0x597f9c7c685b907e823520bd45aeb3d58b505f86b2e41cd5b4cd5b6c72782950; bytes32 internal constant _PENDING_GOVERNANCE_SLOT = 0xcd77091f18f9504fccf6140ab99e20533c811d470bb9a5a983d0edc0720fbf8c; modifier onlyGovernance() { require(_governance() == msg.sender, "Not governance"); _; } constructor() public { assert( _GOVERNANCE_SLOT == bytes32( uint256( keccak256("eip1967.mesh.finance.governable.governance") ) - 1 ) ); assert( _PENDING_GOVERNANCE_SLOT == bytes32( uint256( keccak256( "eip1967.mesh.finance.governable.pendingGovernance" ) ) - 1 ) ); } function initializeGovernance(address _governance) public initializer { _setGovernance(_governance); } function _setGovernance(address _governance) private { setAddress(_GOVERNANCE_SLOT, _governance); } function _setPendingGovernance(address _pendingGovernance) private { setAddress(_PENDING_GOVERNANCE_SLOT, _pendingGovernance); } function updateGovernance(address _newGovernance) public onlyGovernance { require( _newGovernance != address(0), "new governance shouldn't be empty" ); _setPendingGovernance(_newGovernance); } function acceptGovernance() public { require(_pendingGovernance() == msg.sender, "Not pending governance"); address oldGovernance = _governance(); _setGovernance(msg.sender); emit GovernanceUpdated(msg.sender, oldGovernance); } function _governance() internal view returns (address str) { return getAddress(_GOVERNANCE_SLOT); } function _pendingGovernance() internal view returns (address str) { return getAddress(_PENDING_GOVERNANCE_SLOT); } function governance() public view returns (address) { return _governance(); } } // Part: OpenZeppelin/[email protected]/ContextUpgradeable /* * @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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } 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; } uint256[50] private __gap; } // Part: OpenZeppelin/[email protected]/ReentrancyGuardUpgradeable /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; } // Part: OpenZeppelin/[email protected]/ERC20Upgradeable /** * @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 ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable { using SafeMathUpgradeable for uint256; 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_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(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 virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual 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 view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 view virtual override 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 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 virtual { _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 { } uint256[44] private __gap; } // File: Fund.sol contract Fund is ERC20Upgradeable, ReentrancyGuardUpgradeable, IFund, IUpgradeSource, Governable, FundStorage { using SafeERC20 for IERC20; using AddressUpgradeable for address; using SafeMathUpgradeable for uint256; using SafeMathUpgradeable for uint8; event Withdraw(address indexed beneficiary, uint256 amount, uint256 fee); event Deposit(address indexed beneficiary, uint256 amount); event InvestInStrategy(address strategy, uint256 amount); event StrategyRewards( address strategy, uint256 profit, uint256 strategyCreatorFee ); event FundManagerRewards(uint256 profitTotal, uint256 fundManagerFee); event PlatformRewards( uint256 lastBalance, uint256 timeElapsed, uint256 platformFee ); event HardWorkDone(uint256 totalValueLocked, uint256 pricePerShare); event StrategyAdded( address strategy, uint256 weightage, uint256 performanceFeeStrategy ); event StrategyWeightageUpdated(address strategy, uint256 newWeightage); event StrategyPerformanceFeeUpdated( address strategy, uint256 newPerformanceFeeStrategy ); event StrategyRemoved(address strategy); address internal constant ZERO_ADDRESS = address(0); uint256 internal constant MAX_BPS = 10000; // 100% in basis points uint256 internal constant SECS_PER_YEAR = 31556952; // 365.25 days from yearn uint256 internal constant MAX_PLATFORM_FEE = 500; // 5% (annual on AUM), goes to governance/treasury uint256 internal constant MAX_PERFORMANCE_FEE_FUND = 1000; // 10% on profits, goes to fund manager uint256 internal constant MAX_PERFORMANCE_FEE_STRATEGY = 1000; // 10% on profits, goes to strategy creator uint256 internal constant MAX_WITHDRAWAL_FEE = 100; // 1%, goes to governance/treasury struct StrategyParams { uint256 weightage; // weightage of total assets in fund this strategy can access (in BPS) (5000 for 50%) uint256 performanceFeeStrategy; // in BPS, fee on yield of the strategy, goes to strategy creator uint256 activation; // timestamp when strategy is added uint256 lastBalance; // balance at last hard work uint256 indexInList; } mapping(address => StrategyParams) public strategies; address[] public strategyList; // solhint-disable-next-line no-empty-blocks constructor() public {} function initializeFund( address _governance, address _underlying, string memory _name, string memory _symbol ) public initializer { ERC20Upgradeable.__ERC20_init(_name, _symbol); __ReentrancyGuard_init(); Governable.initializeGovernance(_governance); uint8 _decimals = ERC20Upgradeable(_underlying).decimals(); uint256 _underlyingUnit = 10**uint256(_decimals); FundStorage.initializeFundStorage( _underlying, _underlyingUnit, _decimals, _governance, // fund manager is initialized as governance _governance, // relayer is initialized as governance _governance // rewards contract is initialized as governance ); } modifier onlyFundManagerOrGovernance() { require( (_governance() == msg.sender) || (_fundManager() == msg.sender), "Not governance nor fund manager" ); _; } modifier onlyFundManagerOrGovernanceOrRelayer() { require( (_governance() == msg.sender) || (_fundManager() == msg.sender) || (_relayer() == msg.sender), "Not governance nor fund manager nor relayer" ); _; } modifier whenDepositsNotPaused() { require(!_depositsPaused(), "Deposits are paused"); _; } function fundManager() external view returns (address) { return _fundManager(); } function relayer() external view override returns (address) { return _relayer(); } function underlying() external view override returns (address) { return _underlying(); } function underlyingUnit() external view returns (uint256) { return _underlyingUnit(); } function decimals() public view virtual override returns (uint8) { return _decimals(); } function getStrategyCount() internal view returns (uint256) { return strategyList.length; } modifier whenStrategyDefined() { require(getStrategyCount() > 0, "Strategies must be defined"); _; } function getStrategyList() public view returns (address[] memory) { return strategyList; } function getStrategy(address strategy) public view returns (StrategyParams memory) { return strategies[strategy]; } /* * Returns the underlying balance currently in the fund. */ function underlyingBalanceInFund() internal view returns (uint256) { return IERC20(_underlying()).balanceOf(address(this)); } /* * Returns the current underlying (e.g., DAI's) balance together with * the invested amount (if DAI is invested elsewhere by the strategies). */ function underlyingBalanceWithInvestment() internal view returns (uint256) { uint256 underlyingBalance = underlyingBalanceInFund(); for (uint256 i; i < getStrategyCount(); i++) { underlyingBalance = underlyingBalance.add( IStrategy(strategyList[i]).investedUnderlyingBalance() ); } return underlyingBalance; } /* * Returns price per share, scaled by underlying unit (10 ** decimals) to keep everything in uint256. */ function _getPricePerShare() internal view returns (uint256) { return totalSupply() == 0 ? _underlyingUnit() : _underlyingUnit().mul(underlyingBalanceWithInvestment()).div( totalSupply() ); } function getPricePerShare() external view override returns (uint256) { return _getPricePerShare(); } function totalValueLocked() external view override returns (uint256) { return underlyingBalanceWithInvestment(); } function _underlyingFromShares(uint256 numShares) internal view returns (uint256) { return underlyingBalanceWithInvestment().mul(numShares).div(totalSupply()); } /* * get the user's balance (in underlying) */ function underlyingBalanceWithInvestmentForHolder(address holder) external view override returns (uint256) { if (totalSupply() == 0) { return 0; } return _underlyingFromShares(balanceOf(holder)); } function isActiveStrategy(address strategy) internal view returns (bool) { return strategies[strategy].weightage > 0; } function addStrategy( address newStrategy, uint256 weightage, uint256 performanceFeeStrategy ) external onlyFundManagerOrGovernance { require(newStrategy != ZERO_ADDRESS, "new newStrategy cannot be empty"); require( IStrategy(newStrategy).fund() == address(this), "The strategy does not belong to this fund" ); require( isActiveStrategy(newStrategy) == false, "This strategy is already active in this fund" ); require(weightage > 0, "The weightage should be greater than 0"); uint256 totalWeightInStrategies = _totalWeightInStrategies().add(weightage); require( totalWeightInStrategies <= _maxInvestmentInStrategies(), "Total investment can't be above max allowed" ); require( performanceFeeStrategy <= MAX_PERFORMANCE_FEE_STRATEGY, "Performance fee too high" ); strategies[newStrategy].weightage = weightage; _setTotalWeightInStrategies(totalWeightInStrategies); // solhint-disable-next-line not-rely-on-time strategies[newStrategy].activation = block.timestamp; strategies[newStrategy].indexInList = getStrategyCount(); strategies[newStrategy].performanceFeeStrategy = performanceFeeStrategy; strategyList.push(newStrategy); _setShouldRebalance(true); IERC20(_underlying()).safeApprove(newStrategy, 0); IERC20(_underlying()).safeApprove(newStrategy, type(uint256).max); emit StrategyAdded(newStrategy, weightage, performanceFeeStrategy); } function removeStrategy(address activeStrategy) external onlyFundManagerOrGovernance { require( activeStrategy != ZERO_ADDRESS, "current strategy cannot be empty" ); require( isActiveStrategy(activeStrategy), "This strategy is not active in this fund" ); _setTotalWeightInStrategies( _totalWeightInStrategies().sub(strategies[activeStrategy].weightage) ); uint256 totalStrategies = getStrategyCount(); for ( uint256 i = strategies[activeStrategy].indexInList; i < totalStrategies - 1; i++ ) { strategyList[i] = strategyList[i + 1]; strategies[strategyList[i]].indexInList = i; } strategyList.pop(); delete strategies[activeStrategy]; IERC20(_underlying()).safeApprove(activeStrategy, 0); IStrategy(activeStrategy).withdrawAllToFund(); _setShouldRebalance(true); emit StrategyRemoved(activeStrategy); } function updateStrategyWeightage( address activeStrategy, uint256 newWeightage ) external onlyFundManagerOrGovernance { require( activeStrategy != ZERO_ADDRESS, "current strategy cannot be empty" ); require( isActiveStrategy(activeStrategy), "This strategy is not active in this fund" ); require(newWeightage > 0, "The weightage should be greater than 0"); uint256 totalWeightInStrategies = _totalWeightInStrategies() .sub(strategies[activeStrategy].weightage) .add(newWeightage); require( totalWeightInStrategies <= _maxInvestmentInStrategies(), "Total investment can't be above max allowed" ); _setTotalWeightInStrategies(totalWeightInStrategies); strategies[activeStrategy].weightage = newWeightage; _setShouldRebalance(true); emit StrategyWeightageUpdated(activeStrategy, newWeightage); } function updateStrategyPerformanceFee( address activeStrategy, uint256 newPerformanceFeeStrategy ) external onlyFundManagerOrGovernance { require( activeStrategy != ZERO_ADDRESS, "current strategy cannot be empty" ); require( isActiveStrategy(activeStrategy), "This strategy is not active in this fund" ); require( newPerformanceFeeStrategy <= MAX_PERFORMANCE_FEE_STRATEGY, "Performance fee too high" ); strategies[activeStrategy] .performanceFeeStrategy = newPerformanceFeeStrategy; emit StrategyPerformanceFeeUpdated( activeStrategy, newPerformanceFeeStrategy ); } function processFees() internal { uint256 profitToFund = 0; for (uint256 i; i < getStrategyCount(); i++) { address strategy = strategyList[i]; uint256 profit = 0; uint256 strategyCreatorFee = 0; if ( IStrategy(strategy).investedUnderlyingBalance() > strategies[strategy].lastBalance ) { profit = IStrategy(strategy).investedUnderlyingBalance() - strategies[strategy].lastBalance; strategyCreatorFee = profit .mul(strategies[strategy].performanceFeeStrategy) .div(MAX_BPS); if ( strategyCreatorFee > 0 && strategyCreatorFee < underlyingBalanceInFund() ) { IERC20(_underlying()).safeTransfer( IStrategy(strategy).creator(), strategyCreatorFee ); } profitToFund = profitToFund.add(profit).sub(strategyCreatorFee); } emit StrategyRewards(strategy, profit, strategyCreatorFee); } uint256 fundManagerFee = profitToFund.mul(_performanceFeeFund()).div(MAX_BPS); if (fundManagerFee > 0 && fundManagerFee < underlyingBalanceInFund()) { address fundManagerRewards = (_fundManager() == _governance()) ? _platformRewards() : _fundManager(); IERC20(_underlying()).safeTransfer( fundManagerRewards, fundManagerFee ); emit FundManagerRewards(profitToFund, fundManagerFee); } uint256 platformFee = // solhint-disable-next-line not-rely-on-time (_totalInvested() * (block.timestamp - _lastHardworkTimestamp())) .mul(_platformFee()) .div(MAX_BPS) .div(SECS_PER_YEAR); if (platformFee > 0 && platformFee < underlyingBalanceInFund()) { IERC20(_underlying()).safeTransfer(_platformRewards(), platformFee); emit PlatformRewards( _totalInvested(), // solhint-disable-next-line not-rely-on-time block.timestamp - _lastHardworkTimestamp(), platformFee ); } } /* * Invests the underlying capital to various strategies. Looks for weightage changes. */ function doHardWork() external whenStrategyDefined onlyFundManagerOrGovernanceOrRelayer { if (_lastHardworkTimestamp() > 0) { processFees(); } // ensure that new funds are invested too if (_shouldRebalance()) { _setShouldRebalance(false); doHardWorkWithRebalance(); } else { doHardWorkWithoutRebalance(); } // solhint-disable-next-line not-rely-on-time _setLastHardworkTimestamp(block.timestamp); emit HardWorkDone( underlyingBalanceWithInvestment(), _getPricePerShare() ); } function doHardWorkWithoutRebalance() internal { uint256 lastReserve = _totalAccounted() > 0 ? _totalAccounted().sub(_totalInvested()) : 0; uint256 availableAmountToInvest = underlyingBalanceInFund() > lastReserve ? underlyingBalanceInFund().sub(lastReserve) : 0; if (availableAmountToInvest == 0) { return; } _setTotalAccounted(_totalAccounted().add(availableAmountToInvest)); uint256 totalInvested = 0; for (uint256 i; i < getStrategyCount(); i++) { address strategy = strategyList[i]; uint256 availableAmountForStrategy = availableAmountToInvest.mul(strategies[strategy].weightage).div( MAX_BPS ); if (availableAmountForStrategy > 0) { IERC20(_underlying()).safeTransfer( strategy, availableAmountForStrategy ); totalInvested = totalInvested.add(availableAmountForStrategy); emit InvestInStrategy(strategy, availableAmountForStrategy); } IStrategy(strategy).doHardWork(); strategies[strategy].lastBalance = IStrategy(strategy) .investedUnderlyingBalance(); } _setTotalInvested(totalInvested); } function doHardWorkWithRebalance() internal { uint256 totalUnderlyingWithInvestment = underlyingBalanceWithInvestment(); _setTotalAccounted(totalUnderlyingWithInvestment); uint256 totalInvested = 0; uint256[] memory toDeposit = new uint256[](getStrategyCount()); for (uint256 i; i < getStrategyCount(); i++) { address strategy = strategyList[i]; uint256 shouldBeInStrategy = totalUnderlyingWithInvestment .mul(strategies[strategy].weightage) .div(MAX_BPS); totalInvested = totalInvested.add(shouldBeInStrategy); uint256 currentlyInStrategy = IStrategy(strategy).investedUnderlyingBalance(); if (currentlyInStrategy > shouldBeInStrategy) { // withdraw from strategy IStrategy(strategy).withdrawToFund( currentlyInStrategy.sub(shouldBeInStrategy) ); } else if (shouldBeInStrategy > currentlyInStrategy) { // can not directly deposit here as there might not be enough balance before withdrawing from required strategies toDeposit[i] = shouldBeInStrategy.sub(currentlyInStrategy); } } _setTotalInvested(totalInvested); for (uint256 i; i < getStrategyCount(); i++) { address strategy = strategyList[i]; if (toDeposit[i] > 0) { IERC20(_underlying()).safeTransfer(strategy, toDeposit[i]); emit InvestInStrategy(strategy, toDeposit[i]); } IStrategy(strategy).doHardWork(); strategies[strategy].lastBalance = IStrategy(strategy) .investedUnderlyingBalance(); } } function pauseDeposits(bool trigger) external onlyFundManagerOrGovernance { _setDepositsPaused(trigger); } /* * Allows for depositing the underlying asset in exchange for shares. * Approval is assumed. */ function deposit(uint256 amount) external override nonReentrant whenDepositsNotPaused { _deposit(amount, msg.sender, msg.sender); } /* * Allows for depositing the underlying asset and shares assigned to the holder. * This facilitates depositing for someone else (e.g. using DepositHelper) */ function depositFor(uint256 amount, address holder) external override nonReentrant whenDepositsNotPaused { require(holder != ZERO_ADDRESS, "holder must be defined"); _deposit(amount, msg.sender, holder); } function _deposit( uint256 amount, address sender, address beneficiary ) internal { require(amount > 0, "Cannot deposit 0"); if (_depositLimit() > 0) { // if deposit limit is 0, then there is no deposit limit require( underlyingBalanceWithInvestment().add(amount) <= _depositLimit(), "Total deposit limit hit" ); } if (_depositLimitTxMax() > 0) { // if deposit limit is 0, then there is no deposit limit require( amount <= _depositLimitTxMax(), "Maximum transaction deposit limit hit" ); } if (_depositLimitTxMin() > 0) { // if deposit limit is 0, then there is no deposit limit require( amount >= _depositLimitTxMin(), "Minimum transaction deposit limit hit" ); } uint256 toMint = totalSupply() == 0 ? amount : amount.mul(totalSupply()).div( underlyingBalanceWithInvestment() ); _mint(beneficiary, toMint); IERC20(_underlying()).safeTransferFrom(sender, address(this), amount); emit Deposit(beneficiary, amount); } function withdraw(uint256 numberOfShares) external override nonReentrant { require(totalSupply() > 0, "Fund has no shares"); require(numberOfShares > 0, "numberOfShares must be greater than 0"); uint256 underlyingAmountToWithdraw = _underlyingFromShares(numberOfShares); _burn(msg.sender, numberOfShares); if (underlyingAmountToWithdraw > underlyingBalanceInFund()) { uint256 missing = underlyingAmountToWithdraw.sub(underlyingBalanceInFund()); uint256 missingCarryOver; for (uint256 i; i < getStrategyCount(); i++) { if (isActiveStrategy(strategyList[i])) { uint256 balanceBefore = underlyingBalanceInFund(); uint256 weightage = strategies[strategyList[i]].weightage; uint256 missingforStrategy = (missing.mul(weightage).div(_totalWeightInStrategies())) .add(missingCarryOver); IStrategy(strategyList[i]).withdrawToFund( missingforStrategy ); missingCarryOver = missingforStrategy .add(balanceBefore) .sub(underlyingBalanceInFund()); } } // recalculate to improve accuracy underlyingAmountToWithdraw = MathUpgradeable.min( underlyingAmountToWithdraw, underlyingBalanceInFund() ); _setShouldRebalance(true); } uint256 withdrawalFee = underlyingAmountToWithdraw.mul(_withdrawalFee()).div(MAX_BPS); if (withdrawalFee > 0) { IERC20(_underlying()).safeTransfer( _platformRewards(), withdrawalFee ); underlyingAmountToWithdraw = underlyingAmountToWithdraw.sub( withdrawalFee ); } IERC20(_underlying()).safeTransfer( msg.sender, underlyingAmountToWithdraw ); emit Withdraw(msg.sender, underlyingAmountToWithdraw, withdrawalFee); } /** * Schedules an upgrade for this fund's proxy. */ function scheduleUpgrade(address newImplementation) external onlyGovernance { // Timelock implementation can be done here later _setNextImplementation(newImplementation); } function shouldUpgrade() external view override returns (bool, address) { return (_nextImplementation() != address(0), _nextImplementation()); } function finalizeUpgrade() external override onlyGovernance { _setNextImplementation(address(0)); } function setFundManager(address newFundManager) external onlyFundManagerOrGovernance { _setFundManager(newFundManager); } function setRelayer(address newRelayer) external onlyFundManagerOrGovernance { _setRelayer(newRelayer); } function setPlatformRewards(address newRewards) external onlyGovernance { _setPlatformRewards(newRewards); } function setShouldRebalance(bool trigger) external onlyFundManagerOrGovernance { _setShouldRebalance(trigger); } function setMaxInvestmentInStrategies(uint256 value) external onlyFundManagerOrGovernance { require(value < MAX_BPS, "Value greater than 100%"); _setMaxInvestmentInStrategies(value); } // if limit == 0 then there is no deposit limit function setDepositLimit(uint256 limit) external onlyFundManagerOrGovernance { _setDepositLimit(limit); } function depositLimit() external view returns (uint256) { return _depositLimit(); } // if limit == 0 then there is no deposit limit function setDepositLimitTxMax(uint256 limit) external onlyFundManagerOrGovernance { _setDepositLimitTxMax(limit); } function depositLimitTxMax() external view returns (uint256) { return _depositLimitTxMax(); } // if limit == 0 then there is no deposit limit function setDepositLimitTxMin(uint256 limit) external onlyFundManagerOrGovernance { _setDepositLimitTxMin(limit); } function depositLimitTxMin() external view returns (uint256) { return _depositLimitTxMin(); } function setPerformanceFeeFund(uint256 fee) external onlyFundManagerOrGovernance { require(fee <= MAX_PERFORMANCE_FEE_FUND, "Fee greater than max limit"); _setPerformanceFeeFund(fee); } function performanceFeeFund() external view returns (uint256) { return _performanceFeeFund(); } function setPlatformFee(uint256 fee) external onlyFundManagerOrGovernance { require(fee <= MAX_PLATFORM_FEE, "Fee greater than max limit"); _setPlatformFee(fee); } function platformFee() external view returns (uint256) { return _platformFee(); } function setWithdrawalFee(uint256 fee) external onlyFundManagerOrGovernance { require(fee <= MAX_WITHDRAWAL_FEE, "Fee greater than max limit"); _setWithdrawalFee(fee); } function withdrawalFee() external view returns (uint256) { return _withdrawalFee(); } // no tokens should ever be stored on this contract. Any tokens that are sent here by mistake are recoverable by governance function sweep(address _token, address _sweepTo) external onlyGovernance { require(_token != address(_underlying()), "can not sweep underlying"); IERC20(_token).safeTransfer( _sweepTo, IERC20(_token).balanceOf(address(this)) ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profitTotal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fundManagerFee","type":"uint256"}],"name":"FundManagerRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGovernance","type":"address"},{"indexed":false,"internalType":"address","name":"oldGovernance","type":"address"}],"name":"GovernanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalValueLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pricePerShare","type":"uint256"}],"name":"HardWorkDone","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvestInStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lastBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeElapsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"platformFee","type":"uint256"}],"name":"PlatformRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"weightage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"performanceFeeStrategy","type":"uint256"}],"name":"StrategyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPerformanceFeeStrategy","type":"uint256"}],"name":"StrategyPerformanceFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"strategyCreatorFee","type":"uint256"}],"name":"StrategyRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"newWeightage","type":"uint256"}],"name":"StrategyWeightageUpdated","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"acceptGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStrategy","type":"address"},{"internalType":"uint256","name":"weightage","type":"uint256"},{"internalType":"uint256","name":"performanceFeeStrategy","type":"uint256"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","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":"address","name":"account","type":"address"}],"name":"balanceOf","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":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"holder","type":"address"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositLimitTxMax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositLimitTxMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doHardWork","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizeUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"getStrategy","outputs":[{"components":[{"internalType":"uint256","name":"weightage","type":"uint256"},{"internalType":"uint256","name":"performanceFeeStrategy","type":"uint256"},{"internalType":"uint256","name":"activation","type":"uint256"},{"internalType":"uint256","name":"lastBalance","type":"uint256"},{"internalType":"uint256","name":"indexInList","type":"uint256"}],"internalType":"struct Fund.StrategyParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initializeFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"uint256","name":"_underlyingUnit","type":"uint256"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"_fundManager","type":"address"},{"internalType":"address","name":"_relayer","type":"address"},{"internalType":"address","name":"_platformRewards","type":"address"}],"name":"initializeFundStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_governance","type":"address"}],"name":"initializeGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"trigger","type":"bool"}],"name":"pauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"performanceFeeFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"activeStrategy","type":"address"}],"name":"removeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"scheduleUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setDepositLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setDepositLimitTxMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setDepositLimitTxMin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFundManager","type":"address"}],"name":"setFundManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setMaxInvestmentInStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setPerformanceFeeFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRewards","type":"address"}],"name":"setPlatformRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRelayer","type":"address"}],"name":"setRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"trigger","type":"bool"}],"name":"setShouldRebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setWithdrawalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shouldUpgrade","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"strategies","outputs":[{"internalType":"uint256","name":"weightage","type":"uint256"},{"internalType":"uint256","name":"performanceFeeStrategy","type":"uint256"},{"internalType":"uint256","name":"activation","type":"uint256"},{"internalType":"uint256","name":"lastBalance","type":"uint256"},{"internalType":"uint256","name":"indexInList","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"strategyList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_sweepTo","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValueLocked","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":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"underlyingBalanceWithInvestmentForHolder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"updateGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"activeStrategy","type":"address"},{"internalType":"uint256","name":"newPerformanceFeeStrategy","type":"uint256"}],"name":"updateStrategyPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"activeStrategy","type":"address"},{"internalType":"uint256","name":"newWeightage","type":"uint256"}],"name":"updateStrategyWeightage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfShares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506151e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80638bc7e8c4116101de578063bdc8144b1161010f578063eb6a0005116100ad578063f47994251161007c578063f47994251461071b578063f8806a131461072e578063fa34d6111461074e578063fc84c390146107615761038e565b8063eb6a0005146106f0578063ec18154e14610703578063ecf708581461070b578063f05f50c1146107135761038e565b8063d0194ed6116100e9578063d0194ed6146106a4578063d7cd647a146106b7578063d7fbc7b8146106ca578063dd62ed3e146106dd5761038e565b8063bdc8144b14610669578063cc8432df1461067c578063cdc39b0a1461068f5761038e565b8063a457c2d71161017c578063b161dd4e11610156578063b161dd4e14610628578063b256126314610630578063b6b55f2514610643578063b8dc491b146106565761038e565b8063a457c2d7146105ef578063a9059cbb14610602578063ac1e5025146106155761038e565b806395d89b41116101b857806395d89b41146105b65780639a508c8e146105be5780639d16acfd146105c6578063a267526b146105dc5761038e565b80638bc7e8c4146105885780638cb1d67f146105905780638e2d2a2d146105a35761038e565b806339509351116102c35780636209ec2d11610261578063738b62e511610230578063738b62e51461055257806374a00f8e146105655780638406c079146105785780638a2320ba146105805761038e565b80636209ec2d1461051c5780636548e9bc146105245780636f307dc31461053757806370a082311461053f5761038e565b80634fa5d8541161029d5780634fa5d854146104e457806353ceb01c146104ec57806355d202a6146104f45780635aa6e675146105075761038e565b806339509351146104a557806339ebf823146104b85780633d68175c146104dc5761038e565b8063238efcbc11610330578063291b6bde1161030a578063291b6bde146104575780632e1a7d4d1461046a578063313ce5671461047d57806336efd16f146104925761038e565b8063238efcbc1461043457806323b872dd1461043c57806326232a2e1461044f5761038e565b806312e8e2c31161036c57806312e8e2c3146103e6578063175188e8146103f957806318160ddd1461040c578063232a3060146104215761038e565b806306fdde0314610393578063095ea7b3146103b15780630c80447a146103d1575b600080fd5b61039b610774565b6040516103a8919061461f565b60405180910390f35b6103c46103bf366004614387565b61080a565b6040516103a891906145fb565b6103e46103df366004614251565b610828565b005b6103e46103f4366004614496565b61086c565b6103e4610407366004614251565b6108e0565b610414610b9d565b6040516103a8919061505b565b6103e461042f366004614251565b610ba3565b6103e4610bf5565b6103c461044a366004614347565b610c75565b610414610cfd565b6103e4610465366004614496565b610d0c565b6103e4610478366004614496565b610d5e565b610485611021565b6040516103a891906150ab565b6103e46104a03660046144c6565b61102b565b6103c46104b3366004614387565b6110b2565b6104cb6104c6366004614251565b611100565b6040516103a8959493929190615088565b61041461112f565b6103e4611139565b610414611259565b6103e4610502366004614251565b611263565b61050f6112f0565b6040516103a89190614522565b61050f6112fa565b6103e4610532366004614251565b611304565b61050f611356565b61041461054d366004614251565b611360565b6103e461056036600461445e565b61137f565b6103e46105733660046142c1565b6113d1565b61050f6114ff565b610414611509565b610414611513565b61041461059e366004614251565b61151d565b6103e46105b136600461445e565b611544565b61039b611596565b6103e46115f7565b6105ce611632565b6040516103a8929190614606565b61050f6105ea366004614496565b611659565b6103c46105fd366004614387565b611680565b6103c4610610366004614387565b6116e8565b6103e4610623366004614496565b6116fc565b61041461176f565b6103e461063e366004614251565b611779565b6103e4610651366004614496565b6117d7565b6103e4610664366004614289565b611837565b6103e4610677366004614496565b611930565b6103e461068a366004614387565b611982565b610697611af6565b6040516103a891906145ae565b6103e46106b2366004614387565b611b57565b6103e46106c5366004614496565b611c5d565b6103e46106d83660046143e6565b611caf565b6104146106eb366004614289565b611dfb565b6103e46106fe366004614496565b611e26565b610414611e9a565b610414611ea4565b610414611eae565b6103e4610729366004614251565b611eb8565b61074161073c366004614251565b611ef0565b6040516103a89190615021565b6103e461075c3660046143b2565b611f50565b6103e461076f366004614496565b612217565b60368054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108005780601f106107d557610100808354040283529160200191610800565b820191906000526020600020905b8154815290600101906020018083116107e357829003601f168201915b5050505050905090565b600061081e61081761228a565b848461228e565b5060015b92915050565b33610831612342565b6001600160a01b0316146108605760405162461bcd60e51b815260040161085790614aa9565b60405180910390fd5b6108698161236d565b50565b33610875612342565b6001600160a01b0316148061089957503361088e612397565b6001600160a01b0316145b6108b55760405162461bcd60e51b8152600401610857906149c9565b6101f48111156108d75760405162461bcd60e51b815260040161085790614b4f565b610869816123c2565b336108e9612342565b6001600160a01b0316148061090d575033610902612397565b6001600160a01b0316145b6109295760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b03811661094f5760405162461bcd60e51b815260040161085790614c0c565b610958816123ec565b6109745760405162461bcd60e51b815260040161085790614891565b6001600160a01b038116600090815260c960205260409020546109a8906109a39061099d612409565b90612434565b61245c565b60006109b2612486565b6001600160a01b038316600090815260c960205260409020600401549091505b60018203811015610a835760ca81600101815481106109ed57fe5b60009182526020909120015460ca80546001600160a01b039092169183908110610a1357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508060c9600060ca8481548110610a5357fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020600401556001016109d2565b5060ca805480610a8f57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038416825260c9905260408120818155600181018290556002810182905560038101829055600401819055610b05908390610af561248c565b6001600160a01b031691906124b7565b816001600160a01b031663219babc26040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b4057600080fd5b505af1158015610b54573d6000803e3d6000fd5b50505050610b6260016125b6565b7f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea482604051610b919190614522565b60405180910390a15050565b60355490565b33610bac612342565b6001600160a01b03161480610bd0575033610bc5612397565b6001600160a01b0316145b610bec5760405162461bcd60e51b8152600401610857906149c9565b610869816125e0565b33610bfe61260a565b6001600160a01b031614610c245760405162461bcd60e51b815260040161085790614b1f565b6000610c2e612342565b9050610c3933612635565b7f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d3382604051610c6a929190614536565b60405180910390a150565b6000610c8284848461265f565b610cf284610c8e61228a565b610ced85604051806060016040528060288152602001615160602891396001600160a01b038a16600090815260346020526040812090610ccc61228a565b6001600160a01b031681526020810191909152604001600020549190612774565b61228e565b5060015b9392505050565b6000610d076127a0565b905090565b33610d15612342565b6001600160a01b03161480610d39575033610d2e612397565b6001600160a01b0316145b610d555760405162461bcd60e51b8152600401610857906149c9565b610869816127cb565b60026065541415610d815760405162461bcd60e51b815260040161085790614f5d565b60026065556000610d90610b9d565b11610dad5760405162461bcd60e51b815260040161085790614a00565b60008111610dcd5760405162461bcd60e51b815260040161085790614d09565b6000610dd8826127f5565b9050610de43383612814565b610dec6128f6565b811115610f74576000610e07610e006128f6565b8390612434565b90506000805b610e15612486565b811015610f5357610e4660ca8281548110610e2c57fe5b6000918252602090912001546001600160a01b03166123ec565b15610f4b576000610e556128f6565b9050600060c9600060ca8581548110610e6a57fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120549150610eb685610eb0610ea0612409565b610eaa8a8761297b565b906129b5565b906129e7565b905060ca8481548110610ec557fe5b600091825260209091200154604051631c37a68760e31b81526001600160a01b039091169063e1bd343890610efe90849060040161505b565b600060405180830381600087803b158015610f1857600080fd5b505af1158015610f2c573d6000803e3d6000fd5b50505050610f45610f3b6128f6565b61099d83866129e7565b94505050505b600101610e0d565b50610f6583610f606128f6565b612a0c565b9250610f7160016125b6565b50505b6000610f8e612710610eaa610f87612a22565b859061297b565b90508015610fc757610fba610fa1612a4d565b82610faa61248c565b6001600160a01b03169190612a78565b610fc48282612434565b91505b610fd43383610faa61248c565b336001600160a01b03167ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568838360405161100f929190615064565b60405180910390a25050600160655550565b6000610d07612a97565b6002606554141561104e5760405162461bcd60e51b815260040161085790614f5d565b600260655561105b612ac2565b156110785760405162461bcd60e51b815260040161085790614864565b6001600160a01b03811661109e5760405162461bcd60e51b815260040161085790614e63565b6110a9823383612aed565b50506001606555565b600061081e6110bf61228a565b84610ced85603460006110d061228a565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906129e7565b60c960205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b6000610d07612c62565b6000611143612486565b116111605760405162461bcd60e51b815260040161085790614795565b33611169612342565b6001600160a01b0316148061118d575033611182612397565b6001600160a01b0316145b806111a757503361119c612c9c565b6001600160a01b0316145b6111c35760405162461bcd60e51b815260040161085790614947565b60006111cd612cc7565b11156111db576111db612cf2565b6111e36130c0565b156111ff576111f260006125b6565b6111fa6130eb565b611207565b611207613492565b611210426136b1565b7f5ba6fd81d2d96e4f83a0035f32fbbc686167312646c8ad6751c80f136c2196c96112396136db565b611241612c62565b60405161124f929190615064565b60405180910390a1565b6000610d076137a2565b600054610100900460ff168061127c575061127c6137cd565b8061128a575060005460ff16155b6112a65760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff161580156112d1576000805460ff1961ff0019909116610100171660011790555b6112da82612635565b80156112ec576000805461ff00191690555b5050565b6000610d07612342565b6000610d07612397565b3361130d612342565b6001600160a01b03161480611331575033611326612397565b6001600160a01b0316145b61134d5760405162461bcd60e51b8152600401610857906149c9565b610869816137de565b6000610d0761248c565b6001600160a01b0381166000908152603360205260409020545b919050565b33611388612342565b6001600160a01b031614806113ac5750336113a1612397565b6001600160a01b0316145b6113c85760405162461bcd60e51b8152600401610857906149c9565b61086981613808565b600054610100900460ff16806113ea57506113ea6137cd565b806113f8575060005460ff16155b6114145760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff1615801561143f576000805460ff1961ff0019909116610100171660011790555b6114498383613832565b6114516138c8565b61145a85611263565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561149557600080fd5b505afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd91906144ea565b905060ff8116600a0a6114e48682848a8080611caf565b505080156114f8576000805461ff00191690555b5050505050565b6000610d07612c9c565b6000610d07613952565b6000610d07612a22565b6000611527610b9d565b6115335750600061137a565b61082261153f83611360565b6127f5565b3361154d612342565b6001600160a01b03161480611571575033611566612397565b6001600160a01b0316145b61158d5760405162461bcd60e51b8152600401610857906149c9565b610869816125b6565b60378054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108005780601f106107d557610100808354040283529160200191610800565b33611600612342565b6001600160a01b0316146116265760405162461bcd60e51b815260040161085790614aa9565b611630600061236d565b565b6000808061163e61397d565b6001600160a01b0316141561165161397d565b915091509091565b60ca818154811061166657fe5b6000918252602090912001546001600160a01b0316905081565b600061081e61168d61228a565b84610ced8560405180606001604052806025815260200161518860259139603460006116b761228a565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612774565b600061081e6116f561228a565b848461265f565b33611705612342565b6001600160a01b0316148061172957503361171e612397565b6001600160a01b0316145b6117455760405162461bcd60e51b8152600401610857906149c9565b60648111156117665760405162461bcd60e51b815260040161085790614b4f565b610869816139a8565b6000610d076139d2565b33611782612342565b6001600160a01b0316146117a85760405162461bcd60e51b815260040161085790614aa9565b6001600160a01b0381166117ce5760405162461bcd60e51b815260040161085790614695565b610869816139fd565b600260655414156117fa5760405162461bcd60e51b815260040161085790614f5d565b6002606555611807612ac2565b156118245760405162461bcd60e51b815260040161085790614864565b61182f813333612aed565b506001606555565b33611840612342565b6001600160a01b0316146118665760405162461bcd60e51b815260040161085790614aa9565b61186e61248c565b6001600160a01b0316826001600160a01b0316141561189f5760405162461bcd60e51b815260040161085790614c8d565b6112ec81836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118cf9190614522565b60206040518083038186803b1580156118e757600080fd5b505afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f91906144ae565b6001600160a01b0385169190612a78565b33611939612342565b6001600160a01b0316148061195d575033611952612397565b6001600160a01b0316145b6119795760405162461bcd60e51b8152600401610857906149c9565b61086981613a27565b3361198b612342565b6001600160a01b031614806119af5750336119a4612397565b6001600160a01b0316145b6119cb5760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b0382166119f15760405162461bcd60e51b815260040161085790614c0c565b6119fa826123ec565b611a165760405162461bcd60e51b815260040161085790614891565b60008111611a365760405162461bcd60e51b81526004016108579061470d565b6001600160a01b038216600090815260c96020526040812054611a61908390610eb09061099d612409565b9050611a6b613a51565b811115611a8a5760405162461bcd60e51b815260040161085790614dd4565b611a938161245c565b6001600160a01b038316600090815260c960205260409020829055611ab860016125b6565b7f3b1b60362a0d5478a841bb1b97188114375be653293f811f21f0ac59b7054a6e8383604051611ae9929190614574565b60405180910390a1505050565b606060ca80548060200260200160405190810160405280929190818152602001828054801561080057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b30575050505050905090565b33611b60612342565b6001600160a01b03161480611b84575033611b79612397565b6001600160a01b0316145b611ba05760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b038216611bc65760405162461bcd60e51b815260040161085790614c0c565b611bcf826123ec565b611beb5760405162461bcd60e51b815260040161085790614891565b6103e8811115611c0d5760405162461bcd60e51b815260040161085790614910565b6001600160a01b038216600090815260c9602052604090819020600101829055517fe028afa225d0a60f63fdea5b8caa828a302266069d50825e0659cead7be0001490610b919084908490614574565b33611c66612342565b6001600160a01b03161480611c8a575033611c7f612397565b6001600160a01b0316145b611ca65760405162461bcd60e51b8152600401610857906149c9565b61086981613a7c565b600054610100900460ff1680611cc85750611cc86137cd565b80611cd6575060005460ff16155b611cf25760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015611d1d576000805460ff1961ff0019909116610100171660011790555b611d2687613aa6565b611d2f86613ad0565b611d3885613afa565b611d41846125e0565b611d4a836137de565b611d5382613b24565b611d5d6000613a27565b611d6760006127cb565b611d716000613a7c565b611d7b6000613b4e565b611d8560006123c2565b611d8f60006139a8565b611d9a612328613b78565b611da4600061245c565b611dae6000613ba2565b611db86000613bcc565b611dc26000613808565b611dcc60006125b6565b611dd660006136b1565b611de0600061236d565b8015611df2576000805461ff00191690555b50505050505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b33611e2f612342565b6001600160a01b03161480611e53575033611e48612397565b6001600160a01b0316145b611e6f5760405162461bcd60e51b8152600401610857906149c9565b6103e8811115611e915760405162461bcd60e51b815260040161085790614b4f565b61086981613b4e565b6000610d076136db565b6000610d07613bf6565b6000610d07613c21565b33611ec1612342565b6001600160a01b031614611ee75760405162461bcd60e51b815260040161085790614aa9565b61086981613b24565b611ef8614111565b506001600160a01b0316600090815260c96020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260038201546060820152600490910154608082015290565b33611f59612342565b6001600160a01b03161480611f7d575033611f72612397565b6001600160a01b0316145b611f995760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b038316611fbf5760405162461bcd60e51b8152600401610857906148d9565b306001600160a01b0316836001600160a01b031663b60d42886040518163ffffffff1660e01b815260040160206040518083038186803b15801561200257600080fd5b505afa158015612016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203a919061426d565b6001600160a01b0316146120605760405162461bcd60e51b815260040161085790614e93565b612069836123ec565b156120865760405162461bcd60e51b815260040161085790614c41565b600082116120a65760405162461bcd60e51b81526004016108579061470d565b60006120b483610eb0612409565b90506120be613a51565b8111156120dd5760405162461bcd60e51b815260040161085790614dd4565b6103e88211156120ff5760405162461bcd60e51b815260040161085790614910565b6001600160a01b038416600090815260c9602052604090208390556121238161245c565b6001600160a01b038416600090815260c9602052604090204260029091015561214a612486565b6001600160a01b038516600081815260c9602052604081206004810193909355600192830185905560ca8054808501825591527f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee10180546001600160a01b03191690911790556121b9906125b6565b6121c7846000610af561248c565b6121d684600019610af561248c565b7f45bb3eed5cd098efb0a286413fb1f3c11841762610cefbabae6a772963e916ba8484846040516122099392919061458d565b60405180910390a150505050565b33612220612342565b6001600160a01b03161480612244575033612239612397565b6001600160a01b0316145b6122605760405162461bcd60e51b8152600401610857906149c9565b61271081106122815760405162461bcd60e51b8152600401610857906146d6565b61086981613b78565b3390565b6001600160a01b0383166122b45760405162461bcd60e51b815260040161085790614e1f565b6001600160a01b0382166122da5760405162461bcd60e51b815260040161085790614753565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061233590859061505b565b60405180910390a3505050565b6000610d077f597f9c7c685b907e823520bd45aeb3d58b505f86b2e41cd5b4cd5b6c72782950613c48565b6108697fa7ae0fa763ec3009113ccc5eb9089e1f0028607f5b8198c52cd42366c1ddb17b82613c4c565b6000610d077f670552e214026020a9e6caa820519c7f879b21bd75b5571387d6a9cf8f94bd18613c48565b6108697f2084059f3bff3cc3fd204df32325dcb05f47c2f590aba5d103ec584523738e7a82613c4c565b6001600160a01b0316600090815260c96020526040902054151590565b6000610d077f63177e03c47ab825f04f5f8f2334e312239890e7588db78cabe10d7aec327fd2613c48565b6000828211156124565760405162461bcd60e51b815260040161085790614992565b50900390565b6108697f63177e03c47ab825f04f5f8f2334e312239890e7588db78cabe10d7aec327fd282613c4c565b60ca5490565b6000610d077fe0dc1d429ff8628e5936b3d6a6546947e1cc9ea7415a59d46ce95b3cfa4442b9613c48565b80158061253f5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906124ed9030908690600401614536565b60206040518083038186803b15801561250557600080fd5b505afa158015612519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253d91906144ae565b155b61255b5760405162461bcd60e51b815260040161085790614f94565b6125b18363095ea7b360e01b848460405160240161257a929190614574565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613c50565b505050565b6108697f7f8e3dfb98485aa419c1d05b6ea089a8cddbafcfcf4491db33f5d0b5fe4f32c782613cdf565b6108697f670552e214026020a9e6caa820519c7f879b21bd75b5571387d6a9cf8f94bd1882613c4c565b6000610d077fcd77091f18f9504fccf6140ab99e20533c811d470bb9a5a983d0edc0720fbf8c613c48565b6108697f597f9c7c685b907e823520bd45aeb3d58b505f86b2e41cd5b4cd5b6c7278295082613c4c565b6001600160a01b0383166126855760405162461bcd60e51b815260040161085790614d8f565b6001600160a01b0382166126ab5760405162461bcd60e51b815260040161085790614652565b6126b68383836125b1565b6126f38160405180606001604052806026815260200161513a602691396001600160a01b0386166000908152603360205260409020549190612774565b6001600160a01b03808516600090815260336020526040808220939093559084168152205461272290826129e7565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061233590859061505b565b600081848411156127985760405162461bcd60e51b8152600401610857919061461f565b505050900390565b6000610d077f2084059f3bff3cc3fd204df32325dcb05f47c2f590aba5d103ec584523738e7a613c48565b6108697f769f312c3790719cf1ea5f75303393f080fd62be88d75fa86726a6be00bb5a2482613c4c565b6000610822612802610b9d565b610eaa8461280e6136db565b9061297b565b6001600160a01b03821661283a5760405162461bcd60e51b815260040161085790614d4e565b612846826000836125b1565b61288381604051806060016040528060228152602001615118602291396001600160a01b0385166000908152603360205260409020549190612774565b6001600160a01b0383166000908152603360205260409020556035546128a99082612434565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906128ea90859061505b565b60405180910390a35050565b600061290061248c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161292b9190614522565b60206040518083038186803b15801561294357600080fd5b505afa158015612957573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0791906144ae565b60008261298a57506000610822565b8282028284828161299757fe5b0414610cf65760405162461bcd60e51b815260040161085790614bcb565b60008082116129d65760405162461bcd60e51b815260040161085790614a72565b8183816129df57fe5b049392505050565b600082820183811015610cf65760405162461bcd60e51b8152600401610857906147cc565b6000818310612a1b5781610cf6565b5090919050565b6000610d077f0fa90db0cd58feef247d70d3b21f64c03d0e3ec10eb297f015da0cc09eb3412c613c48565b6000610d077f92260bfe68dd0f8a9f5439b75466781ba1ce44523ed1a3026a73eada49072e65613c48565b6125b18363a9059cbb60e01b848460405160240161257a929190614574565b6000610d077f15b9fa1072bc4b2cdb762a49a2c7917b8b3af02283e37ffd41d0fccd4eef0d48613c48565b6000610d077f3cefcfe9774096ac956c0d63992ea27a01fb3884a22b8765ad63c8366f90a9c8613cfa565b60008311612b0d5760405162461bcd60e51b815260040161085790614803565b6000612b17613bf6565b1115612b4f57612b25613bf6565b612b3184610eb06136db565b1115612b4f5760405162461bcd60e51b81526004016108579061482d565b6000612b59613952565b1115612b8657612b67613952565b831115612b865760405162461bcd60e51b815260040161085790614cc4565b6000612b90613c21565b1115612bbd57612b9e613c21565b831015612bbd5760405162461bcd60e51b815260040161085790614b86565b6000612bc7610b9d565b15612bee57612be9612bd76136db565b610eaa612be2610b9d565b879061297b565b612bf0565b835b9050612bfc8282613d0e565b612c1b833086612c0a61248c565b6001600160a01b0316929190613dc2565b816001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c85604051612c54919061505b565b60405180910390a250505050565b6000612c6c610b9d565b15612c9457612c8f612c7c610b9d565b610eaa612c876136db565b61280e6137a2565b610d07565b610d076137a2565b6000610d077f84e8c6b8f2281d51d9f683d351409724c3caa7848051aeb9d92c106ab36cc24c613c48565b6000610d077f0260c2bf5555cd32cedf39c0fcb0eab8029c67b3d5137faeb3e24a500db80bc9613c48565b6000805b612cfe612486565b811015612f6857600060ca8281548110612d1457fe5b60009182526020808320909101546001600160a01b031680835260c9825260408084206003015481516322e80f2560e11b815291519295508493909286926345d01e4a926004808301939192829003018186803b158015612d7457600080fd5b505afa158015612d88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dac91906144ae565b1115612f225760c96000846001600160a01b03166001600160a01b0316815260200190815260200160002060030154836001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e1457600080fd5b505afa158015612e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e4c91906144ae565b6001600160a01b038516600090815260c960205260409020600101549190039250612e809061271090610eaa90859061297b565b9050600081118015612e985750612e956128f6565b81105b15612f1157612f11836001600160a01b03166302d05d3f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ed957600080fd5b505afa158015612eed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa1919061426d565b612f1f8161099d87856129e7565b94505b7f20ed094a644ae174b90afe99ef4386dfbd523bfca3ed5e78b3f64c5b2f6c1c04838383604051612f559392919061458d565b60405180910390a1505050600101612cf6565b506000612f7c612710610eaa610f876139d2565b9050600081118015612f945750612f916128f6565b81105b15613021576000612fa3612342565b6001600160a01b0316612fb4612397565b6001600160a01b031614612fcf57612fca612397565b612fd7565b612fd7612a4d565b9050612fe68183610faa61248c565b7f42395da7367895339fd017c34b3884068a0eb6f8f06590e2609ebac28be9b2a98383604051613017929190615064565b60405180910390a1505b60006130556301e18558610eaa612710610eaa61303c6127a0565b613044612cc7565b420361304e613de3565b029061297b565b905060008111801561306d575061306a6128f6565b81105b156125b15761307d610fa1612a4d565b7f283ed0f07b2eecba30acc36ac27e79cfee0e5ab2ad41bc59a964c6012c4babbd6130a6613de3565b6130ae612cc7565b420383604051611ae993929190615072565b6000610d077f7f8e3dfb98485aa419c1d05b6ea089a8cddbafcfcf4491db33f5d0b5fe4f32c7613cfa565b60006130f56136db565b905061310081613ba2565b6000606061310c612486565b67ffffffffffffffff8111801561312257600080fd5b5060405190808252806020026020018201604052801561314c578160200160208202803683370190505b50905060005b61315a612486565b8110156132d757600060ca828154811061317057fe5b60009182526020808320909101546001600160a01b031680835260c990915260408220549092506131aa9061271090610eaa90899061297b565b90506131b685826129e7565b94506000826001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156131f357600080fd5b505afa158015613207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322b91906144ae565b9050818111156132a1576001600160a01b03831663e1bd343861324e8385612434565b6040518263ffffffff1660e01b815260040161326a919061505b565b600060405180830381600087803b15801561328457600080fd5b505af1158015613298573d6000803e3d6000fd5b505050506132cc565b808211156132cc576132b38282612434565b8585815181106132bf57fe5b6020026020010181815250505b505050600101613152565b506132e182613bcc565b60005b6132ec612486565b81101561348c57600060ca828154811061330257fe5b600091825260208220015484516001600160a01b03909116925084908490811061332857fe5b602002602001015111156133a3576133568184848151811061334657fe5b6020026020010151610faa61248c565b7fe96365783ca7db968d526a82902a256e0a72ade94c2632a84f863e222e5d422a8184848151811061338457fe5b602002602001015160405161339a929190614574565b60405180910390a15b806001600160a01b0316634fa5d8546040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156133de57600080fd5b505af11580156133f2573d6000803e3d6000fd5b50505050806001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561342f57600080fd5b505afa158015613443573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346791906144ae565b6001600160a01b03909116600090815260c960205260409020600301556001016132e4565b50505050565b60008061349d613e0e565b116134a95760006134bc565b6134bc6134b4613de3565b61099d613e0e565b90506000816134c96128f6565b116134d55760006134e1565b6134e18261099d6128f6565b9050806134ef575050611630565b6135036134fe82610eb0613e0e565b613ba2565b6000805b61350f612486565b8110156136a757600060ca828154811061352557fe5b60009182526020808320909101546001600160a01b031680835260c9909152604082205490925061355f9061271090610eaa90889061297b565b905080156135ba576135748282610faa61248c565b61357e84826129e7565b93507fe96365783ca7db968d526a82902a256e0a72ade94c2632a84f863e222e5d422a82826040516135b1929190614574565b60405180910390a15b816001600160a01b0316634fa5d8546040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135f557600080fd5b505af1158015613609573d6000803e3d6000fd5b50505050816001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561364657600080fd5b505afa15801561365a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367e91906144ae565b6001600160a01b03909216600090815260c9602052604090206003019190915550600101613507565b506125b181613bcc565b6108697f0260c2bf5555cd32cedf39c0fcb0eab8029c67b3d5137faeb3e24a500db80bc982613c4c565b6000806136e66128f6565b905060005b6136f3612486565b81101561379c5761379260ca828154811061370a57fe5b60009182526020918290200154604080516322e80f2560e11b815290516001600160a01b03909216926345d01e4a92600480840193829003018186803b15801561375357600080fd5b505afa158015613767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378b91906144ae565b83906129e7565b91506001016136eb565b50905090565b6000610d077f4840b03aa097a422092d99dc6875c2b69e8f48c9af2563a0447f3b4e4928d962613c48565b60006137d830613e39565b15905090565b6108697f84e8c6b8f2281d51d9f683d351409724c3caa7848051aeb9d92c106ab36cc24c82613c4c565b6108697f3cefcfe9774096ac956c0d63992ea27a01fb3884a22b8765ad63c8366f90a9c882613cdf565b600054610100900460ff168061384b575061384b6137cd565b80613859575060005460ff16155b6138755760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff161580156138a0576000805460ff1961ff0019909116610100171660011790555b6138a8613e3f565b6138b28383613ec0565b80156125b1576000805461ff0019169055505050565b600054610100900460ff16806138e157506138e16137cd565b806138ef575060005460ff16155b61390b5760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613936576000805460ff1961ff0019909116610100171660011790555b61393e613f79565b8015610869576000805461ff001916905550565b6000610d077f769f312c3790719cf1ea5f75303393f080fd62be88d75fa86726a6be00bb5a24613c48565b6000610d077fa7ae0fa763ec3009113ccc5eb9089e1f0028607f5b8198c52cd42366c1ddb17b613c48565b6108697f0fa90db0cd58feef247d70d3b21f64c03d0e3ec10eb297f015da0cc09eb3412c82613c4c565b6000610d077f5b8979500398f8fbeb42c36d18f31a76fd0ab30f4338d864e7d8734b340e9bb9613c48565b6108697fcd77091f18f9504fccf6140ab99e20533c811d470bb9a5a983d0edc0720fbf8c82613c4c565b6108697fca2f8a3e9ea81335bcce793cde55fc0c38129b594f53052d2bb18099ffa7261382613c4c565b6000610d077fe3b5969c9426551aa8f16dbc7b25042b9b9c9869b759c77a85f0b097ac363475613c48565b6108697f9027949576d185c74d79ad3b8a8dbff32126f3a3ee140b346f146beb18234c8582613c4c565b6108697fe0dc1d429ff8628e5936b3d6a6546947e1cc9ea7415a59d46ce95b3cfa4442b982613c4c565b6108697f4840b03aa097a422092d99dc6875c2b69e8f48c9af2563a0447f3b4e4928d96282613c4c565b6108697f15b9fa1072bc4b2cdb762a49a2c7917b8b3af02283e37ffd41d0fccd4eef0d4882613c4c565b6108697f92260bfe68dd0f8a9f5439b75466781ba1ce44523ed1a3026a73eada49072e6582613c4c565b6108697f5b8979500398f8fbeb42c36d18f31a76fd0ab30f4338d864e7d8734b340e9bb982613c4c565b6108697fe3b5969c9426551aa8f16dbc7b25042b9b9c9869b759c77a85f0b097ac36347582613c4c565b6108697fa19f3b8a62465676ae47ab811ee15e3d2b68d88869cb38686d086a11d382f6bb82613c4c565b6108697f49c84685200b42972f845832b2c3da3d71def653c151340801aeae053ce104e982613c4c565b6000610d077fca2f8a3e9ea81335bcce793cde55fc0c38129b594f53052d2bb18099ffa72613613c48565b6000610d077f9027949576d185c74d79ad3b8a8dbff32126f3a3ee140b346f146beb18234c855b5490565b9055565b6060613ca5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140009092919063ffffffff16565b8051909150156125b15780806020019051810190613cc3919061447a565b6125b15760405162461bcd60e51b815260040161085790614f13565b6112ec8282613cef576000613cf2565b60015b60ff16613c4c565b6000613d0582613c48565b60011492915050565b6001600160a01b038216613d345760405162461bcd60e51b815260040161085790614fea565b613d40600083836125b1565b603554613d4d90826129e7565b6035556001600160a01b038216600090815260336020526040902054613d7390826129e7565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906128ea90859061505b565b61348c846323b872dd60e01b85858560405160240161257a93929190614550565b6000610d077f49c84685200b42972f845832b2c3da3d71def653c151340801aeae053ce104e9613c48565b6000610d077fa19f3b8a62465676ae47ab811ee15e3d2b68d88869cb38686d086a11d382f6bb613c48565b3b151590565b600054610100900460ff1680613e585750613e586137cd565b80613e66575060005460ff16155b613e825760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff1615801561393e576000805460ff1961ff0019909116610100171660011790558015610869576000805461ff001916905550565b600054610100900460ff1680613ed95750613ed96137cd565b80613ee7575060005460ff16155b613f035760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613f2e576000805460ff1961ff0019909116610100171660011790555b8251613f41906036906020860190614140565b508151613f55906037906020850190614140565b506038805460ff1916601217905580156125b1576000805461ff0019169055505050565b600054610100900460ff1680613f925750613f926137cd565b80613fa0575060005460ff16155b613fbc5760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613fe7576000805460ff1961ff0019909116610100171660011790555b60016065558015610869576000805461ff001916905550565b606061400f8484600085614017565b949350505050565b6060824710156140395760405162461bcd60e51b815260040161085790614a2c565b61404285613e39565b61405e5760405162461bcd60e51b815260040161085790614edc565b60006060866001600160a01b0316858760405161407b9190614506565b60006040518083038185875af1925050503d80600081146140b8576040519150601f19603f3d011682016040523d82523d6000602084013e6140bd565b606091505b50915091506140cd8282866140d8565b979650505050505050565b606083156140e7575081610cf6565b8251156140f75782518084602001fd5b8160405162461bcd60e51b8152600401610857919061461f565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061418157805160ff19168380011785556141ae565b828001600101855582156141ae579182015b828111156141ae578251825591602001919060010190614193565b506141ba9291506141be565b5090565b5b808211156141ba57600081556001016141bf565b600082601f8301126141e3578081fd5b813567ffffffffffffffff808211156141fa578283fd5b604051601f8301601f19168101602001828111828210171561421a578485fd5b60405282815292508284830160200186101561423557600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215614262578081fd5b8135610cf6816150e5565b60006020828403121561427e578081fd5b8151610cf6816150e5565b6000806040838503121561429b578081fd5b82356142a6816150e5565b915060208301356142b6816150e5565b809150509250929050565b600080600080608085870312156142d6578182fd5b84356142e1816150e5565b935060208501356142f1816150e5565b9250604085013567ffffffffffffffff8082111561430d578384fd5b614319888389016141d3565b9350606087013591508082111561432e578283fd5b5061433b878288016141d3565b91505092959194509250565b60008060006060848603121561435b578283fd5b8335614366816150e5565b92506020840135614376816150e5565b929592945050506040919091013590565b60008060408385031215614399578182fd5b82356143a4816150e5565b946020939093013593505050565b6000806000606084860312156143c6578283fd5b83356143d1816150e5565b95602085013595506040909401359392505050565b60008060008060008060c087890312156143fe578182fd5b8635614409816150e5565b955060208701359450604087013561442081615108565b93506060870135614430816150e5565b92506080870135614440816150e5565b915060a0870135614450816150e5565b809150509295509295509295565b60006020828403121561446f578081fd5b8135610cf6816150fa565b60006020828403121561448b578081fd5b8151610cf6816150fa565b6000602082840312156144a7578081fd5b5035919050565b6000602082840312156144bf578081fd5b5051919050565b600080604083850312156144d8578182fd5b8235915060208301356142b6816150e5565b6000602082840312156144fb578081fd5b8151610cf681615108565b600082516145188184602087016150b9565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6020808252825182820181905260009190848201906040850190845b818110156145ef5783516001600160a01b0316835292840192918401916001016145ca565b50909695505050505050565b901515815260200190565b91151582526001600160a01b0316602082015260400190565b600060208252825180602084015261463e8160408501602087016150b9565b601f01601f19169190910160400192915050565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526021908201527f6e657720676f7665726e616e63652073686f756c646e277420626520656d70746040820152607960f81b606082015260800190565b60208082526017908201527f56616c75652067726561746572207468616e2031303025000000000000000000604082015260600190565b60208082526026908201527f546865207765696768746167652073686f756c6420626520677265617465722060408201526507468616e20360d41b606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b6020808252601a908201527f53747261746567696573206d75737420626520646566696e6564000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526010908201526f043616e6e6f74206465706f73697420360841b604082015260600190565b60208082526017908201527f546f74616c206465706f736974206c696d697420686974000000000000000000604082015260600190565b60208082526013908201527211195c1bdcda5d1cc8185c99481c185d5cd959606a1b604082015260600190565b60208082526028908201527f54686973207374726174656779206973206e6f742061637469766520696e20746040820152671a1a5cc8199d5b9960c21b606082015260800190565b6020808252601f908201527f6e6577206e657753747261746567792063616e6e6f7420626520656d70747900604082015260600190565b60208082526018908201527f506572666f726d616e63652066656520746f6f20686967680000000000000000604082015260600190565b6020808252602b908201527f4e6f7420676f7665726e616e6365206e6f722066756e64206d616e616765722060408201526a3737b9103932b630bcb2b960a91b606082015260800190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252601f908201527f4e6f7420676f7665726e616e6365206e6f722066756e64206d616e6167657200604082015260600190565b60208082526012908201527146756e6420686173206e6f2073686172657360701b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600e908201526d4e6f7420676f7665726e616e636560901b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601690820152754e6f742070656e64696e6720676f7665726e616e636560501b604082015260600190565b6020808252601a908201527f4665652067726561746572207468616e206d6178206c696d6974000000000000604082015260600190565b60208082526025908201527f4d696e696d756d207472616e73616374696f6e206465706f736974206c696d696040820152641d081a1a5d60da1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252818101527f63757272656e742073747261746567792063616e6e6f7420626520656d707479604082015260600190565b6020808252602c908201527f5468697320737472617465677920697320616c7265616479206163746976652060408201526b1a5b881d1a1a5cc8199d5b9960a21b606082015260800190565b60208082526018908201527f63616e206e6f7420737765657020756e6465726c79696e670000000000000000604082015260600190565b60208082526025908201527f4d6178696d756d207472616e73616374696f6e206465706f736974206c696d696040820152641d081a1a5d60da1b606082015260800190565b60208082526025908201527f6e756d6265724f66536861726573206d75737420626520677265617465722074604082015264068616e20360dc1b606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602b908201527f546f74616c20696e766573746d656e742063616e27742062652061626f76652060408201526a1b585e08185b1b1bddd95960aa1b606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b6020808252601690820152751a1bdb19195c881b5d5cdd081899481919599a5b995960521b604082015260600190565b60208082526029908201527f54686520737472617465677920646f6573206e6f742062656c6f6e6720746f206040820152681d1a1a5cc8199d5b9960ba1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60ff91909116815260200190565b60005b838110156150d45781810151838201526020016150bc565b8381111561348c5750506000910152565b6001600160a01b038116811461086957600080fd5b801515811461086957600080fd5b60ff8116811461086957600080fdfe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220a9bcec6584b2926afeb4008d85fee0869e6baff6263d0884e773eacb9071476a64736f6c634300060c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80638bc7e8c4116101de578063bdc8144b1161010f578063eb6a0005116100ad578063f47994251161007c578063f47994251461071b578063f8806a131461072e578063fa34d6111461074e578063fc84c390146107615761038e565b8063eb6a0005146106f0578063ec18154e14610703578063ecf708581461070b578063f05f50c1146107135761038e565b8063d0194ed6116100e9578063d0194ed6146106a4578063d7cd647a146106b7578063d7fbc7b8146106ca578063dd62ed3e146106dd5761038e565b8063bdc8144b14610669578063cc8432df1461067c578063cdc39b0a1461068f5761038e565b8063a457c2d71161017c578063b161dd4e11610156578063b161dd4e14610628578063b256126314610630578063b6b55f2514610643578063b8dc491b146106565761038e565b8063a457c2d7146105ef578063a9059cbb14610602578063ac1e5025146106155761038e565b806395d89b41116101b857806395d89b41146105b65780639a508c8e146105be5780639d16acfd146105c6578063a267526b146105dc5761038e565b80638bc7e8c4146105885780638cb1d67f146105905780638e2d2a2d146105a35761038e565b806339509351116102c35780636209ec2d11610261578063738b62e511610230578063738b62e51461055257806374a00f8e146105655780638406c079146105785780638a2320ba146105805761038e565b80636209ec2d1461051c5780636548e9bc146105245780636f307dc31461053757806370a082311461053f5761038e565b80634fa5d8541161029d5780634fa5d854146104e457806353ceb01c146104ec57806355d202a6146104f45780635aa6e675146105075761038e565b806339509351146104a557806339ebf823146104b85780633d68175c146104dc5761038e565b8063238efcbc11610330578063291b6bde1161030a578063291b6bde146104575780632e1a7d4d1461046a578063313ce5671461047d57806336efd16f146104925761038e565b8063238efcbc1461043457806323b872dd1461043c57806326232a2e1461044f5761038e565b806312e8e2c31161036c57806312e8e2c3146103e6578063175188e8146103f957806318160ddd1461040c578063232a3060146104215761038e565b806306fdde0314610393578063095ea7b3146103b15780630c80447a146103d1575b600080fd5b61039b610774565b6040516103a8919061461f565b60405180910390f35b6103c46103bf366004614387565b61080a565b6040516103a891906145fb565b6103e46103df366004614251565b610828565b005b6103e46103f4366004614496565b61086c565b6103e4610407366004614251565b6108e0565b610414610b9d565b6040516103a8919061505b565b6103e461042f366004614251565b610ba3565b6103e4610bf5565b6103c461044a366004614347565b610c75565b610414610cfd565b6103e4610465366004614496565b610d0c565b6103e4610478366004614496565b610d5e565b610485611021565b6040516103a891906150ab565b6103e46104a03660046144c6565b61102b565b6103c46104b3366004614387565b6110b2565b6104cb6104c6366004614251565b611100565b6040516103a8959493929190615088565b61041461112f565b6103e4611139565b610414611259565b6103e4610502366004614251565b611263565b61050f6112f0565b6040516103a89190614522565b61050f6112fa565b6103e4610532366004614251565b611304565b61050f611356565b61041461054d366004614251565b611360565b6103e461056036600461445e565b61137f565b6103e46105733660046142c1565b6113d1565b61050f6114ff565b610414611509565b610414611513565b61041461059e366004614251565b61151d565b6103e46105b136600461445e565b611544565b61039b611596565b6103e46115f7565b6105ce611632565b6040516103a8929190614606565b61050f6105ea366004614496565b611659565b6103c46105fd366004614387565b611680565b6103c4610610366004614387565b6116e8565b6103e4610623366004614496565b6116fc565b61041461176f565b6103e461063e366004614251565b611779565b6103e4610651366004614496565b6117d7565b6103e4610664366004614289565b611837565b6103e4610677366004614496565b611930565b6103e461068a366004614387565b611982565b610697611af6565b6040516103a891906145ae565b6103e46106b2366004614387565b611b57565b6103e46106c5366004614496565b611c5d565b6103e46106d83660046143e6565b611caf565b6104146106eb366004614289565b611dfb565b6103e46106fe366004614496565b611e26565b610414611e9a565b610414611ea4565b610414611eae565b6103e4610729366004614251565b611eb8565b61074161073c366004614251565b611ef0565b6040516103a89190615021565b6103e461075c3660046143b2565b611f50565b6103e461076f366004614496565b612217565b60368054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108005780601f106107d557610100808354040283529160200191610800565b820191906000526020600020905b8154815290600101906020018083116107e357829003601f168201915b5050505050905090565b600061081e61081761228a565b848461228e565b5060015b92915050565b33610831612342565b6001600160a01b0316146108605760405162461bcd60e51b815260040161085790614aa9565b60405180910390fd5b6108698161236d565b50565b33610875612342565b6001600160a01b0316148061089957503361088e612397565b6001600160a01b0316145b6108b55760405162461bcd60e51b8152600401610857906149c9565b6101f48111156108d75760405162461bcd60e51b815260040161085790614b4f565b610869816123c2565b336108e9612342565b6001600160a01b0316148061090d575033610902612397565b6001600160a01b0316145b6109295760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b03811661094f5760405162461bcd60e51b815260040161085790614c0c565b610958816123ec565b6109745760405162461bcd60e51b815260040161085790614891565b6001600160a01b038116600090815260c960205260409020546109a8906109a39061099d612409565b90612434565b61245c565b60006109b2612486565b6001600160a01b038316600090815260c960205260409020600401549091505b60018203811015610a835760ca81600101815481106109ed57fe5b60009182526020909120015460ca80546001600160a01b039092169183908110610a1357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508060c9600060ca8481548110610a5357fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020600401556001016109d2565b5060ca805480610a8f57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038416825260c9905260408120818155600181018290556002810182905560038101829055600401819055610b05908390610af561248c565b6001600160a01b031691906124b7565b816001600160a01b031663219babc26040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b4057600080fd5b505af1158015610b54573d6000803e3d6000fd5b50505050610b6260016125b6565b7f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea482604051610b919190614522565b60405180910390a15050565b60355490565b33610bac612342565b6001600160a01b03161480610bd0575033610bc5612397565b6001600160a01b0316145b610bec5760405162461bcd60e51b8152600401610857906149c9565b610869816125e0565b33610bfe61260a565b6001600160a01b031614610c245760405162461bcd60e51b815260040161085790614b1f565b6000610c2e612342565b9050610c3933612635565b7f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d3382604051610c6a929190614536565b60405180910390a150565b6000610c8284848461265f565b610cf284610c8e61228a565b610ced85604051806060016040528060288152602001615160602891396001600160a01b038a16600090815260346020526040812090610ccc61228a565b6001600160a01b031681526020810191909152604001600020549190612774565b61228e565b5060015b9392505050565b6000610d076127a0565b905090565b33610d15612342565b6001600160a01b03161480610d39575033610d2e612397565b6001600160a01b0316145b610d555760405162461bcd60e51b8152600401610857906149c9565b610869816127cb565b60026065541415610d815760405162461bcd60e51b815260040161085790614f5d565b60026065556000610d90610b9d565b11610dad5760405162461bcd60e51b815260040161085790614a00565b60008111610dcd5760405162461bcd60e51b815260040161085790614d09565b6000610dd8826127f5565b9050610de43383612814565b610dec6128f6565b811115610f74576000610e07610e006128f6565b8390612434565b90506000805b610e15612486565b811015610f5357610e4660ca8281548110610e2c57fe5b6000918252602090912001546001600160a01b03166123ec565b15610f4b576000610e556128f6565b9050600060c9600060ca8581548110610e6a57fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120549150610eb685610eb0610ea0612409565b610eaa8a8761297b565b906129b5565b906129e7565b905060ca8481548110610ec557fe5b600091825260209091200154604051631c37a68760e31b81526001600160a01b039091169063e1bd343890610efe90849060040161505b565b600060405180830381600087803b158015610f1857600080fd5b505af1158015610f2c573d6000803e3d6000fd5b50505050610f45610f3b6128f6565b61099d83866129e7565b94505050505b600101610e0d565b50610f6583610f606128f6565b612a0c565b9250610f7160016125b6565b50505b6000610f8e612710610eaa610f87612a22565b859061297b565b90508015610fc757610fba610fa1612a4d565b82610faa61248c565b6001600160a01b03169190612a78565b610fc48282612434565b91505b610fd43383610faa61248c565b336001600160a01b03167ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568838360405161100f929190615064565b60405180910390a25050600160655550565b6000610d07612a97565b6002606554141561104e5760405162461bcd60e51b815260040161085790614f5d565b600260655561105b612ac2565b156110785760405162461bcd60e51b815260040161085790614864565b6001600160a01b03811661109e5760405162461bcd60e51b815260040161085790614e63565b6110a9823383612aed565b50506001606555565b600061081e6110bf61228a565b84610ced85603460006110d061228a565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906129e7565b60c960205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b6000610d07612c62565b6000611143612486565b116111605760405162461bcd60e51b815260040161085790614795565b33611169612342565b6001600160a01b0316148061118d575033611182612397565b6001600160a01b0316145b806111a757503361119c612c9c565b6001600160a01b0316145b6111c35760405162461bcd60e51b815260040161085790614947565b60006111cd612cc7565b11156111db576111db612cf2565b6111e36130c0565b156111ff576111f260006125b6565b6111fa6130eb565b611207565b611207613492565b611210426136b1565b7f5ba6fd81d2d96e4f83a0035f32fbbc686167312646c8ad6751c80f136c2196c96112396136db565b611241612c62565b60405161124f929190615064565b60405180910390a1565b6000610d076137a2565b600054610100900460ff168061127c575061127c6137cd565b8061128a575060005460ff16155b6112a65760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff161580156112d1576000805460ff1961ff0019909116610100171660011790555b6112da82612635565b80156112ec576000805461ff00191690555b5050565b6000610d07612342565b6000610d07612397565b3361130d612342565b6001600160a01b03161480611331575033611326612397565b6001600160a01b0316145b61134d5760405162461bcd60e51b8152600401610857906149c9565b610869816137de565b6000610d0761248c565b6001600160a01b0381166000908152603360205260409020545b919050565b33611388612342565b6001600160a01b031614806113ac5750336113a1612397565b6001600160a01b0316145b6113c85760405162461bcd60e51b8152600401610857906149c9565b61086981613808565b600054610100900460ff16806113ea57506113ea6137cd565b806113f8575060005460ff16155b6114145760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff1615801561143f576000805460ff1961ff0019909116610100171660011790555b6114498383613832565b6114516138c8565b61145a85611263565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561149557600080fd5b505afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd91906144ea565b905060ff8116600a0a6114e48682848a8080611caf565b505080156114f8576000805461ff00191690555b5050505050565b6000610d07612c9c565b6000610d07613952565b6000610d07612a22565b6000611527610b9d565b6115335750600061137a565b61082261153f83611360565b6127f5565b3361154d612342565b6001600160a01b03161480611571575033611566612397565b6001600160a01b0316145b61158d5760405162461bcd60e51b8152600401610857906149c9565b610869816125b6565b60378054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108005780601f106107d557610100808354040283529160200191610800565b33611600612342565b6001600160a01b0316146116265760405162461bcd60e51b815260040161085790614aa9565b611630600061236d565b565b6000808061163e61397d565b6001600160a01b0316141561165161397d565b915091509091565b60ca818154811061166657fe5b6000918252602090912001546001600160a01b0316905081565b600061081e61168d61228a565b84610ced8560405180606001604052806025815260200161518860259139603460006116b761228a565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612774565b600061081e6116f561228a565b848461265f565b33611705612342565b6001600160a01b0316148061172957503361171e612397565b6001600160a01b0316145b6117455760405162461bcd60e51b8152600401610857906149c9565b60648111156117665760405162461bcd60e51b815260040161085790614b4f565b610869816139a8565b6000610d076139d2565b33611782612342565b6001600160a01b0316146117a85760405162461bcd60e51b815260040161085790614aa9565b6001600160a01b0381166117ce5760405162461bcd60e51b815260040161085790614695565b610869816139fd565b600260655414156117fa5760405162461bcd60e51b815260040161085790614f5d565b6002606555611807612ac2565b156118245760405162461bcd60e51b815260040161085790614864565b61182f813333612aed565b506001606555565b33611840612342565b6001600160a01b0316146118665760405162461bcd60e51b815260040161085790614aa9565b61186e61248c565b6001600160a01b0316826001600160a01b0316141561189f5760405162461bcd60e51b815260040161085790614c8d565b6112ec81836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118cf9190614522565b60206040518083038186803b1580156118e757600080fd5b505afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f91906144ae565b6001600160a01b0385169190612a78565b33611939612342565b6001600160a01b0316148061195d575033611952612397565b6001600160a01b0316145b6119795760405162461bcd60e51b8152600401610857906149c9565b61086981613a27565b3361198b612342565b6001600160a01b031614806119af5750336119a4612397565b6001600160a01b0316145b6119cb5760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b0382166119f15760405162461bcd60e51b815260040161085790614c0c565b6119fa826123ec565b611a165760405162461bcd60e51b815260040161085790614891565b60008111611a365760405162461bcd60e51b81526004016108579061470d565b6001600160a01b038216600090815260c96020526040812054611a61908390610eb09061099d612409565b9050611a6b613a51565b811115611a8a5760405162461bcd60e51b815260040161085790614dd4565b611a938161245c565b6001600160a01b038316600090815260c960205260409020829055611ab860016125b6565b7f3b1b60362a0d5478a841bb1b97188114375be653293f811f21f0ac59b7054a6e8383604051611ae9929190614574565b60405180910390a1505050565b606060ca80548060200260200160405190810160405280929190818152602001828054801561080057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b30575050505050905090565b33611b60612342565b6001600160a01b03161480611b84575033611b79612397565b6001600160a01b0316145b611ba05760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b038216611bc65760405162461bcd60e51b815260040161085790614c0c565b611bcf826123ec565b611beb5760405162461bcd60e51b815260040161085790614891565b6103e8811115611c0d5760405162461bcd60e51b815260040161085790614910565b6001600160a01b038216600090815260c9602052604090819020600101829055517fe028afa225d0a60f63fdea5b8caa828a302266069d50825e0659cead7be0001490610b919084908490614574565b33611c66612342565b6001600160a01b03161480611c8a575033611c7f612397565b6001600160a01b0316145b611ca65760405162461bcd60e51b8152600401610857906149c9565b61086981613a7c565b600054610100900460ff1680611cc85750611cc86137cd565b80611cd6575060005460ff16155b611cf25760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015611d1d576000805460ff1961ff0019909116610100171660011790555b611d2687613aa6565b611d2f86613ad0565b611d3885613afa565b611d41846125e0565b611d4a836137de565b611d5382613b24565b611d5d6000613a27565b611d6760006127cb565b611d716000613a7c565b611d7b6000613b4e565b611d8560006123c2565b611d8f60006139a8565b611d9a612328613b78565b611da4600061245c565b611dae6000613ba2565b611db86000613bcc565b611dc26000613808565b611dcc60006125b6565b611dd660006136b1565b611de0600061236d565b8015611df2576000805461ff00191690555b50505050505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b33611e2f612342565b6001600160a01b03161480611e53575033611e48612397565b6001600160a01b0316145b611e6f5760405162461bcd60e51b8152600401610857906149c9565b6103e8811115611e915760405162461bcd60e51b815260040161085790614b4f565b61086981613b4e565b6000610d076136db565b6000610d07613bf6565b6000610d07613c21565b33611ec1612342565b6001600160a01b031614611ee75760405162461bcd60e51b815260040161085790614aa9565b61086981613b24565b611ef8614111565b506001600160a01b0316600090815260c96020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260038201546060820152600490910154608082015290565b33611f59612342565b6001600160a01b03161480611f7d575033611f72612397565b6001600160a01b0316145b611f995760405162461bcd60e51b8152600401610857906149c9565b6001600160a01b038316611fbf5760405162461bcd60e51b8152600401610857906148d9565b306001600160a01b0316836001600160a01b031663b60d42886040518163ffffffff1660e01b815260040160206040518083038186803b15801561200257600080fd5b505afa158015612016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203a919061426d565b6001600160a01b0316146120605760405162461bcd60e51b815260040161085790614e93565b612069836123ec565b156120865760405162461bcd60e51b815260040161085790614c41565b600082116120a65760405162461bcd60e51b81526004016108579061470d565b60006120b483610eb0612409565b90506120be613a51565b8111156120dd5760405162461bcd60e51b815260040161085790614dd4565b6103e88211156120ff5760405162461bcd60e51b815260040161085790614910565b6001600160a01b038416600090815260c9602052604090208390556121238161245c565b6001600160a01b038416600090815260c9602052604090204260029091015561214a612486565b6001600160a01b038516600081815260c9602052604081206004810193909355600192830185905560ca8054808501825591527f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee10180546001600160a01b03191690911790556121b9906125b6565b6121c7846000610af561248c565b6121d684600019610af561248c565b7f45bb3eed5cd098efb0a286413fb1f3c11841762610cefbabae6a772963e916ba8484846040516122099392919061458d565b60405180910390a150505050565b33612220612342565b6001600160a01b03161480612244575033612239612397565b6001600160a01b0316145b6122605760405162461bcd60e51b8152600401610857906149c9565b61271081106122815760405162461bcd60e51b8152600401610857906146d6565b61086981613b78565b3390565b6001600160a01b0383166122b45760405162461bcd60e51b815260040161085790614e1f565b6001600160a01b0382166122da5760405162461bcd60e51b815260040161085790614753565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061233590859061505b565b60405180910390a3505050565b6000610d077f597f9c7c685b907e823520bd45aeb3d58b505f86b2e41cd5b4cd5b6c72782950613c48565b6108697fa7ae0fa763ec3009113ccc5eb9089e1f0028607f5b8198c52cd42366c1ddb17b82613c4c565b6000610d077f670552e214026020a9e6caa820519c7f879b21bd75b5571387d6a9cf8f94bd18613c48565b6108697f2084059f3bff3cc3fd204df32325dcb05f47c2f590aba5d103ec584523738e7a82613c4c565b6001600160a01b0316600090815260c96020526040902054151590565b6000610d077f63177e03c47ab825f04f5f8f2334e312239890e7588db78cabe10d7aec327fd2613c48565b6000828211156124565760405162461bcd60e51b815260040161085790614992565b50900390565b6108697f63177e03c47ab825f04f5f8f2334e312239890e7588db78cabe10d7aec327fd282613c4c565b60ca5490565b6000610d077fe0dc1d429ff8628e5936b3d6a6546947e1cc9ea7415a59d46ce95b3cfa4442b9613c48565b80158061253f5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906124ed9030908690600401614536565b60206040518083038186803b15801561250557600080fd5b505afa158015612519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253d91906144ae565b155b61255b5760405162461bcd60e51b815260040161085790614f94565b6125b18363095ea7b360e01b848460405160240161257a929190614574565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613c50565b505050565b6108697f7f8e3dfb98485aa419c1d05b6ea089a8cddbafcfcf4491db33f5d0b5fe4f32c782613cdf565b6108697f670552e214026020a9e6caa820519c7f879b21bd75b5571387d6a9cf8f94bd1882613c4c565b6000610d077fcd77091f18f9504fccf6140ab99e20533c811d470bb9a5a983d0edc0720fbf8c613c48565b6108697f597f9c7c685b907e823520bd45aeb3d58b505f86b2e41cd5b4cd5b6c7278295082613c4c565b6001600160a01b0383166126855760405162461bcd60e51b815260040161085790614d8f565b6001600160a01b0382166126ab5760405162461bcd60e51b815260040161085790614652565b6126b68383836125b1565b6126f38160405180606001604052806026815260200161513a602691396001600160a01b0386166000908152603360205260409020549190612774565b6001600160a01b03808516600090815260336020526040808220939093559084168152205461272290826129e7565b6001600160a01b0380841660008181526033602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061233590859061505b565b600081848411156127985760405162461bcd60e51b8152600401610857919061461f565b505050900390565b6000610d077f2084059f3bff3cc3fd204df32325dcb05f47c2f590aba5d103ec584523738e7a613c48565b6108697f769f312c3790719cf1ea5f75303393f080fd62be88d75fa86726a6be00bb5a2482613c4c565b6000610822612802610b9d565b610eaa8461280e6136db565b9061297b565b6001600160a01b03821661283a5760405162461bcd60e51b815260040161085790614d4e565b612846826000836125b1565b61288381604051806060016040528060228152602001615118602291396001600160a01b0385166000908152603360205260409020549190612774565b6001600160a01b0383166000908152603360205260409020556035546128a99082612434565b6035556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906128ea90859061505b565b60405180910390a35050565b600061290061248c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161292b9190614522565b60206040518083038186803b15801561294357600080fd5b505afa158015612957573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0791906144ae565b60008261298a57506000610822565b8282028284828161299757fe5b0414610cf65760405162461bcd60e51b815260040161085790614bcb565b60008082116129d65760405162461bcd60e51b815260040161085790614a72565b8183816129df57fe5b049392505050565b600082820183811015610cf65760405162461bcd60e51b8152600401610857906147cc565b6000818310612a1b5781610cf6565b5090919050565b6000610d077f0fa90db0cd58feef247d70d3b21f64c03d0e3ec10eb297f015da0cc09eb3412c613c48565b6000610d077f92260bfe68dd0f8a9f5439b75466781ba1ce44523ed1a3026a73eada49072e65613c48565b6125b18363a9059cbb60e01b848460405160240161257a929190614574565b6000610d077f15b9fa1072bc4b2cdb762a49a2c7917b8b3af02283e37ffd41d0fccd4eef0d48613c48565b6000610d077f3cefcfe9774096ac956c0d63992ea27a01fb3884a22b8765ad63c8366f90a9c8613cfa565b60008311612b0d5760405162461bcd60e51b815260040161085790614803565b6000612b17613bf6565b1115612b4f57612b25613bf6565b612b3184610eb06136db565b1115612b4f5760405162461bcd60e51b81526004016108579061482d565b6000612b59613952565b1115612b8657612b67613952565b831115612b865760405162461bcd60e51b815260040161085790614cc4565b6000612b90613c21565b1115612bbd57612b9e613c21565b831015612bbd5760405162461bcd60e51b815260040161085790614b86565b6000612bc7610b9d565b15612bee57612be9612bd76136db565b610eaa612be2610b9d565b879061297b565b612bf0565b835b9050612bfc8282613d0e565b612c1b833086612c0a61248c565b6001600160a01b0316929190613dc2565b816001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c85604051612c54919061505b565b60405180910390a250505050565b6000612c6c610b9d565b15612c9457612c8f612c7c610b9d565b610eaa612c876136db565b61280e6137a2565b610d07565b610d076137a2565b6000610d077f84e8c6b8f2281d51d9f683d351409724c3caa7848051aeb9d92c106ab36cc24c613c48565b6000610d077f0260c2bf5555cd32cedf39c0fcb0eab8029c67b3d5137faeb3e24a500db80bc9613c48565b6000805b612cfe612486565b811015612f6857600060ca8281548110612d1457fe5b60009182526020808320909101546001600160a01b031680835260c9825260408084206003015481516322e80f2560e11b815291519295508493909286926345d01e4a926004808301939192829003018186803b158015612d7457600080fd5b505afa158015612d88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dac91906144ae565b1115612f225760c96000846001600160a01b03166001600160a01b0316815260200190815260200160002060030154836001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e1457600080fd5b505afa158015612e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e4c91906144ae565b6001600160a01b038516600090815260c960205260409020600101549190039250612e809061271090610eaa90859061297b565b9050600081118015612e985750612e956128f6565b81105b15612f1157612f11836001600160a01b03166302d05d3f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ed957600080fd5b505afa158015612eed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa1919061426d565b612f1f8161099d87856129e7565b94505b7f20ed094a644ae174b90afe99ef4386dfbd523bfca3ed5e78b3f64c5b2f6c1c04838383604051612f559392919061458d565b60405180910390a1505050600101612cf6565b506000612f7c612710610eaa610f876139d2565b9050600081118015612f945750612f916128f6565b81105b15613021576000612fa3612342565b6001600160a01b0316612fb4612397565b6001600160a01b031614612fcf57612fca612397565b612fd7565b612fd7612a4d565b9050612fe68183610faa61248c565b7f42395da7367895339fd017c34b3884068a0eb6f8f06590e2609ebac28be9b2a98383604051613017929190615064565b60405180910390a1505b60006130556301e18558610eaa612710610eaa61303c6127a0565b613044612cc7565b420361304e613de3565b029061297b565b905060008111801561306d575061306a6128f6565b81105b156125b15761307d610fa1612a4d565b7f283ed0f07b2eecba30acc36ac27e79cfee0e5ab2ad41bc59a964c6012c4babbd6130a6613de3565b6130ae612cc7565b420383604051611ae993929190615072565b6000610d077f7f8e3dfb98485aa419c1d05b6ea089a8cddbafcfcf4491db33f5d0b5fe4f32c7613cfa565b60006130f56136db565b905061310081613ba2565b6000606061310c612486565b67ffffffffffffffff8111801561312257600080fd5b5060405190808252806020026020018201604052801561314c578160200160208202803683370190505b50905060005b61315a612486565b8110156132d757600060ca828154811061317057fe5b60009182526020808320909101546001600160a01b031680835260c990915260408220549092506131aa9061271090610eaa90899061297b565b90506131b685826129e7565b94506000826001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156131f357600080fd5b505afa158015613207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322b91906144ae565b9050818111156132a1576001600160a01b03831663e1bd343861324e8385612434565b6040518263ffffffff1660e01b815260040161326a919061505b565b600060405180830381600087803b15801561328457600080fd5b505af1158015613298573d6000803e3d6000fd5b505050506132cc565b808211156132cc576132b38282612434565b8585815181106132bf57fe5b6020026020010181815250505b505050600101613152565b506132e182613bcc565b60005b6132ec612486565b81101561348c57600060ca828154811061330257fe5b600091825260208220015484516001600160a01b03909116925084908490811061332857fe5b602002602001015111156133a3576133568184848151811061334657fe5b6020026020010151610faa61248c565b7fe96365783ca7db968d526a82902a256e0a72ade94c2632a84f863e222e5d422a8184848151811061338457fe5b602002602001015160405161339a929190614574565b60405180910390a15b806001600160a01b0316634fa5d8546040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156133de57600080fd5b505af11580156133f2573d6000803e3d6000fd5b50505050806001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561342f57600080fd5b505afa158015613443573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346791906144ae565b6001600160a01b03909116600090815260c960205260409020600301556001016132e4565b50505050565b60008061349d613e0e565b116134a95760006134bc565b6134bc6134b4613de3565b61099d613e0e565b90506000816134c96128f6565b116134d55760006134e1565b6134e18261099d6128f6565b9050806134ef575050611630565b6135036134fe82610eb0613e0e565b613ba2565b6000805b61350f612486565b8110156136a757600060ca828154811061352557fe5b60009182526020808320909101546001600160a01b031680835260c9909152604082205490925061355f9061271090610eaa90889061297b565b905080156135ba576135748282610faa61248c565b61357e84826129e7565b93507fe96365783ca7db968d526a82902a256e0a72ade94c2632a84f863e222e5d422a82826040516135b1929190614574565b60405180910390a15b816001600160a01b0316634fa5d8546040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135f557600080fd5b505af1158015613609573d6000803e3d6000fd5b50505050816001600160a01b03166345d01e4a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561364657600080fd5b505afa15801561365a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367e91906144ae565b6001600160a01b03909216600090815260c9602052604090206003019190915550600101613507565b506125b181613bcc565b6108697f0260c2bf5555cd32cedf39c0fcb0eab8029c67b3d5137faeb3e24a500db80bc982613c4c565b6000806136e66128f6565b905060005b6136f3612486565b81101561379c5761379260ca828154811061370a57fe5b60009182526020918290200154604080516322e80f2560e11b815290516001600160a01b03909216926345d01e4a92600480840193829003018186803b15801561375357600080fd5b505afa158015613767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378b91906144ae565b83906129e7565b91506001016136eb565b50905090565b6000610d077f4840b03aa097a422092d99dc6875c2b69e8f48c9af2563a0447f3b4e4928d962613c48565b60006137d830613e39565b15905090565b6108697f84e8c6b8f2281d51d9f683d351409724c3caa7848051aeb9d92c106ab36cc24c82613c4c565b6108697f3cefcfe9774096ac956c0d63992ea27a01fb3884a22b8765ad63c8366f90a9c882613cdf565b600054610100900460ff168061384b575061384b6137cd565b80613859575060005460ff16155b6138755760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff161580156138a0576000805460ff1961ff0019909116610100171660011790555b6138a8613e3f565b6138b28383613ec0565b80156125b1576000805461ff0019169055505050565b600054610100900460ff16806138e157506138e16137cd565b806138ef575060005460ff16155b61390b5760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613936576000805460ff1961ff0019909116610100171660011790555b61393e613f79565b8015610869576000805461ff001916905550565b6000610d077f769f312c3790719cf1ea5f75303393f080fd62be88d75fa86726a6be00bb5a24613c48565b6000610d077fa7ae0fa763ec3009113ccc5eb9089e1f0028607f5b8198c52cd42366c1ddb17b613c48565b6108697f0fa90db0cd58feef247d70d3b21f64c03d0e3ec10eb297f015da0cc09eb3412c82613c4c565b6000610d077f5b8979500398f8fbeb42c36d18f31a76fd0ab30f4338d864e7d8734b340e9bb9613c48565b6108697fcd77091f18f9504fccf6140ab99e20533c811d470bb9a5a983d0edc0720fbf8c82613c4c565b6108697fca2f8a3e9ea81335bcce793cde55fc0c38129b594f53052d2bb18099ffa7261382613c4c565b6000610d077fe3b5969c9426551aa8f16dbc7b25042b9b9c9869b759c77a85f0b097ac363475613c48565b6108697f9027949576d185c74d79ad3b8a8dbff32126f3a3ee140b346f146beb18234c8582613c4c565b6108697fe0dc1d429ff8628e5936b3d6a6546947e1cc9ea7415a59d46ce95b3cfa4442b982613c4c565b6108697f4840b03aa097a422092d99dc6875c2b69e8f48c9af2563a0447f3b4e4928d96282613c4c565b6108697f15b9fa1072bc4b2cdb762a49a2c7917b8b3af02283e37ffd41d0fccd4eef0d4882613c4c565b6108697f92260bfe68dd0f8a9f5439b75466781ba1ce44523ed1a3026a73eada49072e6582613c4c565b6108697f5b8979500398f8fbeb42c36d18f31a76fd0ab30f4338d864e7d8734b340e9bb982613c4c565b6108697fe3b5969c9426551aa8f16dbc7b25042b9b9c9869b759c77a85f0b097ac36347582613c4c565b6108697fa19f3b8a62465676ae47ab811ee15e3d2b68d88869cb38686d086a11d382f6bb82613c4c565b6108697f49c84685200b42972f845832b2c3da3d71def653c151340801aeae053ce104e982613c4c565b6000610d077fca2f8a3e9ea81335bcce793cde55fc0c38129b594f53052d2bb18099ffa72613613c48565b6000610d077f9027949576d185c74d79ad3b8a8dbff32126f3a3ee140b346f146beb18234c855b5490565b9055565b6060613ca5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140009092919063ffffffff16565b8051909150156125b15780806020019051810190613cc3919061447a565b6125b15760405162461bcd60e51b815260040161085790614f13565b6112ec8282613cef576000613cf2565b60015b60ff16613c4c565b6000613d0582613c48565b60011492915050565b6001600160a01b038216613d345760405162461bcd60e51b815260040161085790614fea565b613d40600083836125b1565b603554613d4d90826129e7565b6035556001600160a01b038216600090815260336020526040902054613d7390826129e7565b6001600160a01b0383166000818152603360205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906128ea90859061505b565b61348c846323b872dd60e01b85858560405160240161257a93929190614550565b6000610d077f49c84685200b42972f845832b2c3da3d71def653c151340801aeae053ce104e9613c48565b6000610d077fa19f3b8a62465676ae47ab811ee15e3d2b68d88869cb38686d086a11d382f6bb613c48565b3b151590565b600054610100900460ff1680613e585750613e586137cd565b80613e66575060005460ff16155b613e825760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff1615801561393e576000805460ff1961ff0019909116610100171660011790558015610869576000805461ff001916905550565b600054610100900460ff1680613ed95750613ed96137cd565b80613ee7575060005460ff16155b613f035760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613f2e576000805460ff1961ff0019909116610100171660011790555b8251613f41906036906020860190614140565b508151613f55906037906020850190614140565b506038805460ff1916601217905580156125b1576000805461ff0019169055505050565b600054610100900460ff1680613f925750613f926137cd565b80613fa0575060005460ff16155b613fbc5760405162461bcd60e51b815260040161085790614ad1565b600054610100900460ff16158015613fe7576000805460ff1961ff0019909116610100171660011790555b60016065558015610869576000805461ff001916905550565b606061400f8484600085614017565b949350505050565b6060824710156140395760405162461bcd60e51b815260040161085790614a2c565b61404285613e39565b61405e5760405162461bcd60e51b815260040161085790614edc565b60006060866001600160a01b0316858760405161407b9190614506565b60006040518083038185875af1925050503d80600081146140b8576040519150601f19603f3d011682016040523d82523d6000602084013e6140bd565b606091505b50915091506140cd8282866140d8565b979650505050505050565b606083156140e7575081610cf6565b8251156140f75782518084602001fd5b8160405162461bcd60e51b8152600401610857919061461f565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061418157805160ff19168380011785556141ae565b828001600101855582156141ae579182015b828111156141ae578251825591602001919060010190614193565b506141ba9291506141be565b5090565b5b808211156141ba57600081556001016141bf565b600082601f8301126141e3578081fd5b813567ffffffffffffffff808211156141fa578283fd5b604051601f8301601f19168101602001828111828210171561421a578485fd5b60405282815292508284830160200186101561423557600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215614262578081fd5b8135610cf6816150e5565b60006020828403121561427e578081fd5b8151610cf6816150e5565b6000806040838503121561429b578081fd5b82356142a6816150e5565b915060208301356142b6816150e5565b809150509250929050565b600080600080608085870312156142d6578182fd5b84356142e1816150e5565b935060208501356142f1816150e5565b9250604085013567ffffffffffffffff8082111561430d578384fd5b614319888389016141d3565b9350606087013591508082111561432e578283fd5b5061433b878288016141d3565b91505092959194509250565b60008060006060848603121561435b578283fd5b8335614366816150e5565b92506020840135614376816150e5565b929592945050506040919091013590565b60008060408385031215614399578182fd5b82356143a4816150e5565b946020939093013593505050565b6000806000606084860312156143c6578283fd5b83356143d1816150e5565b95602085013595506040909401359392505050565b60008060008060008060c087890312156143fe578182fd5b8635614409816150e5565b955060208701359450604087013561442081615108565b93506060870135614430816150e5565b92506080870135614440816150e5565b915060a0870135614450816150e5565b809150509295509295509295565b60006020828403121561446f578081fd5b8135610cf6816150fa565b60006020828403121561448b578081fd5b8151610cf6816150fa565b6000602082840312156144a7578081fd5b5035919050565b6000602082840312156144bf578081fd5b5051919050565b600080604083850312156144d8578182fd5b8235915060208301356142b6816150e5565b6000602082840312156144fb578081fd5b8151610cf681615108565b600082516145188184602087016150b9565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6020808252825182820181905260009190848201906040850190845b818110156145ef5783516001600160a01b0316835292840192918401916001016145ca565b50909695505050505050565b901515815260200190565b91151582526001600160a01b0316602082015260400190565b600060208252825180602084015261463e8160408501602087016150b9565b601f01601f19169190910160400192915050565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526021908201527f6e657720676f7665726e616e63652073686f756c646e277420626520656d70746040820152607960f81b606082015260800190565b60208082526017908201527f56616c75652067726561746572207468616e2031303025000000000000000000604082015260600190565b60208082526026908201527f546865207765696768746167652073686f756c6420626520677265617465722060408201526507468616e20360d41b606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b6020808252601a908201527f53747261746567696573206d75737420626520646566696e6564000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526010908201526f043616e6e6f74206465706f73697420360841b604082015260600190565b60208082526017908201527f546f74616c206465706f736974206c696d697420686974000000000000000000604082015260600190565b60208082526013908201527211195c1bdcda5d1cc8185c99481c185d5cd959606a1b604082015260600190565b60208082526028908201527f54686973207374726174656779206973206e6f742061637469766520696e20746040820152671a1a5cc8199d5b9960c21b606082015260800190565b6020808252601f908201527f6e6577206e657753747261746567792063616e6e6f7420626520656d70747900604082015260600190565b60208082526018908201527f506572666f726d616e63652066656520746f6f20686967680000000000000000604082015260600190565b6020808252602b908201527f4e6f7420676f7665726e616e6365206e6f722066756e64206d616e616765722060408201526a3737b9103932b630bcb2b960a91b606082015260800190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252601f908201527f4e6f7420676f7665726e616e6365206e6f722066756e64206d616e6167657200604082015260600190565b60208082526012908201527146756e6420686173206e6f2073686172657360701b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600e908201526d4e6f7420676f7665726e616e636560901b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601690820152754e6f742070656e64696e6720676f7665726e616e636560501b604082015260600190565b6020808252601a908201527f4665652067726561746572207468616e206d6178206c696d6974000000000000604082015260600190565b60208082526025908201527f4d696e696d756d207472616e73616374696f6e206465706f736974206c696d696040820152641d081a1a5d60da1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252818101527f63757272656e742073747261746567792063616e6e6f7420626520656d707479604082015260600190565b6020808252602c908201527f5468697320737472617465677920697320616c7265616479206163746976652060408201526b1a5b881d1a1a5cc8199d5b9960a21b606082015260800190565b60208082526018908201527f63616e206e6f7420737765657020756e6465726c79696e670000000000000000604082015260600190565b60208082526025908201527f4d6178696d756d207472616e73616374696f6e206465706f736974206c696d696040820152641d081a1a5d60da1b606082015260800190565b60208082526025908201527f6e756d6265724f66536861726573206d75737420626520677265617465722074604082015264068616e20360dc1b606082015260800190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602b908201527f546f74616c20696e766573746d656e742063616e27742062652061626f76652060408201526a1b585e08185b1b1bddd95960aa1b606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b6020808252601690820152751a1bdb19195c881b5d5cdd081899481919599a5b995960521b604082015260600190565b60208082526029908201527f54686520737472617465677920646f6573206e6f742062656c6f6e6720746f206040820152681d1a1a5cc8199d5b9960ba1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60ff91909116815260200190565b60005b838110156150d45781810151838201526020016150bc565b8381111561348c5750506000910152565b6001600160a01b038116811461086957600080fd5b801515811461086957600080fd5b60ff8116811461086957600080fdfe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220a9bcec6584b2926afeb4008d85fee0869e6baff6263d0884e773eacb9071476a64736f6c634300060c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.