Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
- | 12170595 | 1475 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
DMMPool
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-04-04 */ // SPDX-License-Identifier: BUSL-1.1 // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, 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; } } // File: @openzeppelin/contracts/math/Math.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @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); } } // File: @openzeppelin/contracts/utils/ReentrancyGuard.sol pragma solidity >=0.6.0 <0.8.0; /** * @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 ReentrancyGuard { // 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; constructor () internal { _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; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity >=0.6.2 <0.8.0; /** * @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); } } } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity >=0.6.0 <0.8.0; /** * @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"); } } } // File: contracts/libraries/MathExt.sol pragma solidity 0.6.12; library MathExt { using SafeMath for uint256; uint256 public constant PRECISION = (10**18); /// @dev Returns x*y in precision function mulInPrecision(uint256 x, uint256 y) internal pure returns (uint256) { return x.mul(y) / PRECISION; } /// @dev source: dsMath /// @param xInPrecision should be < PRECISION, so this can not overflow /// @return zInPrecision = (x/PRECISION) ^k * PRECISION function unsafePowInPrecision(uint256 xInPrecision, uint256 k) internal pure returns (uint256 zInPrecision) { require(xInPrecision <= PRECISION, "MathExt: x > PRECISION"); zInPrecision = k % 2 != 0 ? xInPrecision : PRECISION; for (k /= 2; k != 0; k /= 2) { xInPrecision = (xInPrecision * xInPrecision) / PRECISION; if (k % 2 != 0) { zInPrecision = (zInPrecision * xInPrecision) / PRECISION; } } } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } // File: contracts/libraries/FeeFomula.sol pragma solidity 0.6.12; library FeeFomula { using SafeMath for uint256; using MathExt for uint256; uint256 private constant PRECISION = 10**18; uint256 private constant R0 = 1477405064814996100; // 1.4774050648149961 uint256 private constant C0 = (60 * PRECISION) / 10000; uint256 private constant A = uint256(PRECISION * 20000) / 27; uint256 private constant B = uint256(PRECISION * 250) / 9; uint256 private constant C1 = uint256(PRECISION * 985) / 27; uint256 private constant U = (120 * PRECISION) / 100; uint256 private constant G = (836 * PRECISION) / 1000; uint256 private constant F = 5 * PRECISION; uint256 private constant L = (2 * PRECISION) / 10000; // C2 = 25 * PRECISION - (F * (PRECISION - G)**2) / ((PRECISION - G)**2 + L * PRECISION) uint256 private constant C2 = 20036905816356657810; /// @dev calculate fee from rFactorInPrecision, see section 3.2 in dmmSwap white paper /// @dev fee in [15, 60] bps /// @return fee percentage in Precision function getFee(uint256 rFactorInPrecision) internal pure returns (uint256) { if (rFactorInPrecision >= R0) { return C0; } else if (rFactorInPrecision >= PRECISION) { // C1 + A * (r-U)^3 + b * (r -U) if (rFactorInPrecision > U) { uint256 tmp = rFactorInPrecision - U; uint256 tmp3 = tmp.unsafePowInPrecision(3); return (C1.add(A.mulInPrecision(tmp3)).add(B.mulInPrecision(tmp))) / 10000; } else { uint256 tmp = U - rFactorInPrecision; uint256 tmp3 = tmp.unsafePowInPrecision(3); return C1.sub(A.mulInPrecision(tmp3)).sub(B.mulInPrecision(tmp)) / 10000; } } else { // [ C2 + sign(r - G) * F * (r-G) ^2 / (L + (r-G) ^2) ] / 10000 uint256 tmp = ( rFactorInPrecision > G ? (rFactorInPrecision - G) : (G - rFactorInPrecision) ); tmp = tmp.unsafePowInPrecision(2); uint256 tmp2 = F.mul(tmp).div(tmp.add(L)); if (rFactorInPrecision > G) { return C2.add(tmp2) / 10000; } else { return C2.sub(tmp2) / 10000; } } } } // File: @openzeppelin/contracts/utils/Context.sol pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/token/ERC20/ERC20.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath 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. */ constructor (string memory name_, string memory symbol_) public { _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 { } } // File: contracts/interfaces/IERC20Permit.sol pragma solidity 0.6.12; interface IERC20Permit is IERC20 { function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; } // File: contracts/libraries/ERC20Permit.sol pragma solidity 0.6.12; /// @dev https://eips.ethereum.org/EIPS/eip-2612 contract ERC20Permit is ERC20, IERC20Permit { /// @dev To make etherscan auto-verify new pool, this variable is not immutable bytes32 public domainSeparator; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint256) public nonces; constructor( string memory name, string memory symbol, string memory version ) public ERC20(name, symbol) { uint256 chainId; assembly { chainId := chainid() } domainSeparator = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes(name)), keccak256(bytes(version)), chainId, address(this) ) ); } function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external override { require(deadline >= block.timestamp, "ERC20Permit: EXPIRED"); bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", domainSeparator, keccak256( abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline) ) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require( recoveredAddress != address(0) && recoveredAddress == owner, "ERC20Permit: INVALID_SIGNATURE" ); _approve(owner, spender, value); } } // File: contracts/interfaces/IDMMFactory.sol pragma solidity 0.6.12; interface IDMMFactory { function createPool( IERC20 tokenA, IERC20 tokenB, uint32 ampBps ) external returns (address pool); function setFeeConfiguration(address feeTo, uint16 governmentFeeBps) external; function setFeeToSetter(address) external; function getFeeConfiguration() external view returns (address feeTo, uint16 governmentFeeBps); function feeToSetter() external view returns (address); function allPools(uint256) external view returns (address pool); function allPoolsLength() external view returns (uint256); function getUnamplifiedPool(IERC20 token0, IERC20 token1) external view returns (address); function getPools(IERC20 token0, IERC20 token1) external view returns (address[] memory _tokenPools); function isPool( IERC20 token0, IERC20 token1, address pool ) external view returns (bool); } // File: contracts/interfaces/IDMMCallee.sol pragma solidity 0.6.12; interface IDMMCallee { function dmmSwapCall( address sender, uint256 amount0, uint256 amount1, bytes calldata data ) external; } // File: contracts/interfaces/IDMMPool.sol pragma solidity 0.6.12; interface IDMMPool { function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function sync() external; function getReserves() external view returns (uint112 reserve0, uint112 reserve1); function getTradeInfo() external view returns ( uint112 _vReserve0, uint112 _vReserve1, uint112 reserve0, uint112 reserve1, uint256 feeInPrecision ); function token0() external view returns (IERC20); function token1() external view returns (IERC20); function ampBps() external view returns (uint32); function factory() external view returns (IDMMFactory); function kLast() external view returns (uint256); } // File: contracts/interfaces/IERC20Metadata.sol pragma solidity 0.6.12; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); } // File: contracts/VolumeTrendRecorder.sol pragma solidity 0.6.12; /// @dev contract to calculate volume trend. See secion 3.1 in the white paper /// @dev EMA stands for Exponential moving average /// @dev https://en.wikipedia.org/wiki/Moving_average contract VolumeTrendRecorder { using MathExt for uint256; using SafeMath for uint256; uint256 private constant MAX_UINT128 = 2**128 - 1; uint256 internal constant PRECISION = 10**18; uint256 private constant SHORT_ALPHA = (2 * PRECISION) / 5401; uint256 private constant LONG_ALPHA = (2 * PRECISION) / 10801; uint128 internal shortEMA; uint128 internal longEMA; // total volume in current block uint128 internal currentBlockVolume; uint128 internal lastTradeBlock; event UpdateEMA(uint256 shortEMA, uint256 longEMA, uint128 lastBlockVolume, uint256 skipBlock); constructor(uint128 _emaInit) public { shortEMA = _emaInit; longEMA = _emaInit; lastTradeBlock = safeUint128(block.number); } function getVolumeTrendData() external view returns ( uint128 _shortEMA, uint128 _longEMA, uint128 _currentBlockVolume, uint128 _lastTradeBlock ) { _shortEMA = shortEMA; _longEMA = longEMA; _currentBlockVolume = currentBlockVolume; _lastTradeBlock = lastTradeBlock; } /// @dev records a new trade, update ema and returns current rFactor for this trade /// @return rFactor in Precision for this trade function recordNewUpdatedVolume(uint256 blockNumber, uint256 value) internal returns (uint256) { // this can not be underflow because block.number always increases uint256 skipBlock = blockNumber - lastTradeBlock; if (skipBlock == 0) { currentBlockVolume = safeUint128( uint256(currentBlockVolume).add(value), "volume exceeds valid range" ); return calculateRFactor(uint256(shortEMA), uint256(longEMA)); } uint128 _currentBlockVolume = currentBlockVolume; uint256 _shortEMA = newEMA(shortEMA, SHORT_ALPHA, currentBlockVolume); uint256 _longEMA = newEMA(longEMA, LONG_ALPHA, currentBlockVolume); // ema = ema * (1-aplha) ^(skipBlock -1) _shortEMA = _shortEMA.mulInPrecision( (PRECISION - SHORT_ALPHA).unsafePowInPrecision(skipBlock - 1) ); _longEMA = _longEMA.mulInPrecision( (PRECISION - LONG_ALPHA).unsafePowInPrecision(skipBlock - 1) ); shortEMA = safeUint128(_shortEMA); longEMA = safeUint128(_longEMA); currentBlockVolume = safeUint128(value); lastTradeBlock = safeUint128(blockNumber); emit UpdateEMA(_shortEMA, _longEMA, _currentBlockVolume, skipBlock); return calculateRFactor(_shortEMA, _longEMA); } /// @return rFactor in Precision for this trade function getRFactor(uint256 blockNumber) internal view returns (uint256) { // this can not be underflow because block.number always increases uint256 skipBlock = blockNumber - lastTradeBlock; if (skipBlock == 0) { return calculateRFactor(shortEMA, longEMA); } uint256 _shortEMA = newEMA(shortEMA, SHORT_ALPHA, currentBlockVolume); uint256 _longEMA = newEMA(longEMA, LONG_ALPHA, currentBlockVolume); _shortEMA = _shortEMA.mulInPrecision( (PRECISION - SHORT_ALPHA).unsafePowInPrecision(skipBlock - 1) ); _longEMA = _longEMA.mulInPrecision( (PRECISION - LONG_ALPHA).unsafePowInPrecision(skipBlock - 1) ); return calculateRFactor(_shortEMA, _longEMA); } function calculateRFactor(uint256 _shortEMA, uint256 _longEMA) internal pure returns (uint256) { if (_longEMA == 0) { return 0; } return (_shortEMA * MathExt.PRECISION) / _longEMA; } /// @dev return newEMA value /// @param ema previous ema value in wei /// @param alpha in Precicion (required < Precision) /// @param value current value to update ema /// @dev ema and value is uint128 and alpha < Percison /// @dev so this function can not overflow and returned ema is not overflow uint128 function newEMA( uint128 ema, uint256 alpha, uint128 value ) internal pure returns (uint256) { assert(alpha < PRECISION); return ((PRECISION - alpha) * uint256(ema) + alpha * uint256(value)) / PRECISION; } function safeUint128(uint256 v) internal pure returns (uint128) { require(v <= MAX_UINT128, "overflow uint128"); return uint128(v); } function safeUint128(uint256 v, string memory errorMessage) internal pure returns (uint128) { require(v <= MAX_UINT128, errorMessage); return uint128(v); } } // File: contracts/DMMPool.sol pragma solidity 0.6.12; contract DMMPool is IDMMPool, ERC20Permit, ReentrancyGuard, VolumeTrendRecorder { using SafeMath for uint256; using SafeERC20 for IERC20; uint256 internal constant MAX_UINT112 = 2**112 - 1; uint256 internal constant BPS = 10000; struct ReserveData { uint256 reserve0; uint256 reserve1; uint256 vReserve0; uint256 vReserve1; // only used when isAmpPool = true } uint256 public constant MINIMUM_LIQUIDITY = 10**3; /// @dev To make etherscan auto-verify new pool, these variables are not immutable IDMMFactory public override factory; IERC20 public override token0; IERC20 public override token1; /// @dev uses single storage slot, accessible via getReservesData uint112 internal reserve0; uint112 internal reserve1; uint32 public override ampBps; /// @dev addition param only when amplification factor > 1 uint112 internal vReserve0; uint112 internal vReserve1; /// @dev vReserve0 * vReserve1, as of immediately after the most recent liquidity event uint256 public override kLast; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to, uint256 feeInPrecision ); event Sync(uint256 vReserve0, uint256 vReserve1, uint256 reserve0, uint256 reserve1); constructor() public ERC20Permit("KyberDMM LP", "DMM-LP", "1") VolumeTrendRecorder(0) { factory = IDMMFactory(msg.sender); } // called once by the factory at time of deployment function initialize( IERC20 _token0, IERC20 _token1, uint32 _ampBps ) external { require(msg.sender == address(factory), "DMM: FORBIDDEN"); token0 = _token0; token1 = _token1; ampBps = _ampBps; } /// @dev this low-level function should be called from a contract /// which performs important safety checks function mint(address to) external override nonReentrant returns (uint256 liquidity) { (bool isAmpPool, ReserveData memory data) = getReservesData(); ReserveData memory _data; _data.reserve0 = token0.balanceOf(address(this)); _data.reserve1 = token1.balanceOf(address(this)); uint256 amount0 = _data.reserve0.sub(data.reserve0); uint256 amount1 = _data.reserve1.sub(data.reserve1); bool feeOn = _mintFee(isAmpPool, data); uint256 _totalSupply = totalSupply(); // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { if (isAmpPool) { uint32 _ampBps = ampBps; _data.vReserve0 = _data.reserve0.mul(_ampBps) / BPS; _data.vReserve1 = _data.reserve1.mul(_ampBps) / BPS; } liquidity = MathExt.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(-1), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min( amount0.mul(_totalSupply) / data.reserve0, amount1.mul(_totalSupply) / data.reserve1 ); if (isAmpPool) { uint256 b = liquidity.add(_totalSupply); _data.vReserve0 = Math.max(data.vReserve0.mul(b) / _totalSupply, _data.reserve0); _data.vReserve1 = Math.max(data.vReserve1.mul(b) / _totalSupply, _data.reserve1); } } require(liquidity > 0, "DMM: INSUFFICIENT_LIQUIDITY_MINTED"); _mint(to, liquidity); _update(isAmpPool, _data); if (feeOn) kLast = getK(isAmpPool, _data); emit Mint(msg.sender, amount0, amount1); } /// @dev this low-level function should be called from a contract /// @dev which performs important safety checks /// @dev user must transfer LP token to this contract before call burn function burn(address to) external override nonReentrant returns (uint256 amount0, uint256 amount1) { (bool isAmpPool, ReserveData memory data) = getReservesData(); // gas savings IERC20 _token0 = token0; // gas savings IERC20 _token1 = token1; // gas savings uint256 balance0 = _token0.balanceOf(address(this)); uint256 balance1 = _token1.balanceOf(address(this)); require(balance0 >= data.reserve0 && balance1 >= data.reserve1, "DMM: UNSYNC_RESERVES"); uint256 liquidity = balanceOf(address(this)); bool feeOn = _mintFee(isAmpPool, data); uint256 _totalSupply = totalSupply(); // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, "DMM: INSUFFICIENT_LIQUIDITY_BURNED"); _burn(address(this), liquidity); _token0.safeTransfer(to, amount0); _token1.safeTransfer(to, amount1); ReserveData memory _data; _data.reserve0 = _token0.balanceOf(address(this)); _data.reserve1 = _token1.balanceOf(address(this)); if (isAmpPool) { uint256 b = Math.min( _data.reserve0.mul(_totalSupply) / data.reserve0, _data.reserve1.mul(_totalSupply) / data.reserve1 ); _data.vReserve0 = Math.max(data.vReserve0.mul(b) / _totalSupply, _data.reserve0); _data.vReserve1 = Math.max(data.vReserve1.mul(b) / _totalSupply, _data.reserve1); } _update(isAmpPool, _data); if (feeOn) kLast = getK(isAmpPool, _data); // data are up-to-date emit Burn(msg.sender, amount0, amount1, to); } /// @dev this low-level function should be called from a contract /// @dev which performs important safety checks function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata callbackData ) external override nonReentrant { require(amount0Out > 0 || amount1Out > 0, "DMM: INSUFFICIENT_OUTPUT_AMOUNT"); (bool isAmpPool, ReserveData memory data) = getReservesData(); // gas savings require( amount0Out < data.reserve0 && amount1Out < data.reserve1, "DMM: INSUFFICIENT_LIQUIDITY" ); ReserveData memory newData; { // scope for _token{0,1}, avoids stack too deep errors IERC20 _token0 = token0; IERC20 _token1 = token1; require(to != address(_token0) && to != address(_token1), "DMM: INVALID_TO"); if (amount0Out > 0) _token0.safeTransfer(to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _token1.safeTransfer(to, amount1Out); // optimistically transfer tokens if (callbackData.length > 0) IDMMCallee(to).dmmSwapCall(msg.sender, amount0Out, amount1Out, callbackData); newData.reserve0 = _token0.balanceOf(address(this)); newData.reserve1 = _token1.balanceOf(address(this)); if (isAmpPool) { newData.vReserve0 = data.vReserve0.add(newData.reserve0).sub(data.reserve0); newData.vReserve1 = data.vReserve1.add(newData.reserve1).sub(data.reserve1); } } uint256 amount0In = newData.reserve0 > data.reserve0 - amount0Out ? newData.reserve0 - (data.reserve0 - amount0Out) : 0; uint256 amount1In = newData.reserve1 > data.reserve1 - amount1Out ? newData.reserve1 - (data.reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, "DMM: INSUFFICIENT_INPUT_AMOUNT"); uint256 feeInPrecision = verifyBalanceAndUpdateEma( amount0In, amount1In, isAmpPool ? data.vReserve0 : data.reserve0, isAmpPool ? data.vReserve1 : data.reserve1, isAmpPool ? newData.vReserve0 : newData.reserve0, isAmpPool ? newData.vReserve1 : newData.reserve1 ); _update(isAmpPool, newData); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to, feeInPrecision); } /// @dev force balances to match reserves function skim(address to) external nonReentrant { token0.safeTransfer(to, token0.balanceOf(address(this)).sub(reserve0)); token1.safeTransfer(to, token1.balanceOf(address(this)).sub(reserve1)); } /// @dev force reserves to match balances function sync() external override nonReentrant { (bool isAmpPool, ReserveData memory data) = getReservesData(); bool feeOn = _mintFee(isAmpPool, data); ReserveData memory newData; newData.reserve0 = IERC20(token0).balanceOf(address(this)); newData.reserve1 = IERC20(token1).balanceOf(address(this)); // update virtual reserves if this is amp pool if (isAmpPool) { uint256 _totalSupply = totalSupply(); uint256 b = Math.min( newData.reserve0.mul(_totalSupply) / data.reserve0, newData.reserve1.mul(_totalSupply) / data.reserve1 ); newData.vReserve0 = Math.max(data.vReserve0.mul(b) / _totalSupply, newData.reserve0); newData.vReserve1 = Math.max(data.vReserve1.mul(b) / _totalSupply, newData.reserve1); } _update(isAmpPool, newData); if (feeOn) kLast = getK(isAmpPool, newData); } /// @dev returns data to calculate amountIn, amountOut function getTradeInfo() external virtual override view returns ( uint112 _reserve0, uint112 _reserve1, uint112 _vReserve0, uint112 _vReserve1, uint256 feeInPrecision ) { // gas saving to read reserve data _reserve0 = reserve0; _reserve1 = reserve1; uint32 _ampBps = ampBps; _vReserve0 = vReserve0; _vReserve1 = vReserve1; if (_ampBps == BPS) { _vReserve0 = _reserve0; _vReserve1 = _reserve1; } uint256 rFactorInPrecision = getRFactor(block.number); feeInPrecision = getFinalFee(FeeFomula.getFee(rFactorInPrecision), _ampBps); } /// @dev returns reserve data to calculate amount to add liquidity function getReserves() external override view returns (uint112 _reserve0, uint112 _reserve1) { _reserve0 = reserve0; _reserve1 = reserve1; } function name() public override view returns (string memory) { IERC20Metadata _token0 = IERC20Metadata(address(token0)); IERC20Metadata _token1 = IERC20Metadata(address(token1)); return string(abi.encodePacked("KyberDMM LP ", _token0.symbol(), "-", _token1.symbol())); } function symbol() public override view returns (string memory) { IERC20Metadata _token0 = IERC20Metadata(address(token0)); IERC20Metadata _token1 = IERC20Metadata(address(token1)); return string(abi.encodePacked("DMM-LP ", _token0.symbol(), "-", _token1.symbol())); } function verifyBalanceAndUpdateEma( uint256 amount0In, uint256 amount1In, uint256 beforeReserve0, uint256 beforeReserve1, uint256 afterReserve0, uint256 afterReserve1 ) internal virtual returns (uint256 feeInPrecision) { // volume = beforeReserve0 * amount1In / beforeReserve1 + amount0In (normalized into amount in token 0) uint256 volume = beforeReserve0.mul(amount1In).div(beforeReserve1).add(amount0In); uint256 rFactorInPrecision = recordNewUpdatedVolume(block.number, volume); feeInPrecision = getFinalFee(FeeFomula.getFee(rFactorInPrecision), ampBps); // verify balance update matches with fomula uint256 balance0Adjusted = afterReserve0.mul(PRECISION); balance0Adjusted = balance0Adjusted.sub(amount0In.mul(feeInPrecision)); balance0Adjusted = balance0Adjusted / PRECISION; uint256 balance1Adjusted = afterReserve1.mul(PRECISION); balance1Adjusted = balance1Adjusted.sub(amount1In.mul(feeInPrecision)); balance1Adjusted = balance1Adjusted / PRECISION; require( balance0Adjusted.mul(balance1Adjusted) >= beforeReserve0.mul(beforeReserve1), "DMM: K" ); } /// @dev update reserves function _update(bool isAmpPool, ReserveData memory data) internal { reserve0 = safeUint112(data.reserve0); reserve1 = safeUint112(data.reserve1); if (isAmpPool) { assert(data.vReserve0 >= data.reserve0 && data.vReserve1 >= data.reserve1); // never happen vReserve0 = safeUint112(data.vReserve0); vReserve1 = safeUint112(data.vReserve1); } emit Sync(data.vReserve0, data.vReserve1, data.reserve0, data.reserve1); } /// @dev if fee is on, mint liquidity equivalent to configured fee of the growth in sqrt(k) function _mintFee(bool isAmpPool, ReserveData memory data) internal returns (bool feeOn) { (address feeTo, uint16 governmentFeeBps) = factory.getFeeConfiguration(); feeOn = feeTo != address(0); uint256 _kLast = kLast; // gas savings if (feeOn) { if (_kLast != 0) { uint256 rootK = MathExt.sqrt(getK(isAmpPool, data)); uint256 rootKLast = MathExt.sqrt(_kLast); if (rootK > rootKLast) { uint256 numerator = totalSupply().mul(rootK.sub(rootKLast)).mul( governmentFeeBps ); uint256 denominator = rootK.add(rootKLast).mul(5000); uint256 liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } else if (_kLast != 0) { kLast = 0; } } /// @dev gas saving to read reserve data function getReservesData() internal view returns (bool isAmpPool, ReserveData memory data) { data.reserve0 = reserve0; data.reserve1 = reserve1; isAmpPool = ampBps != BPS; if (isAmpPool) { data.vReserve0 = vReserve0; data.vReserve1 = vReserve1; } } function getFinalFee(uint256 feeInPrecision, uint32 _ampBps) internal pure returns (uint256) { if (_ampBps <= 20000) { return feeInPrecision; } else if (_ampBps <= 50000) { return (feeInPrecision * 20) / 30; } else if (_ampBps <= 200000) { return (feeInPrecision * 10) / 30; } else { return (feeInPrecision * 4) / 30; } } function getK(bool isAmpPool, ReserveData memory data) internal pure returns (uint256) { return isAmpPool ? data.vReserve0 * data.vReserve1 : data.reserve0 * data.reserve1; } function safeUint112(uint256 x) internal pure returns (uint112) { require(x <= MAX_UINT112, "DMM: OVERFLOW"); return uint112(x); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeInPrecision","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vReserve0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vReserve1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve1","type":"uint256"}],"name":"Sync","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":false,"internalType":"uint256","name":"shortEMA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"longEMA","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"lastBlockVolume","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"skipBlock","type":"uint256"}],"name":"UpdateEMA","type":"event"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ampBps","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IDMMFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTradeInfo","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint112","name":"_vReserve0","type":"uint112"},{"internalType":"uint112","name":"_vReserve1","type":"uint112"},{"internalType":"uint256","name":"feeInPrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVolumeTrendData","outputs":[{"internalType":"uint128","name":"_shortEMA","type":"uint128"},{"internalType":"uint128","name":"_longEMA","type":"uint128"},{"internalType":"uint128","name":"_currentBlockVolume","type":"uint128"},{"internalType":"uint128","name":"_lastTradeBlock","type":"uint128"}],"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":"contract IERC20","name":"_token0","type":"address"},{"internalType":"contract IERC20","name":"_token1","type":"address"},{"internalType":"uint32","name":"_ampBps","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060006040518060400160405280600b81526020016a04b79626572444d4d204c560ac1b815250604051806040016040528060068152602001650444d4d2d4c560d41b815250604051806040016040528060018152602001603160f81b815250828281600390805190602001906200008b929190620001ee565b508051620000a1906004906020840190620001ee565b50506005805460ff19166012179055508251602093840120815191840191909120604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818701528082019390935260608301919091524660808301523060a0808401919091528151808403909101815260c09092019052805192019190912060065550600160085560098054600160801b6001600160801b038085169182026001600160801b03199093169190911716179055620001624362000198565b600a80546001600160801b03928316600160801b02921691909117905550600b80546001600160a01b0319163317905562000280565b60006001600160801b03821115620001ea576040805162461bcd60e51b815260206004820152601060248201526f0deeccae4ccd8deee40ead2dce86264760831b604482015290519081900360640190fd5b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200023157805160ff191683800117855562000261565b8280016001018555821562000261579182015b828111156200026157825182559160200191906001019062000244565b50620001ea9291505b80821115620001ea57600081556001016200026a565b614ae880620002906000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80637464fc3d11610104578063bc25cf77116100a2578063d669402711610071578063d669402714610736578063dd62ed3e14610780578063f698da25146107bb578063fff6cae9146107c3576101da565b8063bc25cf7714610695578063c45a0155146106c8578063d21220a7146106d0578063d505accf146106d8576101da565b806395d89b41116100de57806395d89b4114610613578063a457c2d71461061b578063a9059cbb14610654578063ba9a7a561461068d576101da565b80637464fc3d1461058c5780637ecebe001461059457806389afcb44146105c7576101da565b806323b872dd1161017c57806349386b161161014b57806349386b16146104bb5780636a627842146104dc5780636ecf2b221461050f57806370a0823114610559576101da565b806323b872dd1461041957806330adf81f1461045c578063313ce567146104645780633950935114610482576101da565b8063095ea7b3116101b8578063095ea7b31461033c5780630d94d50b146103895780630dfe1681146103ce57806318160ddd146103ff576101da565b8063022c0d9f146101df57806306fdde031461027a5780630902f1ac146102f7575b600080fd5b610278600480360360808110156101f557600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b5090925090506107cb565b005b610282610e6a565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102bc5781810151838201526020016102a4565b50505050905090810190601f1680156102e95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102ff611282565b60405180836dffffffffffffffffffffffffffff168152602001826dffffffffffffffffffffffffffff1681526020019250505060405180910390f35b6103756004803603604081101561035257600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356112af565b604080519115158252519081900360200190f35b6103916112cd565b604080516fffffffffffffffffffffffffffffffff9586168152938516602085015291841683830152909216606082015290519081900360800190f35b6103d661130c565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b610407611328565b60408051918252519081900360200190f35b6103756004803603606081101561042f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135909116906040013561132e565b6104076113d0565b61046c6113f4565b6040805160ff9092168252519081900360200190f35b6103756004803603604081101561049857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356113fd565b6104c3611458565b6040805163ffffffff9092168252519081900360200190f35b610407600480360360208110156104f257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611484565b6102786004803603606081101561052557600080fd5b50803573ffffffffffffffffffffffffffffffffffffffff908116916020810135909116906040013563ffffffff166118f4565b6104076004803603602081101561056f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a22565b610407611a4e565b610407600480360360208110156105aa57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a54565b6105fa600480360360208110156105dd57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a66565b6040805192835260208301919091528051918290030190f35b610282612044565b6103756004803603604081101561063157600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561238c565b6103756004803603604081101561066a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612401565b610407612415565b610278600480360360208110156106ab57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661241b565b6103d661263d565b6103d6612659565b610278600480360360e08110156106ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135612675565b61073e612941565b604080516dffffffffffffffffffffffffffff968716815294861660208601529285168484015293166060830152608082019290925290519081900360a00190f35b6104076004803603604081101561079657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166129dd565b610407612a15565b610278612a1b565b6002600854141561083d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600855841515806108505750600084115b6108bb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f444d4d3a20494e53554646494349454e545f4f55545055545f414d4f554e5400604482015290519081900360640190fd5b60006108c5614891565b6108cd612cd8565b80519193509150871080156108e55750806020015186105b61095057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f444d4d3a20494e53554646494349454e545f4c49515549444954590000000000604482015290519081900360640190fd5b610958614891565b600c54600d5473ffffffffffffffffffffffffffffffffffffffff9182169190811690881682148015906109b857508073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614155b610a2357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f444d4d3a20494e56414c49445f544f0000000000000000000000000000000000604482015290519081900360640190fd5b8915610a4a57610a4a73ffffffffffffffffffffffffffffffffffffffff8316898c612d7c565b8815610a7157610a7173ffffffffffffffffffffffffffffffffffffffff8216898b612d7c565b8515610b3d578773ffffffffffffffffffffffffffffffffffffffff166381279c7e338c8c8b8b6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b158015610b2457600080fd5b505af1158015610b38573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610ba957600080fd5b505afa158015610bbd573d6000803e3d6000fd5b505050506040513d6020811015610bd357600080fd5b50518352604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8316916370a08231916024808301926020929190829003018186803b158015610c4357600080fd5b505afa158015610c57573d6000803e3d6000fd5b505050506040513d6020811015610c6d57600080fd5b505160208401528415610cc157835183516040860151610c989291610c929190612e0e565b90612e82565b6040840152602080850151908401516060860151610cbb9291610c929190612e0e565b60608401525b5050815181516000918a900310610cd9576000610ce4565b82518251908a900390035b9050600088846020015103836020015111610d00576000610d0e565b888460200151038360200151035b90506000821180610d1f5750600081115b610d8a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f444d4d3a20494e53554646494349454e545f494e5055545f414d4f554e540000604482015290519081900360640190fd5b6000610de4838388610d9d578751610da3565b87604001515b89610db2578860200151610db8565b88606001515b8a610dc4578851610dca565b88604001515b8b610dd9578960200151610ddf565b89606001515b612ef9565b9050610df0868561305e565b60408051848152602081018490528082018d9052606081018c905260808101839052905173ffffffffffffffffffffffffffffffffffffffff8b169133917f606ecd02b3e3b4778f8e97b2e03351de14224efaa5fa64e62200afc9395c24999181900360a00190a350506001600855505050505050505050565b600c54600d54604080517f95d89b41000000000000000000000000000000000000000000000000000000008152905160609373ffffffffffffffffffffffffffffffffffffffff90811693169183916395d89b4191600480820192600092909190829003018186803b158015610edf57600080fd5b505afa158015610ef3573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526020811015610f3a57600080fd5b8101908080516040519392919084640100000000821115610f5a57600080fd5b908301906020820185811115610f6f57600080fd5b8251640100000000811182820188101715610f8957600080fd5b82525081516020918201929091019080838360005b83811015610fb6578181015183820152602001610f9e565b50505050905090810190601f168015610fe35780820380516001836020036101000a031916815260200191505b506040525050508173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561103057600080fd5b505afa158015611044573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561108b57600080fd5b81019080805160405193929190846401000000008211156110ab57600080fd5b9083019060208201858111156110c057600080fd5b82516401000000008111828201881017156110da57600080fd5b82525081516020918201929091019080838360005b838110156111075781810151838201526020016110ef565b50505050905090810190601f1680156111345780820380516001836020036101000a031916815260200191505b5060405250505060405160200180807f4b79626572444d4d204c50200000000000000000000000000000000000000000815250600c0183805190602001908083835b602083106111b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611176565b6001836020036101000a038019825116818451168082178552505050505050905001807f2d0000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b6020831061124657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611209565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529250505090565b600e546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006112c36112bc6131f9565b84846131fd565b5060015b92915050565b600954600a546fffffffffffffffffffffffffffffffff8083169370010000000000000000000000000000000093849004821693838316930490911690565b600c5473ffffffffffffffffffffffffffffffffffffffff1681565b60025490565b600061133b848484613344565b6113c5846113476131f9565b6113c0856040518060600160405280602881526020016149b06028913973ffffffffffffffffffffffffffffffffffffffff8a166000908152600160205260408120906113926131f9565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020549190613514565b6131fd565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60055460ff1690565b60006112c361140a6131f9565b846113c0856001600061141b6131f9565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918c168152925290205490612e0e565b600e547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1681565b6000600260085414156114f857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000611507614891565b61150f612cd8565b9150915061151b614891565b600c54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b15801561158c57600080fd5b505afa1580156115a0573d6000803e3d6000fd5b505050506040513d60208110156115b657600080fd5b50518152600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b15801561162b57600080fd5b505afa15801561163f573d6000803e3d6000fd5b505050506040513d602081101561165557600080fd5b505160208201528151815160009161166d9190612e82565b9050600061168c84602001518460200151612e8290919063ffffffff16565b9050600061169a86866135c5565b905060006116a6611328565b90508061177457861561172957600e54855163ffffffff7c0100000000000000000000000000000000000000000000000000000000909204821691612710916116f191849061373416565b816116f857fe5b04604087015260208601516127109061171a9063ffffffff8085169061373416565b8161172157fe5b046060870152505b6117416103e8610c9261173c8787613734565b6137a7565b975061176f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6103e86137f8565b611827565b85516117b1906117848684613734565b8161178b57fe5b0487602001516117a4848761373490919063ffffffff16565b816117ab57fe5b04613929565b975086156118275760006117c58983612e0e565b90506117f4826117e2838a6040015161373490919063ffffffff16565b816117e957fe5b04876000015161393f565b6040870152606087015161182090839061180e9084613734565b8161181557fe5b04876020015161393f565b6060870152505b60008811611880576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806149d86022913960400191505060405180910390fd5b61188a89896137f8565b611894878661305e565b81156118a8576118a4878661394f565b6010555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600855509395945050505050565b600b5473ffffffffffffffffffffffffffffffffffffffff16331461197a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f444d4d3a20464f5242494444454e000000000000000000000000000000000000604482015290519081900360640190fd5b600c805473ffffffffffffffffffffffffffffffffffffffff9485167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600d805493909416921691909117909155600e805463ffffffff9092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60105481565b60076020526000908152604090205481565b60008060026008541415611adb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000611aea614891565b611af2612cd8565b600c54600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b158015611b7357600080fd5b505afa158015611b87573d6000803e3d6000fd5b505050506040513d6020811015611b9d57600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b158015611c1157600080fd5b505afa158015611c25573d6000803e3d6000fd5b505050506040513d6020811015611c3b57600080fd5b505185519091508210801590611c55575084602001518110155b611cc057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f444d4d3a20554e53594e435f5245534552564553000000000000000000000000604482015290519081900360640190fd5b6000611ccb30611a22565b90506000611cd988886135c5565b90506000611ce5611328565b905080611cf28487613734565b81611cf957fe5b049a5080611d078486613734565b81611d0e57fe5b04995060008b118015611d21575060008a115b611d76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061496d6022913960400191505060405180910390fd5b611d803084613975565b611da173ffffffffffffffffffffffffffffffffffffffff88168d8d612d7c565b611dc273ffffffffffffffffffffffffffffffffffffffff87168d8c612d7c565b611dca614891565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8a16916370a08231916024808301926020929190829003018186803b158015611e3657600080fd5b505afa158015611e4a573d6000803e3d6000fd5b505050506040513d6020811015611e6057600080fd5b50518152604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b158015611ed057600080fd5b505afa158015611ee4573d6000803e3d6000fd5b505050506040513d6020811015611efa57600080fd5b505160208201528915611fa25788518151600091611f4091611f1c9086613734565b81611f2357fe5b048b602001516117a486866020015161373490919063ffffffff16565b9050611f6f83611f5d838d6040015161373490919063ffffffff16565b81611f6457fe5b04836000015161393f565b604083015260608a0151611f9b908490611f899084613734565b81611f9057fe5b04836020015161393f565b6060830152505b611fac8a8261305e565b8215611fc057611fbc8a8261394f565b6010555b8c73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d819364968e8e604051808381526020018281526020019250505060405180910390a3505050505050505050506001600881905550915091565b600c54600d54604080517f95d89b41000000000000000000000000000000000000000000000000000000008152905160609373ffffffffffffffffffffffffffffffffffffffff90811693169183916395d89b4191600480820192600092909190829003018186803b1580156120b957600080fd5b505afa1580156120cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561211457600080fd5b810190808051604051939291908464010000000082111561213457600080fd5b90830190602082018581111561214957600080fd5b825164010000000081118282018810171561216357600080fd5b82525081516020918201929091019080838360005b83811015612190578181015183820152602001612178565b50505050905090810190601f1680156121bd5780820380516001836020036101000a031916815260200191505b506040525050508173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561220a57600080fd5b505afa15801561221e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561226557600080fd5b810190808051604051939291908464010000000082111561228557600080fd5b90830190602082018581111561229a57600080fd5b82516401000000008111828201881017156122b457600080fd5b82525081516020918201929091019080838360005b838110156122e15781810151838201526020016122c9565b50505050905090810190601f16801561230e5780820380516001836020036101000a031916815260200191505b5060405250505060405160200180807f444d4d2d4c5020000000000000000000000000000000000000000000000000008152506007018380519060200190808383602083106111b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611176565b60006112c36123996131f9565b846113c085604051806060016040528060258152602001614a8e60259139600160006123c36131f9565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918d16815292529020549190613514565b60006112c361240e6131f9565b8484613344565b6103e881565b6002600854141561248d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600855600e54600c54604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051612574938593612554936dffffffffffffffffffffffffffff9092169273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561252257600080fd5b505afa158015612536573d6000803e3d6000fd5b505050506040513d602081101561254c57600080fd5b505190612e82565b600c5473ffffffffffffffffffffffffffffffffffffffff169190612d7c565b600e54600d54604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051612635938593612615936e0100000000000000000000000000009092046dffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561252257600080fd5b600d5473ffffffffffffffffffffffffffffffffffffffff169190612d7c565b506001600855565b600b5473ffffffffffffffffffffffffffffffffffffffff1681565b600d5473ffffffffffffffffffffffffffffffffffffffff1681565b428410156126e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f45524332305065726d69743a2045585049524544000000000000000000000000604482015290519081900360640190fd5b60065473ffffffffffffffffffffffffffffffffffffffff80891660008181526007602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612845573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158015906128c057508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b61292b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20494e56414c49445f5349474e41545552450000604482015290519081900360640190fd5b6129368989896131fd565b505050505050505050565b600e54600f546dffffffffffffffffffffffffffff808316926e0100000000000000000000000000008082048316938381169391900416906000907c0100000000000000000000000000000000000000000000000000000000900463ffffffff166127108114156129b3578593508492505b60006129be43613abf565b90506129d26129cc82613c63565b83613e44565b925050509091929394565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b60065481565b60026008541415612a8d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000612a9c614891565b612aa4612cd8565b915091506000612ab483836135c5565b9050612abe614891565b600c54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015612b2f57600080fd5b505afa158015612b43573d6000803e3d6000fd5b505050506040513d6020811015612b5957600080fd5b50518152600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015612bce57600080fd5b505afa158015612be2573d6000803e3d6000fd5b505050506040513d6020811015612bf857600080fd5b505160208201528315612caf576000612c0f611328565b84518351919250600091612c4c9190612c289085613734565b81612c2f57fe5b0486602001516117a485876020015161373490919063ffffffff16565b9050612c7b82612c6983886040015161373490919063ffffffff16565b81612c7057fe5b04846000015161393f565b60408401526060850151612ca7908390612c959084613734565b81612c9c57fe5b04846020015161393f565b606084015250505b612cb9848261305e565b8115612ccd57612cc9848261394f565b6010555b505060016008555050565b6000612ce2614891565b600e546dffffffffffffffffffffffffffff80821683526e010000000000000000000000000000820416602083015263ffffffff7c0100000000000000000000000000000000000000000000000000000000909104166127101480159250612d7857600f546dffffffffffffffffffffffffffff80821660408401526e0100000000000000000000000000009091041660608201525b9091565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612e09908490613ea0565b505050565b6000828201838110156113c957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612ef357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600080612f1a88612f1487612f0e8a8c613734565b90613f78565b90612e0e565b90506000612f284383613ff9565b9050612f64612f3682613c63565b600e547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16613e44565b92506000612f7a86670de0b6b3a7640000613734565b9050612f90612f898b86613734565b8290612e82565b9050670de0b6b3a7640000810490506000612fb386670de0b6b3a7640000613734565b9050612fc2612f898b87613734565b670de0b6b3a764000090049050612fd98989613734565b612fe38383613734565b101561305057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f444d4d3a204b0000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050509695505050505050565b80516130699061434c565b600e80547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff9290921691909117905560208101516130b69061434c565b600e806101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555081156131a157805160408201511080159061310c57508060200151816060015110155b61311257fe5b61311f816040015161434c565b600f80547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff92909216919091179055606081015161316c9061434c565b600f600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055505b6040808201516060808401518451602080870151865195865290850192909252838501529082015290517f2f9d55abfefdfd4c3a83e00a1b419b3c2fe4b83100c559f0e2213e57f6e0bba99181900360800190a15050565b3390565b73ffffffffffffffffffffffffffffffffffffffff8316613269576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180614a406024913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166132d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806148ff6022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff83166133b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180614a1b6025913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821661341c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806148ba6023913960400191505060405180910390fd5b613427838383612e09565b613471816040518060600160405280602681526020016149216026913973ffffffffffffffffffffffffffffffffffffffff86166000908152602081905260409020549190613514565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822093909355908416815220546134ad9082612e0e565b73ffffffffffffffffffffffffffffffffffffffff8084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156135bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561358257818101518382015260200161356a565b50505050905090810190601f1680156135af5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000806000600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5cb2e16040518163ffffffff1660e01b8152600401604080518083038186803b15801561363157600080fd5b505afa158015613645573d6000803e3d6000fd5b505050506040513d604081101561365b57600080fd5b50805160209091015160105473ffffffffffffffffffffffffffffffffffffffff831615801596509294509092509061371f57801561371a5760006136a361173c888861394f565b905060006136b0836137a7565b9050808211156137175760006136df61ffff86166136d96136d18686612e82565b6136d9611328565b90613734565b905060006136f36113886136d98686612e0e565b9050600081838161370057fe5b04905080156137135761371388826137f8565b5050505b50505b61372b565b801561372b5760006010555b50505092915050565b600082613743575060006112c7565b8282028284828161375057fe5b04146113c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061498f6021913960400191505060405180910390fd5b600060038211156137ea575080600160028204015b818110156137e4578091506002818285816137d357fe5b0401816137dc57fe5b0490506137bc565b50611a49565b8115611a4957506001919050565b73ffffffffffffffffffffffffffffffffffffffff821661387a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61388660008383612e09565b6002546138939082612e0e565b60025573ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020546138c69082612e0e565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b600081831061393857816113c9565b5090919050565b60008183101561393857816113c9565b6000826139635760208201518251026113c9565b50606081015160409091015102919050565b73ffffffffffffffffffffffffffffffffffffffff82166139e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806149fa6021913960400191505060405180910390fd5b6139ed82600083612e09565b613a37816040518060600160405280602281526020016148dd6022913973ffffffffffffffffffffffffffffffffffffffff85166000908152602081905260409020549190613514565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902055600254613a6a9082612e82565b60025560408051828152905160009173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600a5460009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16820380613b3057600954613b28906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004166143cf565b915050611a49565b600954600090613b77906fffffffffffffffffffffffffffffffff16611519671bc16d674ec800005b600a54919004906fffffffffffffffffffffffffffffffff166143f1565b600954909150600090613bbb9070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612a31671bc16d674ec80000613b59565b9050613c0b613c047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501611519671bc16d674ec800005b04670de0b6b3a76400000390614452565b8390614523565b9150613c4e613c477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501612a31671bc16d674ec80000613bf3565b8290614523565b9050613c5a82826143cf565b95945050505050565b6000671480cc142da92a848210613c825750661550f7dca70000611a49565b670de0b6b3a76400008210613d8a576710a741a462780000821115613d2b577fffffffffffffffffffffffffffffffffffffffffffffffffef58be5b9d88000082016000613cd1826003614452565b9050612710613d1a613cf1846009680d8d726b7177a800005b0490614523565b612f14613d0a85601b69043c33c1937564800000613cea565b6801fa48421ec7b1ed0990612e0e565b81613d2157fe5b0492505050611a49565b6710a741a4627800008290036000613d44826003614452565b9050612710613d1a613d61846009680d8d726b7177a80000613cea565b610c92613d7a85601b69043c33c1937564800000613cea565b6801fa48421ec7b1ed0990612e82565b6000670b9a1192183a00008311613dac57670b9a1192183a0000839003613dd0565b7ffffffffffffffffffffffffffffffffffffffffffffffffff465ee6de7c6000083015b9050613ddd816002614452565b90506000613e06613df48365b5e620f48000612e0e565b612f0e674563918244f4000085613734565b9050670b9a1192183a0000841115613e2e57612710613d1a6801161163ae0de59a9283612e0e565b612710613d1a6801161163ae0de59a9283612e82565b6000614e208263ffffffff1611613e5c5750816112c7565b61c3508263ffffffff1611613e7a57601e601484025b0490506112c7565b62030d408263ffffffff1611613e9557601e600a8402613e72565b601e60048402613e72565b6060613f02826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661453f9092919063ffffffff16565b805190915015612e0957808060200190516020811015613f2157600080fd5b5051612e09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180614a64602a913960400191505060405180910390fd5b6000808211613fe857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381613ff157fe5b049392505050565b600a5460009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff168303806140f457600a5461408a9061404f906fffffffffffffffffffffffffffffffff1685612e0e565b6040518060400160405280601a81526020017f766f6c756d6520657863656564732076616c69642072616e6765000000000000815250614556565b600a80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9283161790556009546140ec91818116917001000000000000000000000000000000009004166143cf565b9150506112c7565b600a546009546fffffffffffffffffffffffffffffffff918216916000916141289116611519671bc16d674ec80000613b59565b60095490915060009061416c9070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612a31671bc16d674ec80000613b59565b90506141a8613c047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601611519671bc16d674ec80000613bf3565b91506141e4613c477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601612a31671bc16d674ec80000613bf3565b90506141ef826145da565b600980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055614239816145da565b600980546fffffffffffffffffffffffffffffffff928316700100000000000000000000000000000000029216919091179055614275866145da565b600a80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556142bf876145da565b600a80546fffffffffffffffffffffffffffffffff9283167001000000000000000000000000000000000290831617905560408051848152602081018490529185168282015260608201869052517f96e2c334d3c0fa98c8b728ee84471864ffe5b28e05f46e52f8a469d0ab3a8b8b9181900360800190a161434182826143cf565b979650505050505050565b60006dffffffffffffffffffffffffffff8211156143cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f444d4d3a204f564552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b5090565b6000816143de575060006112c7565b81670de0b6b3a7640000840281613ff157fe5b6000670de0b6b3a7640000831061440457fe5b670de0b6b3a7640000826fffffffffffffffffffffffffffffffff168402856fffffffffffffffffffffffffffffffff1685670de0b6b3a76400000302018161444957fe5b04949350505050565b6000670de0b6b3a76400008311156144cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d6174684578743a2078203e20505245434953494f4e00000000000000000000604482015290519081900360640190fd5b600282066144e157670de0b6b3a76400006144e3565b825b90506002820491505b81156112c757670de0b6b3a7640000838002049250600282061561451857670de0b6b3a7640000908302045b6002820491506144ec565b6000670de0b6b3a76400006145388484613734565b81613ff157fe5b606061454e848460008561465b565b949350505050565b6000816fffffffffffffffffffffffffffffffff8411156145d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815283516024840152835190928392604490910191908501908083836000831561358257818101518382015260200161356a565b509192915050565b60006fffffffffffffffffffffffffffffffff8211156143cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6f766572666c6f772075696e7431323800000000000000000000000000000000604482015290519081900360640190fd5b6060824710156146b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806149476026913960400191505060405180910390fd5b6146bf8561480b565b61472a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600060608673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b6020831061479457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614757565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146147f6576040519150601f19603f3d011682016040523d82523d6000602084013e6147fb565b606091505b5091509150614341828286614811565b3b151590565b606083156148205750816113c9565b8251156148305782518084602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815284516024840152845185939192839260440191908501908083836000831561358257818101518382015260200161356a565b604051806080016040528060008152602001600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c444d4d3a20494e53554646494349454e545f4c49515549444954595f4255524e4544536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365444d4d3a20494e53554646494349454e545f4c49515549444954595f4d494e54454445524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122049f6f8528b3e4b37e72b9bde0aa804ce74fda17a3dc51ea424bf85cf5943707e64736f6c634300060c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80637464fc3d11610104578063bc25cf77116100a2578063d669402711610071578063d669402714610736578063dd62ed3e14610780578063f698da25146107bb578063fff6cae9146107c3576101da565b8063bc25cf7714610695578063c45a0155146106c8578063d21220a7146106d0578063d505accf146106d8576101da565b806395d89b41116100de57806395d89b4114610613578063a457c2d71461061b578063a9059cbb14610654578063ba9a7a561461068d576101da565b80637464fc3d1461058c5780637ecebe001461059457806389afcb44146105c7576101da565b806323b872dd1161017c57806349386b161161014b57806349386b16146104bb5780636a627842146104dc5780636ecf2b221461050f57806370a0823114610559576101da565b806323b872dd1461041957806330adf81f1461045c578063313ce567146104645780633950935114610482576101da565b8063095ea7b3116101b8578063095ea7b31461033c5780630d94d50b146103895780630dfe1681146103ce57806318160ddd146103ff576101da565b8063022c0d9f146101df57806306fdde031461027a5780630902f1ac146102f7575b600080fd5b610278600480360360808110156101f557600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b5090925090506107cb565b005b610282610e6a565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102bc5781810151838201526020016102a4565b50505050905090810190601f1680156102e95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102ff611282565b60405180836dffffffffffffffffffffffffffff168152602001826dffffffffffffffffffffffffffff1681526020019250505060405180910390f35b6103756004803603604081101561035257600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356112af565b604080519115158252519081900360200190f35b6103916112cd565b604080516fffffffffffffffffffffffffffffffff9586168152938516602085015291841683830152909216606082015290519081900360800190f35b6103d661130c565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b610407611328565b60408051918252519081900360200190f35b6103756004803603606081101561042f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135909116906040013561132e565b6104076113d0565b61046c6113f4565b6040805160ff9092168252519081900360200190f35b6103756004803603604081101561049857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356113fd565b6104c3611458565b6040805163ffffffff9092168252519081900360200190f35b610407600480360360208110156104f257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611484565b6102786004803603606081101561052557600080fd5b50803573ffffffffffffffffffffffffffffffffffffffff908116916020810135909116906040013563ffffffff166118f4565b6104076004803603602081101561056f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a22565b610407611a4e565b610407600480360360208110156105aa57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a54565b6105fa600480360360208110156105dd57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611a66565b6040805192835260208301919091528051918290030190f35b610282612044565b6103756004803603604081101561063157600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561238c565b6103756004803603604081101561066a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612401565b610407612415565b610278600480360360208110156106ab57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661241b565b6103d661263d565b6103d6612659565b610278600480360360e08110156106ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135612675565b61073e612941565b604080516dffffffffffffffffffffffffffff968716815294861660208601529285168484015293166060830152608082019290925290519081900360a00190f35b6104076004803603604081101561079657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166129dd565b610407612a15565b610278612a1b565b6002600854141561083d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600855841515806108505750600084115b6108bb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f444d4d3a20494e53554646494349454e545f4f55545055545f414d4f554e5400604482015290519081900360640190fd5b60006108c5614891565b6108cd612cd8565b80519193509150871080156108e55750806020015186105b61095057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f444d4d3a20494e53554646494349454e545f4c49515549444954590000000000604482015290519081900360640190fd5b610958614891565b600c54600d5473ffffffffffffffffffffffffffffffffffffffff9182169190811690881682148015906109b857508073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614155b610a2357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f444d4d3a20494e56414c49445f544f0000000000000000000000000000000000604482015290519081900360640190fd5b8915610a4a57610a4a73ffffffffffffffffffffffffffffffffffffffff8316898c612d7c565b8815610a7157610a7173ffffffffffffffffffffffffffffffffffffffff8216898b612d7c565b8515610b3d578773ffffffffffffffffffffffffffffffffffffffff166381279c7e338c8c8b8b6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b158015610b2457600080fd5b505af1158015610b38573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610ba957600080fd5b505afa158015610bbd573d6000803e3d6000fd5b505050506040513d6020811015610bd357600080fd5b50518352604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8316916370a08231916024808301926020929190829003018186803b158015610c4357600080fd5b505afa158015610c57573d6000803e3d6000fd5b505050506040513d6020811015610c6d57600080fd5b505160208401528415610cc157835183516040860151610c989291610c929190612e0e565b90612e82565b6040840152602080850151908401516060860151610cbb9291610c929190612e0e565b60608401525b5050815181516000918a900310610cd9576000610ce4565b82518251908a900390035b9050600088846020015103836020015111610d00576000610d0e565b888460200151038360200151035b90506000821180610d1f5750600081115b610d8a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f444d4d3a20494e53554646494349454e545f494e5055545f414d4f554e540000604482015290519081900360640190fd5b6000610de4838388610d9d578751610da3565b87604001515b89610db2578860200151610db8565b88606001515b8a610dc4578851610dca565b88604001515b8b610dd9578960200151610ddf565b89606001515b612ef9565b9050610df0868561305e565b60408051848152602081018490528082018d9052606081018c905260808101839052905173ffffffffffffffffffffffffffffffffffffffff8b169133917f606ecd02b3e3b4778f8e97b2e03351de14224efaa5fa64e62200afc9395c24999181900360a00190a350506001600855505050505050505050565b600c54600d54604080517f95d89b41000000000000000000000000000000000000000000000000000000008152905160609373ffffffffffffffffffffffffffffffffffffffff90811693169183916395d89b4191600480820192600092909190829003018186803b158015610edf57600080fd5b505afa158015610ef3573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526020811015610f3a57600080fd5b8101908080516040519392919084640100000000821115610f5a57600080fd5b908301906020820185811115610f6f57600080fd5b8251640100000000811182820188101715610f8957600080fd5b82525081516020918201929091019080838360005b83811015610fb6578181015183820152602001610f9e565b50505050905090810190601f168015610fe35780820380516001836020036101000a031916815260200191505b506040525050508173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561103057600080fd5b505afa158015611044573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561108b57600080fd5b81019080805160405193929190846401000000008211156110ab57600080fd5b9083019060208201858111156110c057600080fd5b82516401000000008111828201881017156110da57600080fd5b82525081516020918201929091019080838360005b838110156111075781810151838201526020016110ef565b50505050905090810190601f1680156111345780820380516001836020036101000a031916815260200191505b5060405250505060405160200180807f4b79626572444d4d204c50200000000000000000000000000000000000000000815250600c0183805190602001908083835b602083106111b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611176565b6001836020036101000a038019825116818451168082178552505050505050905001807f2d0000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b6020831061124657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611209565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529250505090565b600e546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006112c36112bc6131f9565b84846131fd565b5060015b92915050565b600954600a546fffffffffffffffffffffffffffffffff8083169370010000000000000000000000000000000093849004821693838316930490911690565b600c5473ffffffffffffffffffffffffffffffffffffffff1681565b60025490565b600061133b848484613344565b6113c5846113476131f9565b6113c0856040518060600160405280602881526020016149b06028913973ffffffffffffffffffffffffffffffffffffffff8a166000908152600160205260408120906113926131f9565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020549190613514565b6131fd565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60055460ff1690565b60006112c361140a6131f9565b846113c0856001600061141b6131f9565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918c168152925290205490612e0e565b600e547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1681565b6000600260085414156114f857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000611507614891565b61150f612cd8565b9150915061151b614891565b600c54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b15801561158c57600080fd5b505afa1580156115a0573d6000803e3d6000fd5b505050506040513d60208110156115b657600080fd5b50518152600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b15801561162b57600080fd5b505afa15801561163f573d6000803e3d6000fd5b505050506040513d602081101561165557600080fd5b505160208201528151815160009161166d9190612e82565b9050600061168c84602001518460200151612e8290919063ffffffff16565b9050600061169a86866135c5565b905060006116a6611328565b90508061177457861561172957600e54855163ffffffff7c0100000000000000000000000000000000000000000000000000000000909204821691612710916116f191849061373416565b816116f857fe5b04604087015260208601516127109061171a9063ffffffff8085169061373416565b8161172157fe5b046060870152505b6117416103e8610c9261173c8787613734565b6137a7565b975061176f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6103e86137f8565b611827565b85516117b1906117848684613734565b8161178b57fe5b0487602001516117a4848761373490919063ffffffff16565b816117ab57fe5b04613929565b975086156118275760006117c58983612e0e565b90506117f4826117e2838a6040015161373490919063ffffffff16565b816117e957fe5b04876000015161393f565b6040870152606087015161182090839061180e9084613734565b8161181557fe5b04876020015161393f565b6060870152505b60008811611880576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806149d86022913960400191505060405180910390fd5b61188a89896137f8565b611894878661305e565b81156118a8576118a4878661394f565b6010555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600855509395945050505050565b600b5473ffffffffffffffffffffffffffffffffffffffff16331461197a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f444d4d3a20464f5242494444454e000000000000000000000000000000000000604482015290519081900360640190fd5b600c805473ffffffffffffffffffffffffffffffffffffffff9485167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600d805493909416921691909117909155600e805463ffffffff9092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60105481565b60076020526000908152604090205481565b60008060026008541415611adb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000611aea614891565b611af2612cd8565b600c54600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b158015611b7357600080fd5b505afa158015611b87573d6000803e3d6000fd5b505050506040513d6020811015611b9d57600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b158015611c1157600080fd5b505afa158015611c25573d6000803e3d6000fd5b505050506040513d6020811015611c3b57600080fd5b505185519091508210801590611c55575084602001518110155b611cc057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f444d4d3a20554e53594e435f5245534552564553000000000000000000000000604482015290519081900360640190fd5b6000611ccb30611a22565b90506000611cd988886135c5565b90506000611ce5611328565b905080611cf28487613734565b81611cf957fe5b049a5080611d078486613734565b81611d0e57fe5b04995060008b118015611d21575060008a115b611d76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061496d6022913960400191505060405180910390fd5b611d803084613975565b611da173ffffffffffffffffffffffffffffffffffffffff88168d8d612d7c565b611dc273ffffffffffffffffffffffffffffffffffffffff87168d8c612d7c565b611dca614891565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8a16916370a08231916024808301926020929190829003018186803b158015611e3657600080fd5b505afa158015611e4a573d6000803e3d6000fd5b505050506040513d6020811015611e6057600080fd5b50518152604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b158015611ed057600080fd5b505afa158015611ee4573d6000803e3d6000fd5b505050506040513d6020811015611efa57600080fd5b505160208201528915611fa25788518151600091611f4091611f1c9086613734565b81611f2357fe5b048b602001516117a486866020015161373490919063ffffffff16565b9050611f6f83611f5d838d6040015161373490919063ffffffff16565b81611f6457fe5b04836000015161393f565b604083015260608a0151611f9b908490611f899084613734565b81611f9057fe5b04836020015161393f565b6060830152505b611fac8a8261305e565b8215611fc057611fbc8a8261394f565b6010555b8c73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d819364968e8e604051808381526020018281526020019250505060405180910390a3505050505050505050506001600881905550915091565b600c54600d54604080517f95d89b41000000000000000000000000000000000000000000000000000000008152905160609373ffffffffffffffffffffffffffffffffffffffff90811693169183916395d89b4191600480820192600092909190829003018186803b1580156120b957600080fd5b505afa1580156120cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561211457600080fd5b810190808051604051939291908464010000000082111561213457600080fd5b90830190602082018581111561214957600080fd5b825164010000000081118282018810171561216357600080fd5b82525081516020918201929091019080838360005b83811015612190578181015183820152602001612178565b50505050905090810190601f1680156121bd5780820380516001836020036101000a031916815260200191505b506040525050508173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561220a57600080fd5b505afa15801561221e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561226557600080fd5b810190808051604051939291908464010000000082111561228557600080fd5b90830190602082018581111561229a57600080fd5b82516401000000008111828201881017156122b457600080fd5b82525081516020918201929091019080838360005b838110156122e15781810151838201526020016122c9565b50505050905090810190601f16801561230e5780820380516001836020036101000a031916815260200191505b5060405250505060405160200180807f444d4d2d4c5020000000000000000000000000000000000000000000000000008152506007018380519060200190808383602083106111b357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611176565b60006112c36123996131f9565b846113c085604051806060016040528060258152602001614a8e60259139600160006123c36131f9565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918d16815292529020549190613514565b60006112c361240e6131f9565b8484613344565b6103e881565b6002600854141561248d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600855600e54600c54604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051612574938593612554936dffffffffffffffffffffffffffff9092169273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561252257600080fd5b505afa158015612536573d6000803e3d6000fd5b505050506040513d602081101561254c57600080fd5b505190612e82565b600c5473ffffffffffffffffffffffffffffffffffffffff169190612d7c565b600e54600d54604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051612635938593612615936e0100000000000000000000000000009092046dffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561252257600080fd5b600d5473ffffffffffffffffffffffffffffffffffffffff169190612d7c565b506001600855565b600b5473ffffffffffffffffffffffffffffffffffffffff1681565b600d5473ffffffffffffffffffffffffffffffffffffffff1681565b428410156126e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f45524332305065726d69743a2045585049524544000000000000000000000000604482015290519081900360640190fd5b60065473ffffffffffffffffffffffffffffffffffffffff80891660008181526007602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612845573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158015906128c057508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b61292b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20494e56414c49445f5349474e41545552450000604482015290519081900360640190fd5b6129368989896131fd565b505050505050505050565b600e54600f546dffffffffffffffffffffffffffff808316926e0100000000000000000000000000008082048316938381169391900416906000907c0100000000000000000000000000000000000000000000000000000000900463ffffffff166127108114156129b3578593508492505b60006129be43613abf565b90506129d26129cc82613c63565b83613e44565b925050509091929394565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b60065481565b60026008541415612a8d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026008556000612a9c614891565b612aa4612cd8565b915091506000612ab483836135c5565b9050612abe614891565b600c54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015612b2f57600080fd5b505afa158015612b43573d6000803e3d6000fd5b505050506040513d6020811015612b5957600080fd5b50518152600d54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015612bce57600080fd5b505afa158015612be2573d6000803e3d6000fd5b505050506040513d6020811015612bf857600080fd5b505160208201528315612caf576000612c0f611328565b84518351919250600091612c4c9190612c289085613734565b81612c2f57fe5b0486602001516117a485876020015161373490919063ffffffff16565b9050612c7b82612c6983886040015161373490919063ffffffff16565b81612c7057fe5b04846000015161393f565b60408401526060850151612ca7908390612c959084613734565b81612c9c57fe5b04846020015161393f565b606084015250505b612cb9848261305e565b8115612ccd57612cc9848261394f565b6010555b505060016008555050565b6000612ce2614891565b600e546dffffffffffffffffffffffffffff80821683526e010000000000000000000000000000820416602083015263ffffffff7c0100000000000000000000000000000000000000000000000000000000909104166127101480159250612d7857600f546dffffffffffffffffffffffffffff80821660408401526e0100000000000000000000000000009091041660608201525b9091565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612e09908490613ea0565b505050565b6000828201838110156113c957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612ef357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600080612f1a88612f1487612f0e8a8c613734565b90613f78565b90612e0e565b90506000612f284383613ff9565b9050612f64612f3682613c63565b600e547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16613e44565b92506000612f7a86670de0b6b3a7640000613734565b9050612f90612f898b86613734565b8290612e82565b9050670de0b6b3a7640000810490506000612fb386670de0b6b3a7640000613734565b9050612fc2612f898b87613734565b670de0b6b3a764000090049050612fd98989613734565b612fe38383613734565b101561305057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f444d4d3a204b0000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050509695505050505050565b80516130699061434c565b600e80547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff9290921691909117905560208101516130b69061434c565b600e806101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555081156131a157805160408201511080159061310c57508060200151816060015110155b61311257fe5b61311f816040015161434c565b600f80547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff92909216919091179055606081015161316c9061434c565b600f600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055505b6040808201516060808401518451602080870151865195865290850192909252838501529082015290517f2f9d55abfefdfd4c3a83e00a1b419b3c2fe4b83100c559f0e2213e57f6e0bba99181900360800190a15050565b3390565b73ffffffffffffffffffffffffffffffffffffffff8316613269576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180614a406024913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166132d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806148ff6022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff83166133b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180614a1b6025913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821661341c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806148ba6023913960400191505060405180910390fd5b613427838383612e09565b613471816040518060600160405280602681526020016149216026913973ffffffffffffffffffffffffffffffffffffffff86166000908152602081905260409020549190613514565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822093909355908416815220546134ad9082612e0e565b73ffffffffffffffffffffffffffffffffffffffff8084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156135bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561358257818101518382015260200161356a565b50505050905090810190601f1680156135af5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000806000600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5cb2e16040518163ffffffff1660e01b8152600401604080518083038186803b15801561363157600080fd5b505afa158015613645573d6000803e3d6000fd5b505050506040513d604081101561365b57600080fd5b50805160209091015160105473ffffffffffffffffffffffffffffffffffffffff831615801596509294509092509061371f57801561371a5760006136a361173c888861394f565b905060006136b0836137a7565b9050808211156137175760006136df61ffff86166136d96136d18686612e82565b6136d9611328565b90613734565b905060006136f36113886136d98686612e0e565b9050600081838161370057fe5b04905080156137135761371388826137f8565b5050505b50505b61372b565b801561372b5760006010555b50505092915050565b600082613743575060006112c7565b8282028284828161375057fe5b04146113c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061498f6021913960400191505060405180910390fd5b600060038211156137ea575080600160028204015b818110156137e4578091506002818285816137d357fe5b0401816137dc57fe5b0490506137bc565b50611a49565b8115611a4957506001919050565b73ffffffffffffffffffffffffffffffffffffffff821661387a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61388660008383612e09565b6002546138939082612e0e565b60025573ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020546138c69082612e0e565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b600081831061393857816113c9565b5090919050565b60008183101561393857816113c9565b6000826139635760208201518251026113c9565b50606081015160409091015102919050565b73ffffffffffffffffffffffffffffffffffffffff82166139e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806149fa6021913960400191505060405180910390fd5b6139ed82600083612e09565b613a37816040518060600160405280602281526020016148dd6022913973ffffffffffffffffffffffffffffffffffffffff85166000908152602081905260409020549190613514565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902055600254613a6a9082612e82565b60025560408051828152905160009173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600a5460009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16820380613b3057600954613b28906fffffffffffffffffffffffffffffffff808216917001000000000000000000000000000000009004166143cf565b915050611a49565b600954600090613b77906fffffffffffffffffffffffffffffffff16611519671bc16d674ec800005b600a54919004906fffffffffffffffffffffffffffffffff166143f1565b600954909150600090613bbb9070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612a31671bc16d674ec80000613b59565b9050613c0b613c047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501611519671bc16d674ec800005b04670de0b6b3a76400000390614452565b8390614523565b9150613c4e613c477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501612a31671bc16d674ec80000613bf3565b8290614523565b9050613c5a82826143cf565b95945050505050565b6000671480cc142da92a848210613c825750661550f7dca70000611a49565b670de0b6b3a76400008210613d8a576710a741a462780000821115613d2b577fffffffffffffffffffffffffffffffffffffffffffffffffef58be5b9d88000082016000613cd1826003614452565b9050612710613d1a613cf1846009680d8d726b7177a800005b0490614523565b612f14613d0a85601b69043c33c1937564800000613cea565b6801fa48421ec7b1ed0990612e0e565b81613d2157fe5b0492505050611a49565b6710a741a4627800008290036000613d44826003614452565b9050612710613d1a613d61846009680d8d726b7177a80000613cea565b610c92613d7a85601b69043c33c1937564800000613cea565b6801fa48421ec7b1ed0990612e82565b6000670b9a1192183a00008311613dac57670b9a1192183a0000839003613dd0565b7ffffffffffffffffffffffffffffffffffffffffffffffffff465ee6de7c6000083015b9050613ddd816002614452565b90506000613e06613df48365b5e620f48000612e0e565b612f0e674563918244f4000085613734565b9050670b9a1192183a0000841115613e2e57612710613d1a6801161163ae0de59a9283612e0e565b612710613d1a6801161163ae0de59a9283612e82565b6000614e208263ffffffff1611613e5c5750816112c7565b61c3508263ffffffff1611613e7a57601e601484025b0490506112c7565b62030d408263ffffffff1611613e9557601e600a8402613e72565b601e60048402613e72565b6060613f02826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661453f9092919063ffffffff16565b805190915015612e0957808060200190516020811015613f2157600080fd5b5051612e09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180614a64602a913960400191505060405180910390fd5b6000808211613fe857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381613ff157fe5b049392505050565b600a5460009070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff168303806140f457600a5461408a9061404f906fffffffffffffffffffffffffffffffff1685612e0e565b6040518060400160405280601a81526020017f766f6c756d6520657863656564732076616c69642072616e6765000000000000815250614556565b600a80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9283161790556009546140ec91818116917001000000000000000000000000000000009004166143cf565b9150506112c7565b600a546009546fffffffffffffffffffffffffffffffff918216916000916141289116611519671bc16d674ec80000613b59565b60095490915060009061416c9070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612a31671bc16d674ec80000613b59565b90506141a8613c047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601611519671bc16d674ec80000613bf3565b91506141e4613c477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601612a31671bc16d674ec80000613bf3565b90506141ef826145da565b600980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055614239816145da565b600980546fffffffffffffffffffffffffffffffff928316700100000000000000000000000000000000029216919091179055614275866145da565b600a80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556142bf876145da565b600a80546fffffffffffffffffffffffffffffffff9283167001000000000000000000000000000000000290831617905560408051848152602081018490529185168282015260608201869052517f96e2c334d3c0fa98c8b728ee84471864ffe5b28e05f46e52f8a469d0ab3a8b8b9181900360800190a161434182826143cf565b979650505050505050565b60006dffffffffffffffffffffffffffff8211156143cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f444d4d3a204f564552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b5090565b6000816143de575060006112c7565b81670de0b6b3a7640000840281613ff157fe5b6000670de0b6b3a7640000831061440457fe5b670de0b6b3a7640000826fffffffffffffffffffffffffffffffff168402856fffffffffffffffffffffffffffffffff1685670de0b6b3a76400000302018161444957fe5b04949350505050565b6000670de0b6b3a76400008311156144cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d6174684578743a2078203e20505245434953494f4e00000000000000000000604482015290519081900360640190fd5b600282066144e157670de0b6b3a76400006144e3565b825b90506002820491505b81156112c757670de0b6b3a7640000838002049250600282061561451857670de0b6b3a7640000908302045b6002820491506144ec565b6000670de0b6b3a76400006145388484613734565b81613ff157fe5b606061454e848460008561465b565b949350505050565b6000816fffffffffffffffffffffffffffffffff8411156145d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815283516024840152835190928392604490910191908501908083836000831561358257818101518382015260200161356a565b509192915050565b60006fffffffffffffffffffffffffffffffff8211156143cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6f766572666c6f772075696e7431323800000000000000000000000000000000604482015290519081900360640190fd5b6060824710156146b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806149476026913960400191505060405180910390fd5b6146bf8561480b565b61472a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600060608673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b6020831061479457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614757565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146147f6576040519150601f19603f3d011682016040523d82523d6000602084013e6147fb565b606091505b5091509150614341828286614811565b3b151590565b606083156148205750816113c9565b8251156148305782518084602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815284516024840152845185939192839260440191908501908083836000831561358257818101518382015260200161356a565b604051806080016040528060008152602001600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c444d4d3a20494e53554646494349454e545f4c49515549444954595f4255524e4544536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365444d4d3a20494e53554646494349454e545f4c49515549444954595f4d494e54454445524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122049f6f8528b3e4b37e72b9bde0aa804ce74fda17a3dc51ea424bf85cf5943707e64736f6c634300060c0033
Deployed Bytecode Sourcemap
52101:15783:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58443:2397;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;58443:2397:0;;-1:-1:-1;58443:2397:0;-1:-1:-1;58443:2397:0;:::i;:::-;;63232:302;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63061:163;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34834:169;;;;;;;;;;;;;;;;-1:-1:-1;34834:169:0;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;47983:401;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52725:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;33787:108;;;:::i;:::-;;;;;;;;;;;;;;;;35485:321;;;;;;;;;;;;;;;;-1:-1:-1;35485:321:0;;;;;;;;;;;;;;;;;;:::i;42289:117::-;;;:::i;33631:91::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;36215:218;;;;;;;;;;;;;;;;-1:-1:-1;36215:218:0;;;;;;;;;:::i;52934:29::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;54343:1812;;;;;;;;;;;;;;;;-1:-1:-1;54343:1812:0;;;;:::i;53932:268::-;;;;;;;;;;;;;;;;-1:-1:-1;53932:268:0;;;;;;;;;;;;;;;;;;;;;:::i;33958:127::-;;;;;;;;;;;;;;;;-1:-1:-1;33958:127:0;;;;:::i;53195:29::-;;;:::i;42415:41::-;;;;;;;;;;;;;;;;-1:-1:-1;42415:41:0;;;;:::i;56363:1948::-;;;;;;;;;;;;;;;;-1:-1:-1;56363:1948:0;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;63542:299;;;:::i;36936:269::-;;;;;;;;;;;;;;;;-1:-1:-1;36936:269:0;;;;;;;;;:::i;34298:175::-;;;;;;;;;;;;;;;;-1:-1:-1;34298:175:0;;;;;;;;;:::i;52539:49::-;;;:::i;60895:218::-;;;;;;;;;;;;;;;;-1:-1:-1;60895:218:0;;;;:::i;52683:35::-;;;:::i;52761:29::-;;;:::i;43096:839::-;;;;;;;;;;;;;;;;-1:-1:-1;43096:839:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;62209:772::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34536:151;;;;;;;;;;;;;;;;-1:-1:-1;34536:151:0;;;;;;;;;;;:::i;42147:30::-;;;:::i;61168:973::-;;;:::i;58443:2397::-;10117:1;10723:7;;:19;;10715:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10117:1;10856:7;:18;58631:14;;;;:32:::1;;;58662:1;58649:10;:14;58631:32;58623:76;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;58711:14;58727:23;;:::i;:::-;58754:17;:15;:17::i;:::-;58832:13:::0;;58710:61;;-1:-1:-1;58710:61:0;-1:-1:-1;58819:26:0;::::1;:56:::0;::::1;;;;58862:4;:13;;;58849:10;:26;58819:56;58797:133;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;58943:26;;:::i;:::-;59080:6;::::0;59118::::1;::::0;59080::::1;::::0;;::::1;::::0;59118;;::::1;::::0;59147:22;::::1;::::0;::::1;::::0;::::1;::::0;:48:::1;;;59187:7;59173:22;;:2;:22;;;;59147:48;59139:76;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;59234:14:::0;;59230:56:::1;;59250:36;:20;::::0;::::1;59271:2:::0;59275:10;59250:20:::1;:36::i;:::-;59339:14:::0;;59335:56:::1;;59355:36;:20;::::0;::::1;59376:2:::0;59380:10;59355:20:::1;:36::i;:::-;59444:23:::0;;59440:122:::1;;59497:2;59486:26;;;59513:10;59525;59537;59549:12;;59486:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;59440:122;59596:32;::::0;;;;;59622:4:::1;59596:32;::::0;::::1;::::0;;;:17:::1;::::0;::::1;::::0;::::1;::::0;:32;;;;;::::1;::::0;;;;;;;;:17;:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;59596:32:0;59577:51;;59662:32:::1;::::0;;;;;59688:4:::1;59662:32;::::0;::::1;::::0;;;:17:::1;::::0;::::1;::::0;::::1;::::0;:32;;;;;59596::::1;::::0;59662;;;;;;;:17;:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;59662:32:0;::::1;59643:16:::0;::::1;:51:::0;59709:219;::::1;;;59804:13:::0;;59782:16;;59763:14:::1;::::0;::::1;::::0;:55:::1;::::0;59804:13;59763:36:::1;::::0;:14;:18:::1;:36::i;:::-;:40:::0;::::1;:55::i;:::-;59743:17;::::0;::::1;:75:::0;59898:13:::1;::::0;;::::1;::::0;59876:16;;::::1;::::0;59857:14:::1;::::0;::::1;::::0;:55:::1;::::0;59898:13;59857:36:::1;::::0;:14;:18:::1;:36::i;:55::-;59837:17;::::0;::::1;:75:::0;59709:219:::1;-1:-1:-1::0;;59988:13:0;;59969:16;;59949:17:::1;::::0;59988:26;;::::1;-1:-1:-1::0;59969:125:0::1;;60093:1;59969:125;;;60050:13:::0;;60030:16;;60050:26;;;::::1;60030:47:::0;::::1;59969:125;59949:145;;60105:17;60160:10;60144:4;:13;;;:26;60125:7;:16;;;:45;:125;;60249:1;60125:125;;;60222:10;60206:4;:13;;;:26;60186:7;:16;;;:47;60125:125;60105:145;;60281:1;60269:9;:13;:30;;;;60298:1;60286:9;:13;60269:30;60261:73;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;60345:22;60370:324;60410:9;60434;60458;:42;;60487:13:::0;;60458:42:::1;;;60470:4;:14;;;60458:42;60515:9;:42;;60544:4;:13;;;60515:42;;;60527:4;:14;;;60515:42;60572:9;:48;;60604:16:::0;;60572:48:::1;;;60584:7;:17;;;60572:48;60635:9;:48;;60667:7;:16;;;60635:48;;;60647:7;:17;;;60635:48;60370:25;:324::i;:::-;60345:349;;60707:27;60715:9;60726:7;60707;:27::i;:::-;60750:82;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;;;;;;;;;;;::::1;::::0;::::1;::::0;60755:10:::1;::::0;60750:82:::1;::::0;;;;;;;::::1;-1:-1:-1::0;;10073:1:0;11035:7;:22;-1:-1:-1;;;;;;;;;58443:2397:0:o;63232:302::-;63352:6;;63419;;63485:16;;;;;;;;63278:13;;63352:6;;;;;63419;;63352;;63485:14;;:16;;;;;63304:22;;63485:16;;;;;;;;63352:6;63485:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63485:16:0;;;;;;;;;;-1:-1:-1;63485:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63508:7;:14;;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63508:16:0;;;;;;;;;;-1:-1:-1;63508:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63452:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63438:88;;;;63232:302;:::o;63061:163::-;63177:8;;;;;;;63208;;;;;;63061:163::o;34834:169::-;34917:4;34934:39;34943:12;:10;:12::i;:::-;34957:7;34966:6;34934:8;:39::i;:::-;-1:-1:-1;34991:4:0;34834:169;;;;;:::o;47983:401::-;48245:8;;48315:18;;48245:8;;;;;48275:7;;;;;;;;48315:18;;;;48362:14;;;;;47983:401::o;52725:29::-;;;;;;:::o;33787:108::-;33875:12;;33787:108;:::o;35485:321::-;35591:4;35608:36;35618:6;35626:9;35637:6;35608:9;:36::i;:::-;35655:121;35664:6;35672:12;:10;:12::i;:::-;35686:89;35724:6;35686:89;;;;;;;;;;;;;;;;;:19;;;;;;;:11;:19;;;;;;35706:12;:10;:12::i;:::-;35686:33;;;;;;;;;;;;;-1:-1:-1;35686:33:0;;;:89;:37;:89::i;:::-;35655:8;:121::i;:::-;-1:-1:-1;35794:4:0;35485:321;;;;;;:::o;42289:117::-;42340:66;42289:117;:::o;33631:91::-;33705:9;;;;33631:91;:::o;36215:218::-;36303:4;36320:83;36329:12;:10;:12::i;:::-;36343:7;36352:50;36391:10;36352:11;:25;36364:12;:10;:12::i;:::-;36352:25;;;;;;;;;;;;;;;;;;-1:-1:-1;36352:25:0;;;:34;;;;;;;;;;;:38;:50::i;52934:29::-;;;;;;;;;:::o;54343:1812::-;54409:17;10117:1;10723:7;;:19;;10715:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10117:1;10856:7;:18;54440:14:::1;54456:23;;:::i;:::-;54483:17;:15;:17::i;:::-;54439:61;;;;54511:24;;:::i;:::-;54563:6;::::0;:31:::1;::::0;;;;;54588:4:::1;54563:31;::::0;::::1;::::0;;;:6:::1;::::0;;::::1;::::0;:16:::1;::::0;:31;;;;;::::1;::::0;;;;;;;;;:6;:31;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;54563:31:0;54546:48;;54622:6:::1;::::0;:31:::1;::::0;;;;;54647:4:::1;54622:31;::::0;::::1;::::0;;;:6:::1;::::0;;::::1;::::0;:16:::1;::::0;:31;;;;;54563::::1;::::0;54622;;;;;;;;:6;:31;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;54622:31:0;::::1;54605:14:::0;::::1;:48:::0;54701:13;;54682:14;;54664:15:::1;::::0;54682:33:::1;::::0;:14;:18:::1;:33::i;:::-;54664:51;;54726:15;54744:33;54763:4;:13;;;54744:5;:14;;;:18;;:33;;;;:::i;:::-;54726:51;;54790:10;54803:25;54812:9;54823:4;54803:8;:25::i;:::-;54790:38;;54839:20;54862:13;:11;:13::i;:::-;54839:36:::0;-1:-1:-1;54968:17:0;54964:942:::1;;55006:9;55002:213;;;55053:6;::::0;55096:14;;55053:6:::1;::::0;;;::::1;::::0;::::1;::::0;52345:5:::1;::::0;55096:27:::1;::::0;55053:6;;55096:18:::1;:27;:::i;:::-;:33;;;;;;55078:15;::::0;::::1;:51:::0;55166:14:::1;::::0;::::1;::::0;52345:5:::1;::::0;55166:27:::1;::::0;::::1;::::0;;::::1;::::0;:18:::1;:27;:::i;:::-;:33;;;;;;55148:15;::::0;::::1;:51:::0;-1:-1:-1;55002:213:0::1;55241:57;52583:5;55241:34;55254:20;:7:::0;55266;55254:11:::1;:20::i;:::-;55241:12;:34::i;:57::-;55229:69;;55313:37;55327:2;52583:5;55313;:37::i;:::-;54964:942;;;55505:13:::0;;55450:143:::1;::::0;55477:25:::1;:7:::0;55489:12;55477:11:::1;:25::i;:::-;:41;;;;;;55565:4;:13;;;55537:25;55549:12;55537:7;:11;;:25;;;;:::i;:::-;:41;;;;;;55450:8;:143::i;:::-;55438:155;;55612:9;55608:287;;;55642:9;55654:27;:9:::0;55668:12;55654:13:::1;:27::i;:::-;55642:39;;55718:62;55751:12;55727:21;55746:1;55727:4;:14;;;:18;;:21;;;;:::i;:::-;:36;;;;;;55765:5;:14;;;55718:8;:62::i;:::-;55700:15;::::0;::::1;:80:::0;55826:14:::1;::::0;::::1;::::0;55817:62:::1;::::0;55850:12;;55826:21:::1;::::0;55845:1;55826:18:::1;:21::i;:::-;:36;;;;;;55864:5;:14;;;55817:8;:62::i;:::-;55799:15;::::0;::::1;:80:::0;-1:-1:-1;55608:287:0::1;55936:1;55924:9;:13;55916:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55987:20;55993:2;55997:9;55987:5;:20::i;:::-;56020:25;56028:9;56039:5;56020:7;:25::i;:::-;56060:5;56056:41;;;56075:22;56080:9;56091:5;56075:4;:22::i;:::-;56067:5;:30:::0;56056:41:::1;56113:34;::::0;;;;;::::1;::::0;::::1;::::0;;;;;56118:10:::1;::::0;56113:34:::1;::::0;;;;;;::::1;-1:-1:-1::0;;10073:1:0;11035:7;:22;-1:-1:-1;54343:1812:0;;;-1:-1:-1;;;;;54343:1812:0:o;53932:268::-;54084:7;;;;54062:10;:30;54054:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54122:6;:16;;;;;;;;;;;;;;54149:6;:16;;;;;;;;;;;;;;;54176:6;:16;;;;;;;;;;;;;;;;;;53932:268::o;33958:127::-;34059:18;;;34032:7;34059:18;;;;;;;;;;;33958:127;;;;:::o;53195:29::-;;;;:::o;42415:41::-;;;;;;;;;;;;;:::o;56363:1948::-;56465:15;56482;10117:1;10723:7;;:19;;10715:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10117:1;10856:7;:18;56516:14:::1;56532:23;;:::i;:::-;56559:17;:15;:17::i;:::-;56619:6;::::0;56668::::1;::::0;56721:32:::1;::::0;;;;;56747:4:::1;56721:32;::::0;::::1;::::0;;;56515:61;;-1:-1:-1;56515:61:0;;-1:-1:-1;56619:6:0::1;::::0;;::::1;::::0;56668;::::1;::::0;56602:14:::1;::::0;56619:6;;56721:17:::1;::::0;:32;;;;;::::1;::::0;;;;;;;;56619:6;56721:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;56721:32:0;56783::::1;::::0;;;;;56809:4:::1;56783:32;::::0;::::1;::::0;;;56721;;-1:-1:-1;56764:16:0::1;::::0;56783:17:::1;::::0;::::1;::::0;::::1;::::0;:32;;;;;56721::::1;::::0;56783;;;;;;;:17;:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;56783:32:0;56846:13;;56783:32;;-1:-1:-1;56834:25:0;::::1;::::0;::::1;::::0;:54:::1;;;56875:4;:13;;;56863:8;:25;;56834:54;56826:87;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;56924:17;56944:24;56962:4;56944:9;:24::i;:::-;56924:44;;56981:10;56994:25;57003:9;57014:4;56994:8;:25::i;:::-;56981:38;;57030:20;57053:13;:11;:13::i;:::-;57030:36:::0;-1:-1:-1;57030:36:0;57165:23:::1;:9:::0;57179:8;57165:13:::1;:23::i;:::-;:38;;;;;;::::0;-1:-1:-1;57298:12:0;57272:23:::1;:9:::0;57286:8;57272:13:::1;:23::i;:::-;:38;;;;;;57262:48;;57387:1;57377:7;:11;:26;;;;;57402:1;57392:7;:11;57377:26;57369:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57453:31;57467:4;57474:9;57453:5;:31::i;:::-;57495:33;:20;::::0;::::1;57516:2:::0;57520:7;57495:20:::1;:33::i;:::-;57539;:20;::::0;::::1;57560:2:::0;57564:7;57539:20:::1;:33::i;:::-;57583:24;;:::i;:::-;57635:32;::::0;;;;;57661:4:::1;57635:32;::::0;::::1;::::0;;;:17:::1;::::0;::::1;::::0;::::1;::::0;:32;;;;;::::1;::::0;;;;;;;;:17;:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;57635:32:0;57618:49;;57695:32:::1;::::0;;;;;57721:4:::1;57695:32;::::0;::::1;::::0;;;:17:::1;::::0;::::1;::::0;::::1;::::0;:32;;;;;57635::::1;::::0;57695;;;;;;;:17;:32;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;57695:32:0;::::1;57678:14:::0;::::1;:49:::0;57738:401;::::1;;;57842:13:::0;;57807:14;;57768:9:::1;::::0;57780:157:::1;::::0;57807:32:::1;::::0;57826:12;57807:18:::1;:32::i;:::-;:48;;;;;;57909:4;:13;;;57874:32;57893:12;57874:5;:14;;;:18;;:32;;;;:::i;57780:157::-;57768:169;;57970:62;58003:12;57979:21;57998:1;57979:4;:14;;;:18;;:21;;;;:::i;:::-;:36;;;;;;58017:5;:14;;;57970:8;:62::i;:::-;57952:15;::::0;::::1;:80:::0;58074:14:::1;::::0;::::1;::::0;58065:62:::1;::::0;58098:12;;58074:21:::1;::::0;58093:1;58074:18:::1;:21::i;:::-;:36;;;;;;58112:5;:14;;;58065:8;:62::i;:::-;58047:15;::::0;::::1;:80:::0;-1:-1:-1;57738:401:0::1;58149:25;58157:9;58168:5;58149:7;:25::i;:::-;58189:5;58185:41;;;58204:22;58209:9;58220:5;58204:4;:22::i;:::-;58196:5;:30:::0;58185:41:::1;58300:2;58265:38;;58270:10;58265:38;;;58282:7;58291;58265:38;;;;;;;;;;;;;;;;;;;;;;;;10887:1;;;;;;;;;;10073::::0;11035:7;:22;;;;56363:1948;;;:::o;63542:299::-;63664:6;;63731;;63792:16;;;;;;;;63590:13;;63664:6;;;;;63731;;63664;;63792:14;;:16;;;;;63616:22;;63792:16;;;;;;;;63664:6;63792:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63792:16:0;;;;;;;;;;-1:-1:-1;63792:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63815:7;:14;;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63815:16:0;;;;;;;;;;-1:-1:-1;63815:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63764:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36936:269;37029:4;37046:129;37055:12;:10;:12::i;:::-;37069:7;37078:96;37117:15;37078:96;;;;;;;;;;;;;;;;;:11;:25;37090:12;:10;:12::i;:::-;37078:25;;;;;;;;;;;;;;;;;;-1:-1:-1;37078:25:0;;;:34;;;;;;;;;;;:96;:38;:96::i;34298:175::-;34384:4;34401:42;34411:12;:10;:12::i;:::-;34425:9;34436:6;34401:9;:42::i;52539:49::-;52583:5;52539:49;:::o;60895:218::-;10117:1;10723:7;;:19;;10715:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10117:1;10856:7;:18;61014:8:::1;::::0;60978:6:::1;::::0;:31:::1;::::0;;;;;61003:4:::1;60978:31;::::0;::::1;::::0;;;60954:70:::1;::::0;60974:2;;60978:45:::1;::::0;61014:8:::1;::::0;;::::1;::::0;60978:6:::1;::::0;;::::1;::::0;:16:::1;::::0;:31;;;;;::::1;::::0;;;;;;;;:6;:31;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;60978:31:0;;:35:::1;:45::i;:::-;60954:6;::::0;::::1;;::::0;:70;:19:::1;:70::i;:::-;61095:8;::::0;61059:6:::1;::::0;:31:::1;::::0;;;;;61084:4:::1;61059:31;::::0;::::1;::::0;;;61035:70:::1;::::0;61055:2;;61059:45:::1;::::0;61095:8;;;::::1;;;::::0;61059:6:::1;::::0;;::::1;::::0;:16:::1;::::0;:31;;;;;::::1;::::0;;;;;;;;:6;:31;::::1;;::::0;::::1;;;;::::0;::::1;:45;61035:6;::::0;::::1;;::::0;:70;:19:::1;:70::i;:::-;-1:-1:-1::0;10073:1:0;11035:7;:22;60895:218::o;52683:35::-;;;;;;:::o;52761:29::-;;;;;;:::o;43096:839::-;43327:15;43315:8;:27;;43307:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43483:15;;43600:13;;;;43378:14;43600:13;;;:6;:13;;;;;;;;:15;;;;;;;;;43549:77;;42340:66;43549:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43517:128;;;;;;43419:241;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43395:276;;;;;;;;;43709:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43378:14;;43600:15;43709:26;;;;;-1:-1:-1;43709:26:0;;;;;;;;;;43600:15;43709:26;;;;;;;;;;;;;;;-1:-1:-1;;43709:26:0;;;;;;-1:-1:-1;;43768:30:0;;;;;;;:59;;;43822:5;43802:25;;:16;:25;;;43768:59;43746:139;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43896:31;43905:5;43912:7;43921:5;43896:8;:31::i;:::-;43096:839;;;;;;;;;:::o;62209:772::-;62568:8;;62665:9;;62568:8;;;;;62599;;;;;;;62665:9;;;;62698;;;;;62332:17;;62635:6;;;;;52345:5;62722:14;;62718:106;;;62766:9;62753:22;;62803:9;62790:22;;62718:106;62834:26;62863:24;62874:12;62863:10;:24::i;:::-;62834:53;;62915:58;62927:36;62944:18;62927:16;:36::i;:::-;62965:7;62915:11;:58::i;:::-;62898:75;;62209:772;;;;;;;:::o;34536:151::-;34652:18;;;;34625:7;34652:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;34536:151::o;42147:30::-;;;;:::o;61168:973::-;10117:1;10723:7;;:19;;10715:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10117:1;10856:7;:18;61227:14:::1;61243:23;;:::i;:::-;61270:17;:15;:17::i;:::-;61226:61;;;;61298:10;61311:25;61320:9;61331:4;61311:8;:25::i;:::-;61298:38;;61347:26;;:::i;:::-;61410:6;::::0;61403:39:::1;::::0;;;;;61436:4:::1;61403:39;::::0;::::1;::::0;;;61410:6:::1;::::0;;::::1;::::0;61403:24:::1;::::0;:39;;;;;::::1;::::0;;;;;;;;;61410:6;61403:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;61403:39:0;61384:58;;61479:6:::1;::::0;61472:39:::1;::::0;;;;;61505:4:::1;61472:39;::::0;::::1;::::0;;;61479:6:::1;::::0;;::::1;::::0;61472:24:::1;::::0;:39;;;;;61403::::1;::::0;61472;;;;;;;;61479:6;61472:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;61472:39:0;::::1;61453:16:::0;::::1;:58:::0;61578:464;::::1;;;61608:20;61631:13;:11;:13::i;:::-;61735::::0;;61698:16;;61608:36;;-1:-1:-1;61659:9:0::1;::::0;61671:161:::1;::::0;61735:13;61698:34:::1;::::0;61608:36;61698:20:::1;:34::i;:::-;:50;;;;;;61804:4;:13;;;61767:34;61788:12;61767:7;:16;;;:20;;:34;;;;:::i;61671:161::-;61659:173;;61867:64;61900:12;61876:21;61895:1;61876:4;:14;;;:18;;:21;;;;:::i;:::-;:36;;;;;;61914:7;:16;;;61867:8;:64::i;:::-;61847:17;::::0;::::1;:84:::0;61975:14:::1;::::0;::::1;::::0;61966:64:::1;::::0;61999:12;;61975:21:::1;::::0;61994:1;61975:18:::1;:21::i;:::-;:36;;;;;;62013:7;:16;;;61966:8;:64::i;:::-;61946:17;::::0;::::1;:84:::0;-1:-1:-1;;61578:464:0::1;62052:27;62060:9;62071:7;62052;:27::i;:::-;62094:5;62090:43;;;62109:24;62114:9;62125:7;62109:4;:24::i;:::-;62101:5;:32:::0;62090:43:::1;-1:-1:-1::0;;10073:1:0;11035:7;:22;-1:-1:-1;;61168:973:0:o;66769:324::-;66819:14;66835:23;;:::i;:::-;66887:8;;;;;;66871:24;;66922:8;;;;66906:13;;;:24;66953:6;;;;;;52345:5;66953:13;;;;-1:-1:-1;66977:109:0;;67024:9;;;;;;67007:14;;;:26;67065:9;;;;;67048:14;;;:26;66977:109;66769:324;;:::o;22582:177::-;22692:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22715:23;22692:58;;;22665:86;;22685:5;;22665:19;:86::i;:::-;22582:177;;;:::o;2837:179::-;2895:7;2927:5;;;2951:6;;;;2943:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3299:158;3357:7;3390:1;3385;:6;;3377:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3444:5:0;;;3299:158::o;63849:1267::-;64103:22;;64268:64;64322:9;64268:49;64302:14;64268:29;:14;64287:9;64268:18;:29::i;:::-;:33;;:49::i;:::-;:53;;:64::i;:::-;64251:81;;64343:26;64372:44;64395:12;64409:6;64372:22;:44::i;:::-;64343:73;;64444:57;64456:36;64473:18;64456:16;:36::i;:::-;64494:6;;;;;;;64444:11;:57::i;:::-;64427:74;-1:-1:-1;64566:24:0;64593:28;:13;47381:6;64593:17;:28::i;:::-;64566:55;-1:-1:-1;64651:51:0;64672:29;:9;64686:14;64672:13;:29::i;:::-;64651:16;;:20;:51::i;:::-;64632:70;-1:-1:-1;47381:6:0;64632:70;64732:28;;-1:-1:-1;64771:24:0;64798:28;:13;47381:6;64798:17;:28::i;:::-;64771:55;-1:-1:-1;64856:51:0;64877:29;:9;64891:14;64877:13;:29::i;64856:51::-;47381:6;64937:28;;;-1:-1:-1;65040:34:0;:14;65059;65040:18;:34::i;:::-;64998:38;:16;65019;64998:20;:38::i;:::-;:76;;64976:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63849:1267;;;;;;;;;;;;:::o;65154:503::-;65255:13;;65243:26;;:11;:26::i;:::-;65232:8;:37;;;;;;;;;;;;;;;65303:13;;;;65291:26;;:11;:26::i;:::-;65280:8;;:37;;;;;;;;;;;;;;;;;;65332:9;65328:240;;;65383:13;;65365:14;;;;:31;;;;:66;;;65418:4;:13;;;65400:4;:14;;;:31;;65365:66;65358:74;;;;65475:27;65487:4;:14;;;65475:11;:27::i;:::-;65463:9;:39;;;;;;;;;;;;;;;65541:14;;;;65529:27;;:11;:27::i;:::-;65517:9;;:39;;;;;;;;;;;;;;;;;;65328:240;65588:14;;;;;65604;;;;;65620:13;;65635;;;;;65583:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65154:503;;:::o;30166:106::-;30254:10;30166:106;:::o;40083:346::-;40185:19;;;40177:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40264:21;;;40256:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40337:18;;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;40389:32;;;;;;;;;;;;;;;;;40083:346;;;:::o;37695:539::-;37801:20;;;37793:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37882:23;;;37874:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37958:47;37979:6;37987:9;37998:6;37958:20;:47::i;:::-;38038:71;38060:6;38038:71;;;;;;;;;;;;;;;;;:17;;;:9;:17;;;;;;;;;;;;:71;:21;:71::i;:::-;38018:17;;;;:9;:17;;;;;;;;;;;:91;;;;38143:20;;;;;;;:32;;38168:6;38143:24;:32::i;:::-;38120:20;;;;:9;:20;;;;;;;;;;;;:55;;;;38191:35;;;;;;;38120:20;;38191:35;;;;;;;;;;;;;37695:539;;;:::o;5664:166::-;5750:7;5786:12;5778:6;;;;5770:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5817:5:0;;;5664:166::o;65762:953::-;65839:10;65863:13;65878:23;65905:7;;;;;;;;;;;:27;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;65905:29:0;;;;;;;66000:5;;65953:19;;;;;;;-1:-1:-1;65905:29:0;;-1:-1:-1;65905:29:0;;-1:-1:-1;66000:5:0;66031:677;;66061:11;;66057:581;;66093:13;66109:35;66122:21;66127:9;66138:4;66122;:21::i;66109:35::-;66093:51;;66163:17;66183:20;66196:6;66183:12;:20::i;:::-;66163:40;;66234:9;66226:5;:17;66222:401;;;66268:17;66288:109;;;;:39;66306:20;:5;66316:9;66306;:20::i;:::-;66288:13;:11;:13::i;:::-;:17;;:39::i;:109::-;66268:129;-1:-1:-1;66420:19:0;66442:30;66467:4;66442:20;:5;66452:9;66442;:20::i;:30::-;66420:52;;66495:17;66527:11;66515:9;:23;;;;;;;-1:-1:-1;66565:13:0;;66561:42;;66580:23;66586:5;66593:9;66580:5;:23::i;:::-;66222:401;;;;66057:581;;;66031:677;;;66659:11;;66655:53;;66695:1;66687:5;:9;66655:53;65762:953;;;;;;;:::o;3716:220::-;3774:7;3798:6;3794:20;;-1:-1:-1;3813:1:0;3806:8;;3794:20;3837:5;;;3841:1;3837;:5;:1;3861:5;;;;;:10;3853:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26826:312;26874:9;26904:1;26900;:5;26896:235;;;-1:-1:-1;26926:1:0;26962;26958;26954:5;;:9;26978:92;26989:1;26985;:5;26978:92;;;27015:1;27011:5;;27053:1;27048;27044;27040;:5;;;;;;:9;27039:15;;;;;;27035:19;;26978:92;;;26896:235;;;;27091:6;;27087:44;;-1:-1:-1;27118:1:0;26826:312;;;:::o;38516:378::-;38600:21;;;38592:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38670:49;38699:1;38703:7;38712:6;38670:20;:49::i;:::-;38747:12;;:24;;38764:6;38747:16;:24::i;:::-;38732:12;:39;38803:18;;;:9;:18;;;;;;;;;;;:30;;38826:6;38803:22;:30::i;:::-;38782:18;;;:9;:18;;;;;;;;;;;:51;;;;38849:37;;;;;;;38782:18;;:9;;38849:37;;;;;;;;;;38516:378;;:::o;7940:106::-;7998:7;8029:1;8025;:5;:13;;8037:1;8025:13;;;-1:-1:-1;8033:1:0;;8018:20;-1:-1:-1;7940:106:0:o;7757:107::-;7815:7;7847:1;7842;:6;;:14;;7855:1;7842:14;;67532:188;67610:7;67637:9;:75;;67699:13;;;;67683;;:29;67637:75;;;-1:-1:-1;67666:14:0;;;;67649;;;;;:31;;67532:188;-1:-1:-1;67532:188:0:o;39227:418::-;39311:21;;;39303:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39383:49;39404:7;39421:1;39425:6;39383:20;:49::i;:::-;39466:68;39489:6;39466:68;;;;;;;;;;;;;;;;;:18;;;:9;:18;;;;;;;;;;;;:68;:22;:68::i;:::-;39445:18;;;:9;:18;;;;;;;;;;:89;39560:12;;:24;;39577:6;39560:16;:24::i;:::-;39545:12;:39;39600:37;;;;;;;;39626:1;;39600:37;;;;;;;;;;;;;39227:418;;:::o;49995:792::-;50189:14;;50059:7;;50189:14;;;;;50175:28;;;50214:89;;50273:8;;50256:35;;50273:8;;;;;50283:7;;;;50256:16;:35::i;:::-;50249:42;;;;;50214:89;50340:8;;50313:17;;50333:49;;50340:8;;47451:4;47434:13;47433:22;50363:18;;47433:22;;;;50363:18;;50333:6;:49::i;:::-;50419:7;;50313:69;;-1:-1:-1;50393:16:0;;50412:47;;50419:7;;;;;47518:5;47501:13;47500:23;;50412:47;50393:66;-1:-1:-1;50482:111:0;50521:61;50568:13;;;47451:4;47434:13;47433:22;;47381:6;50522:23;;50521:46;:61::i;:::-;50482:9;;:24;:111::i;:::-;50470:123;-1:-1:-1;50615:109:0;50653:60;50699:13;;;47518:5;47501:13;47500:23;;50653:60;50615:8;;:23;:109::i;:::-;50604:120;;50742:37;50759:9;50770:8;50742:16;:37::i;:::-;50735:44;49995:792;-1:-1:-1;;;;;49995:792:0:o;28255:1268::-;28322:7;27392:19;28346:18;:24;28342:1174;;-1:-1:-1;27472:24:0;28387:9;;28342:1174;27349:6;28418:18;:31;28414:1102;;27731:23;28516:22;;28512:482;;;28573:22;;;28559:11;28629:27;28573:22;28654:1;28629:24;:27::i;:::-;28614:42;-1:-1:-1;28744:5:0;28683:57;28718:21;28735:3;27628:1;27609:15;27601:28;;;28718:16;:21::i;:::-;28683:30;28690:22;28707:4;27563:2;27542:17;27534:31;;28690:22;27666:29;;28683:6;:30::i;:57::-;28682:67;;;;;;28675:74;;;;;;28512:482;27731:23;28804:22;;;28790:11;28860:27;28804:22;28885:1;28860:24;:27::i;:::-;28845:42;-1:-1:-1;28973:5:0;28913:57;28948:21;28965:3;27628:1;27609:15;27601:28;;28948:21;28913:30;28920:22;28937:4;27563:2;27542:17;27534:31;;28920:22;27666:29;;28913:6;:30::i;28414:1102::-;29104:11;27792:24;29137:22;;:76;;27792:24;29190:22;;;29137:76;;;29163:22;;;29137:76;29104:124;-1:-1:-1;29249:27:0;29104:124;29274:1;29249:24;:27::i;:::-;29243:33;-1:-1:-1;29291:12:0;29306:26;29321:10;29243:33;27901:23;29321:7;:10::i;:::-;29306;27852:13;29312:3;29306:5;:10::i;:26::-;29291:41;-1:-1:-1;27792:24:0;29351:22;;29347:158;;;29416:5;29401:12;28055:20;29408:4;29401:6;:12::i;29347:158::-;29484:5;29469:12;28055:20;29476:4;29469:6;:12::i;67101:423::-;67185:7;67220:5;67209:7;:16;;;67205:312;;-1:-1:-1;67249:14:0;67242:21;;67205:312;67296:5;67285:7;:16;;;67281:236;;67349:2;67343;67326:19;;67325:26;;67318:33;;;;67281:236;67384:6;67373:7;:17;;;67369:148;;67438:2;67432;67415:19;;67414:26;;67369:148;67503:2;67498:1;67481:18;;67480:25;;24887:761;25311:23;25337:69;25365:4;25337:69;;;;;;;;;;;;;;;;;25345:5;25337:27;;;;:69;;;;;:::i;:::-;25421:17;;25311:95;;-1:-1:-1;25421:21:0;25417:224;;25563:10;25552:30;;;;;;;;;;;;;;;-1:-1:-1;25552:30:0;25544:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4414:153;4472:7;4504:1;4500;:5;4492:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4558:1;4554;:5;;;;;;;4414:153;-1:-1:-1;;;4414:153:0:o;48534:1400::-;48773:14;;48638:7;;48773:14;;;;;48759:28;;;48798:273;;48892:18;;48854:130;;48884:38;;48892:18;;48916:5;48884:31;:38::i;:::-;48854:130;;;;;;;;;;;;;;;;;:11;:130::i;:::-;48833:18;:151;;;;;;;;;;;49031:8;;49006:53;;49031:8;;;;49050:7;;;;49006:16;:53::i;:::-;48999:60;;;;;48798:273;49111:18;;49167:8;;49111:18;;;;;49081:27;;49160:49;;49167:8;47451:4;47434:13;47433:22;;49160:49;49246:7;;49140:69;;-1:-1:-1;49220:16:0;;49239:47;;49246:7;;;;;47518:5;47501:13;47500:23;;49239:47;49220:66;-1:-1:-1;49359:111:0;49398:61;49445:13;;;47451:4;47434:13;47433:22;;49359:111;49347:123;-1:-1:-1;49492:109:0;49530:60;49576:13;;;47518:5;47501:13;47500:23;;49492:109;49481:120;;49623:22;49635:9;49623:11;:22::i;:::-;49612:8;:33;;;;;;;;;;;;;;;49666:21;49678:8;49666:11;:21::i;:::-;49656:7;:31;;;;;;;;;;;;;;;;49719:18;49731:5;49719:11;:18::i;:::-;49698;:39;;;;;;;;;;;;;;;49765:24;49777:11;49765;:24::i;:::-;49748:14;:41;;;;;;;;;;;;;;49807:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49889:37;49906:9;49917:8;49889:16;:37::i;:::-;49882:44;48534:1400;-1:-1:-1;;;;;;;48534:1400:0:o;67728:153::-;67783:7;52296:10;67811:1;:16;;67803:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;67871:1:0;67728:153::o;50795:259::-;50908:7;50937:13;50933:54;;-1:-1:-1;50974:1:0;50967:8;;50933:54;51038:8;25825:6;51005:9;:29;51004:42;;;;51399:260;51515:7;47381:6;51542:5;:17;51535:25;;;;47381:6;51632:5;51624:14;;51616:5;:22;51609:3;51601:12;;51592:5;47381:6;51580:17;51579:34;:59;51578:73;;;;;;;51399:260;-1:-1:-1;;;;51399:260:0:o;26179:529::-;26292:20;25825:6;26338:12;:25;;26330:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26420:1;26416;:5;:37;;25825:6;26416:37;;;26429:12;26416:37;26401:52;-1:-1:-1;26476:1:0;26471:6;;;;26466:235;26479:6;;26466:235;;25825:6;26526:27;;;26525:41;;-1:-1:-1;26591:1:0;26587;:5;:10;26583:107;;25825:6;26634:27;;;26633:41;26583:107;26492:1;26487:6;;;;26466:235;;25880:124;25949:7;25825:6;25976:8;:1;25982;25976:5;:8::i;:::-;:20;;;;17575:195;17678:12;17710:52;17732:6;17740:4;17746:1;17749:12;17710:21;:52::i;:::-;17703:59;17575:195;-1:-1:-1;;;;17575:195:0:o;51831:178::-;51914:7;51960:12;47326:10;51942:16;;;51934:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51999:1:0;;51831:178;-1:-1:-1;;51831:178:0:o;51667:156::-;51722:7;47326:10;51750:1;:16;;51742:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18627:530;18754:12;18812:5;18787:21;:30;;18779:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18879:18;18890:6;18879:10;:18::i;:::-;18871:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19005:12;19019:23;19046:6;:11;;19066:5;19074:4;19046:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19004:75;;;;19097:52;19115:7;19124:10;19136:12;19097:17;:52::i;14657:422::-;15024:20;15063:8;;;14657:422::o;21167:742::-;21282:12;21311:7;21307:595;;;-1:-1:-1;21342:10:0;21335:17;;21307:595;21456:17;;:21;21452:439;;21719:10;21713:17;21780:15;21767:10;21763:2;21759:19;21752:44;21667:148;21855:20;;;;;;;;;;;;;;;;;;;;21862:12;;21855:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o
Swarm Source
ipfs://49f6f8528b3e4b37e72b9bde0aa804ce74fda17a3dc51ea424bf85cf5943707e
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.