Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LockedStaking
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-03-07 */ //SPDX-License-Identifier: Unlicense pragma solidity 0.8.17; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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://consensys.net/diligence/blog/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"); (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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } } // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) /** * @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 meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol) /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMaps { struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo(BitMap storage bitmap, uint256 index, bool value) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] &= ~mask; } } /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } } /// @notice Optimized sorts and operations for sorted arrays. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Sort.sol) library LibSort { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSERTION SORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on small arrays (32 or lesser elements). // - Faster on almost sorted arrays. // - Smaller bytecode. // - May be suitable for view functions intended for off-chain querying. /// @dev Sorts the array in-place with insertion sort. function insertionSort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) // Length of `a`. mstore(a, 0) // For insertion sort's inner loop to terminate. let h := add(a, shl(5, n)) // High slot. let s := 0x20 let w := not(31) for { let i := add(a, s) } 1 {} { i := add(i, s) if gt(i, h) { break } let k := mload(i) // Key. let j := add(i, w) // The slot before the current slot. let v := mload(j) // The value of `j`. if iszero(gt(v, k)) { continue } for {} 1 {} { mstore(add(j, s), v) j := add(j, w) // `sub(j, 0x20)`. v := mload(j) if iszero(gt(v, k)) { break } } mstore(add(j, s), k) } mstore(a, n) // Restore the length of `a`. } } /// @dev Sorts the array in-place with insertion sort. function insertionSort(int256[] memory a) internal pure { _convertTwosComplement(a); insertionSort(_toUints(a)); _convertTwosComplement(a); } /// @dev Sorts the array in-place with insertion sort. function insertionSort(address[] memory a) internal pure { insertionSort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTRO-QUICKSORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on larger arrays (more than 32 elements). // - Robust performance. // - Larger bytecode. /// @dev Sorts the array in-place with intro-quicksort. function sort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let w := not(31) let s := 0x20 let n := mload(a) // Length of `a`. mstore(a, 0) // For insertion sort's inner loop to terminate. // Let the stack be the start of the free memory. let stack := mload(0x40) for {} iszero(lt(n, 2)) {} { // Push `l` and `h` to the stack. // The `shl` by 5 is equivalent to multiplying by `0x20`. let l := add(a, s) let h := add(a, shl(5, n)) let j := l // forgefmt: disable-next-item for {} iszero(or(eq(j, h), gt(mload(j), mload(add(j, s))))) {} { j := add(j, s) } // If the array is already sorted. if eq(j, h) { break } j := h // forgefmt: disable-next-item for {} iszero(gt(mload(j), mload(add(j, w)))) {} { j := add(j, w) // `sub(j, 0x20)`. } // If the array is reversed sorted. if eq(j, l) { for {} 1 {} { let t := mload(l) mstore(l, mload(h)) mstore(h, t) h := add(h, w) // `sub(h, 0x20)`. l := add(l, s) if iszero(lt(l, h)) { break } } break } // Push `l` and `h` onto the stack. mstore(stack, l) mstore(add(stack, s), h) stack := add(stack, 0x40) break } for { let stackBottom := mload(0x40) } iszero(eq(stack, stackBottom)) {} { // Pop `l` and `h` from the stack. stack := sub(stack, 0x40) let l := mload(stack) let h := mload(add(stack, s)) // Do insertion sort if `h - l <= 0x20 * 12`. // Threshold is fine-tuned via trial and error. if iszero(gt(sub(h, l), 0x180)) { // Hardcode sort the first 2 elements. let i := add(l, s) if iszero(lt(mload(l), mload(i))) { let t := mload(i) mstore(i, mload(l)) mstore(l, t) } for {} 1 {} { i := add(i, s) if gt(i, h) { break } let k := mload(i) // Key. let j := add(i, w) // The slot before the current slot. let v := mload(j) // The value of `j`. if iszero(gt(v, k)) { continue } for {} 1 {} { mstore(add(j, s), v) j := add(j, w) v := mload(j) if iszero(gt(v, k)) { break } } mstore(add(j, s), k) } continue } // Pivot slot is the average of `l` and `h`. let p := add(shl(5, shr(6, add(l, h))), and(31, l)) // Median of 3 with sorting. { let e0 := mload(l) let e2 := mload(h) let e1 := mload(p) if iszero(lt(e0, e1)) { let t := e0 e0 := e1 e1 := t } if iszero(lt(e0, e2)) { let t := e0 e0 := e2 e2 := t } if iszero(lt(e1, e2)) { let t := e1 e1 := e2 e2 := t } mstore(p, e1) mstore(h, e2) mstore(l, e0) } // Hoare's partition. { // The value of the pivot slot. let x := mload(p) p := h for { let i := l } 1 {} { for {} 1 {} { i := add(i, s) if iszero(gt(x, mload(i))) { break } } let j := p for {} 1 {} { j := add(j, w) if iszero(lt(x, mload(j))) { break } } p := j if iszero(lt(i, p)) { break } // Swap slots `i` and `p`. let t := mload(i) mstore(i, mload(p)) mstore(p, t) } } // If slice on right of pivot is non-empty, push onto stack. { mstore(stack, add(p, s)) // Skip `mstore(add(stack, 0x20), h)`, as it is already on the stack. stack := add(stack, shl(6, lt(add(p, s), h))) } // If slice on left of pivot is non-empty, push onto stack. { mstore(stack, l) mstore(add(stack, s), p) stack := add(stack, shl(6, gt(p, l))) } } mstore(a, n) // Restore the length of `a`. } } /// @dev Sorts the array in-place with intro-quicksort. function sort(int256[] memory a) internal pure { _convertTwosComplement(a); sort(_toUints(a)); _convertTwosComplement(a); } /// @dev Sorts the array in-place with intro-quicksort. function sort(address[] memory a) internal pure { sort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER USEFUL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, the `uniquifySorted` methods will not revert if the // array is not sorted -- it will simply remove consecutive duplicate elements. /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { // If the length of `a` is greater than 1. if iszero(lt(mload(a), 2)) { let x := add(a, 0x20) let y := add(a, 0x40) let end := add(a, shl(5, add(mload(a), 1))) for {} 1 {} { if iszero(eq(mload(x), mload(y))) { x := add(x, 0x20) mstore(x, mload(y)) } y := add(y, 0x20) if eq(y, end) { break } } mstore(a, shr(5, sub(x, a))) } } } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(int256[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(address[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(uint256[] memory a, uint256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(a, needle, 0); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(int256[] memory a, int256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(address[] memory a, address needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(uint160(needle)), 0); } /// @dev Reverses the array in-place. function reverse(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { if iszero(lt(mload(a), 2)) { let s := 0x20 let w := not(31) let h := add(a, shl(5, mload(a))) for { a := add(a, s) } 1 {} { let t := mload(a) mstore(a, mload(h)) mstore(h, t) h := add(h, w) a := add(a, s) if iszero(lt(a, h)) { break } } } } } /// @dev Reverses the array in-place. function reverse(int256[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Reverses the array in-place. function reverse(address[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Returns whether the array is sorted in ascending order. function isSorted(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(gt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(sgt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(address[] memory a) internal pure returns (bool result) { result = isSorted(_toUints(a)); } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := lt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := slt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) { result = isSortedAndUniquified(_toUints(a)); } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _difference(a, b, 0); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_difference(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _intersection(a, b, 0); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _union(a, b, 0); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set union between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_union(_toUints(a), _toUints(b), 0)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Reinterpret cast to an uint256 array. function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an uint256 array. function _toUints(address[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { // As any address written to memory will have the upper 96 bits // of the word zeroized (as per Solidity spec), we can directly // compare these addresses as if they are whole uint256 words. casted := a } } /// @dev Reinterpret cast to an int array. function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an address array. function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Converts an array of signed two-complement integers /// to unsigned integers suitable for sorting. function _convertTwosComplement(int256[] memory a) private pure { /// @solidity memory-safe-assembly assembly { let w := shl(255, 1) for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} { a := add(a, 0x20) mstore(a, add(mload(a), w)) } } } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed) private pure returns (bool found, uint256 index) { /// @solidity memory-safe-assembly assembly { let m := 0 // Middle slot. let s := 0x20 let l := add(a, s) // Slot of the start of search. let h := add(a, shl(5, mload(a))) // Slot of the end of search. for { needle := add(signed, needle) } 1 {} { // Average of `l` and `h`. m := add(shl(5, shr(6, add(l, h))), and(31, l)) let t := add(signed, mload(m)) found := eq(t, needle) if or(gt(l, h), found) { break } // Decide whether to search the left or right half. if iszero(gt(needle, t)) { h := sub(m, s) continue } l := add(m, s) } // `m` will be less than `add(a, 0x20)` in the case of an empty array, // or when the value is less than the smallest value in the array. let t := iszero(lt(m, add(a, s))) index := shr(5, mul(sub(m, add(a, s)), t)) found := and(found, t) } } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _difference(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _union(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { k := add(k, s) mstore(k, v) b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } for {} iszero(gt(b, bEnd)) {} { k := add(k, s) mstore(k, mload(b)) b := add(b, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } } /*/////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error MustProlongLock(uint256 oldDuration, uint256 newDuration); error AmountIsZero(); error TransferFailed(); error NothingToClaim(); error LockStillActive(); error DurationOutOfBounds(uint256 duration); error UpdateToSmallerMultiplier(uint16 oldMultiplier, uint16 newMultiplier); error ZeroAddress(); error ZeroPrecision(); error ZeroAmount(); error MaxLocksSucceeded(); error MaxRewardsSucceeded(); error CanOnlyAddFutureRewards(); error NotRewardoor(); error CantAutoCompound(); error AlreadyAutoCompound(); error NotAutoCompoundEnabled(); error RewardStartEqEnd(); error IntervalNotRoundedWithEpoch(); error CantChangePast(); error CantUpdateExpiredLock(); contract LockedStaking is Initializable, OwnableUpgradeable { using BitMaps for BitMaps.BitMap; using FixedPointMathLib for uint256; /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event LockAdded(address indexed from, uint208 amount, uint32 end, uint16 multiplier); event LockUpdated(address indexed from, uint8 index, uint208 amount, uint32 end, uint16 multiplier); event Unlock(address indexed from, uint256 amount, uint256 index); event Claim(address indexed from, uint256 amount); event RewardAdded(uint256 start, uint256 end, uint256 amountPerSecond); event RewardUpdated(uint256 index, uint256 start, uint256 end, uint256 amountPerSecond); event RewardRemoved(uint256 index); event AutoCompoundEnabled(address indexed from, uint256 index, uint256 shares); event AutoCompoundDisabled(address indexed from, uint256 index, uint256 amount); event AutoCompounded(uint256 compoundAmount); event RewardoorSet(address indexed rewardoor, bool value); /*/////////////////////////////////////////////////////////////// IMMUTABLES & CONSTANTS //////////////////////////////////////////////////////////////*/ uint256 public constant MAX_LOCK_COUNT = 5; uint256 public constant MAX_REWARD_COUNT = 5; uint256 public constant MAX_MULTIPLIER = 998; uint256 public constant EPOCH_DURATION = 8 * 60 * 60; uint256 public constant ALGORITHM_THRESHOLD_IN_EPOCHS = 5; /*/////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ struct Lock { uint16 multiplier; uint32 end; uint208 amount; } struct Reward { uint32 start; uint32 end; uint192 amountPerSecond; } struct TotalReward { uint256 start; uint256 end; uint256 epochReward; } struct CompoundVars { uint256 from; uint256 to; uint256 currentPeriod; uint256 compoundClaimable; uint256 epochRewards; uint256 currCompLastAccRewardWeight; } /*/////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ IERC20 public swapToken; uint256 public precision; // no longer used but kept for upgradeability Reward[] public rewards; mapping(address => Lock[]) public locks; mapping(address => uint256) public userLastAccRewardsWeight; uint256 public lastRewardUpdate; uint256 public totalScore; uint256 public accRewardWeight; mapping(address => bool) public rewardoors; BitMaps.BitMap private lockCompoundedBitMap; uint256 public compoundAmount; uint256 public compoundShares; uint256 public compoundLastAccRewardWeight; /*/////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ modifier onlyRewardoor() { if (!rewardoors[msg.sender]) revert NotRewardoor(); _; } constructor() { _disableInitializers(); } /*/////////////////////////////////////////////////////////////// EXTERNAL //////////////////////////////////////////////////////////////*/ function initialize(address _swapToken, uint256 _precision) external initializer { if (_swapToken == address(0)) revert ZeroAddress(); if (_precision == 0) revert ZeroPrecision(); swapToken = IERC20(_swapToken); precision = _precision; __Ownable_init(); } /// @notice Adds new reward function addReward( uint32 start, uint32 end, uint192 amountPerSecond ) external onlyRewardoor { if (rewards.length == MAX_REWARD_COUNT) revert MaxRewardsSucceeded(); if (amountPerSecond == 0) revert AmountIsZero(); if (start == end) revert RewardStartEqEnd(); if (start < block.timestamp || end < block.timestamp) revert CanOnlyAddFutureRewards(); if (start % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (end % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); rewards.push(Reward(start, end, amountPerSecond)); if (!IERC20(swapToken).transferFrom(msg.sender, address(this), (end - start) * amountPerSecond)) revert TransferFailed(); emit RewardAdded(start, end, amountPerSecond); } /// @notice Removes existing reward and sends remaining reward to owner function removeReward(uint256 index) external onlyRewardoor { updateRewardsWeight(); Reward memory reward = rewards[index]; rewards[index] = rewards[rewards.length - 1]; rewards.pop(); // if rewards are not unlocked completely, send remaining to owner if (reward.end > block.timestamp) { uint256 lockedRewards = (reward.end - max(block.timestamp, reward.start)) * reward.amountPerSecond; if (!IERC20(swapToken).transfer(msg.sender, lockedRewards)) revert TransferFailed(); } emit RewardRemoved(index); } /// @notice Updates existing reward, cant change reward start if its already started function updateReward( uint256 index, uint256 newStart, uint256 newEnd, uint256 newAmountPerSecond ) external onlyRewardoor { if (newStart % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (newEnd % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (newAmountPerSecond == 0) revert ZeroAmount(); updateRewardsWeight(); Reward storage reward = rewards[index]; uint256 oldEnd = reward.end; if (oldEnd < block.timestamp) revert CantChangePast(); if (newEnd < block.timestamp) revert CanOnlyAddFutureRewards(); uint256 oldStart = reward.start; if ((oldStart < block.timestamp || newStart < block.timestamp) && newStart != oldStart) revert CantChangePast(); uint256 newTotalRewards = (newEnd - newStart) * newAmountPerSecond; uint256 oldTotalRewards = (oldEnd - oldStart) * reward.amountPerSecond; if (newStart != oldStart) { reward.start = uint32(newStart); } reward.end = uint32(newEnd); reward.amountPerSecond = uint192(newAmountPerSecond); if (oldTotalRewards > newTotalRewards) { if (!IERC20(swapToken).transfer(msg.sender, oldTotalRewards - newTotalRewards)) revert TransferFailed(); } else if (oldTotalRewards != newTotalRewards) { if (!IERC20(swapToken).transferFrom(msg.sender, address(this), newTotalRewards - oldTotalRewards)) revert TransferFailed(); } emit RewardUpdated(index, newStart, newEnd, newAmountPerSecond); } /// @notice Sets address eligibility to add/update rewards function setRewardoor(address addr, bool value) external onlyOwner { rewardoors[addr] = value; emit RewardoorSet(addr, value); } /// @notice Creates new lock for a user, adds potential claimable amount to it function addLock(uint208 amount, uint256 duration) external { if (amount == 0) revert AmountIsZero(); if (locks[msg.sender].length == MAX_LOCK_COUNT) revert MaxLocksSucceeded(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); uint256 addedAmount = claimable + amount; userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; uint32 end = uint32(block.timestamp + duration); uint16 multiplier = getDurationMultiplier(duration); locks[msg.sender].push(Lock(multiplier, end, uint208(addedAmount))); totalScore += multiplier * addedAmount; if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit LockAdded(msg.sender, uint208(addedAmount), end, multiplier); } /// @notice adds claimable to current lock, keeping the same end function compound(uint8 index) external { uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); if (claimable == 0) revert NothingToClaim(); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; Lock storage lock = locks[msg.sender][index]; if (lock.end < block.timestamp) revert CantUpdateExpiredLock(); uint208 newAmount = uint208(lock.amount + claimable); uint16 multiplier = lock.multiplier; lock.amount = newAmount; totalScore += claimable * multiplier; emit Claim(msg.sender, claimable); emit LockUpdated(msg.sender, index, newAmount, lock.end, multiplier); } /// @notice adds amount + potential claimable to existing lock, keeping the same end /// @dev if lock has auto compound enabled, adjusts the compoundLastAccRewardWeight to have the same current claimable amount function updateLockAmount(uint256 index, uint208 amount) external { if (amount == 0) revert AmountIsZero(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); uint256 addedAmount = amount + claimable; Lock storage lock = locks[msg.sender][index]; if (lock.end < block.timestamp) revert CantUpdateExpiredLock(); uint208 newAmount; if (lockCompoundedBitMap.get(getBitMapIndex(index, msg.sender))) { uint256 oldCompoundAmount = compoundAmount; compoundLastAccRewardWeight = calculateCompAccRewardWeightIn( oldCompoundAmount, addedAmount, newAccRewardsWeight, compoundLastAccRewardWeight ); uint256 newShares = convertToAutoCompoundShares(addedAmount); compoundAmount = oldCompoundAmount + addedAmount; compoundShares += newShares; newAmount = uint208(lock.amount + newShares); } else { newAmount = uint208(lock.amount + addedAmount); } lock.amount = newAmount; uint16 multiplier = lock.multiplier; userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; totalScore += addedAmount * multiplier; if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit LockUpdated(msg.sender, uint8(index), newAmount, lock.end, multiplier); } /// @notice claims for current locks and increases duration of existing lock function updateLockDuration(uint8 index, uint256 duration) external { uint256 newAccRewardsWeight = updateRewardsWeight(); Lock storage lock = locks[msg.sender][index]; uint32 end = uint32(block.timestamp + duration); if (lock.end >= end) revert MustProlongLock(lock.end, end); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; uint16 multiplier = getDurationMultiplier(duration); lock.end = end; uint16 oldMultiplier = lock.multiplier; if (oldMultiplier > multiplier) revert UpdateToSmallerMultiplier(oldMultiplier, multiplier); lock.multiplier = multiplier; uint208 amount = lock.amount; totalScore += (multiplier - oldMultiplier) * amount; if (claimable != 0) { if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } emit LockUpdated(msg.sender, index, amount, end, multiplier); } /// @notice claims for current locks function claim() external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); if (claimable == 0) revert NothingToClaim(); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } /// @notice returns locked amount + potential claimable to user and deletes lock from array function unlock(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); Lock storage lock = locks[msg.sender][index]; if (lock.end > block.timestamp) revert LockStillActive(); uint256 bitMapIndex = getBitMapIndex(index, msg.sender); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); bool isLockAutoCompound = lockCompoundedBitMap.get(bitMapIndex); uint256 amount; if (isLockAutoCompound) { uint256 shares = lock.amount; amount = convertToAutoCompoundAssets(shares); compoundLastAccRewardWeight = calculateCompAccRewardWeightOut( compoundAmount, amount, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount -= amount; compoundShares -= shares; } else { amount = lock.amount; } userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; unchecked { totalScore -= amount * lock.multiplier; } uint256 lastLockIndex; unchecked { lastLockIndex = locks[msg.sender].length - 1; } if (index == lastLockIndex) { if (isLockAutoCompound) { lockCompoundedBitMap.unset(bitMapIndex); } } else { locks[msg.sender][index] = locks[msg.sender][lastLockIndex]; uint256 lastLockBitMapIndex = getBitMapIndex(lastLockIndex, msg.sender); if (isLockAutoCompound) { if (!lockCompoundedBitMap.get(lastLockBitMapIndex)) { lockCompoundedBitMap.unset(bitMapIndex); } else { lockCompoundedBitMap.unset(lastLockBitMapIndex); } } else if (lockCompoundedBitMap.get(lastLockBitMapIndex)) { lockCompoundedBitMap.set(bitMapIndex); lockCompoundedBitMap.unset(lastLockBitMapIndex); } } locks[msg.sender].pop(); if (!IERC20(swapToken).transfer(msg.sender, amount + claimable)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit Unlock(msg.sender, amount, index); } /// @notice enables auto compound for existing lock, automatically adding all future rewards to principal /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same function enableAutoCompound(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); Lock storage lock = locks[msg.sender][index]; if (lock.multiplier != MAX_MULTIPLIER) revert CantAutoCompound(); uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound(); lockCompoundedBitMap.set(bitMapIndex); uint256 lockAmount = lock.amount + claimable; uint256 shares = convertToAutoCompoundShares(lockAmount); compoundLastAccRewardWeight = calculateCompAccRewardWeightIn( compoundAmount, lockAmount, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount += lockAmount; compoundShares += shares; lock.amount = uint208(shares); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (claimable != 0) { totalScore += claimable * MAX_MULTIPLIER; emit Claim(msg.sender, claimable); } emit AutoCompoundEnabled(msg.sender, index, shares); } /// @notice disables auto compound for existing lock, stops automatically adding all future rewards to principal /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same function disableAutoCompound(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); Lock storage lock = locks[msg.sender][index]; uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (!lockCompoundedBitMap.get(bitMapIndex)) revert NotAutoCompoundEnabled(); lockCompoundedBitMap.unset(bitMapIndex); uint256 sharesAmount = lock.amount; uint256 assets = convertToAutoCompoundAssets(sharesAmount); compoundLastAccRewardWeight = calculateCompAccRewardWeightOut( compoundAmount, assets, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount -= assets; compoundShares -= sharesAmount; lock.amount = uint208(assets); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (claimable != 0) { if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } emit AutoCompoundDisabled(msg.sender, index, assets); } function getRewardsLength() external view returns (uint256) { return rewards.length; } function getUserLocks(address addr) external view returns (Lock[] memory) { return locks[addr]; } function getLockLength(address addr) external view returns (uint256) { return locks[addr].length; } function getRewards() external view returns (Reward[] memory) { return rewards; } /// @notice is existing lock enabled for automatically adding all future rewards to principal function hasLockAutoCompoundEnabled(address user, uint256 index) external view returns (bool) { return lockCompoundedBitMap.get(getBitMapIndex(index, user)); } // gets rewards weight & returns users claimable amount function getUserClaimable(address user) external view returns (uint256 claimable) { (uint256 accRewardsWeight, , , ) = getRewardWeight(); return calculateUserClaimable(user, accRewardsWeight); } /*/////////////////////////////////////////////////////////////// PUBLIC //////////////////////////////////////////////////////////////*/ /// @notice updates new accrued reward weight, compound accrued reward weight, total score & compound amount function updateRewardsWeight() public returns (uint256) { ( uint256 currAccRewardWeight, uint256 currCompoundLastAccRewardWeight, uint256 currTotalScore, uint256 currCompoundAmount ) = getRewardWeight(); lastRewardUpdate = block.timestamp; accRewardWeight = currAccRewardWeight; compoundLastAccRewardWeight = currCompoundLastAccRewardWeight; totalScore = currTotalScore; if (currCompoundAmount != compoundAmount) { compoundAmount = currCompoundAmount; emit AutoCompounded(currCompoundAmount); } return currAccRewardWeight; } function convertToAutoCompoundShares(uint256 assets) public view returns (uint256) { uint256 supply = compoundShares; return supply == 0 ? assets : assets.mulDivDown(supply, compoundAmount); } function convertToAutoCompoundAssets(uint256 shares) public view returns (uint256) { uint256 supply = compoundShares; return supply == 0 ? shares : shares.mulDivDown(compoundAmount, supply); } /*/////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ /// @notice calculates new accrued reward weight and does auto compound /// @dev iterate over all rewards on every epoch to find epoch reward function getRewardWeightRegular() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 currTotalScore = totalScore; if (currTotalScore == 0) { return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount); } uint256 _lastRewardUpdate = lastRewardUpdate; uint256 currAccRewardWeight = accRewardWeight; uint256 currCompoundLastAccRewardWeight = compoundLastAccRewardWeight; uint256 currCompoundAmount = compoundAmount; Reward[] memory rewardsMem = rewards; uint256 from; uint256 to; uint256 epochRewards; uint256 compoundClaimable; from = _lastRewardUpdate; to = getEpoch(_lastRewardUpdate) + EPOCH_DURATION; while (to <= block.timestamp) { epochRewards = getPeriodRewards(rewardsMem, from, to); unchecked { currAccRewardWeight += epochRewards.divWadDown(currTotalScore); compoundClaimable = (currAccRewardWeight - currCompoundLastAccRewardWeight).mulWadDown( currCompoundAmount * MAX_MULTIPLIER ); currCompoundAmount += compoundClaimable; currCompoundLastAccRewardWeight = currAccRewardWeight; currTotalScore += compoundClaimable * MAX_MULTIPLIER; from = to; to += EPOCH_DURATION; } } if (from < block.timestamp) { epochRewards = getPeriodRewards(rewardsMem, from, block.timestamp); currAccRewardWeight += epochRewards.divWadDown(currTotalScore); } return (currAccRewardWeight, currCompoundLastAccRewardWeight, currTotalScore, currCompoundAmount); } /// @notice calculates new accrued reward weight and does auto compound if needed /// @dev if we're still in the same epoch as last one, dont do auto compounding /// @dev if more than 5 epochs have passed since last update, do the optimized method(find intersections, sort, calculate, apply) /// @dev if no more than 5 epochs have passed since last update, do the regular method(iterate over all rewards every epoch) /// @return new accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount function getRewardWeight() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 rewardUpdate = lastRewardUpdate; if (rewardUpdate == block.timestamp) { return (accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount); } uint256 lastUpdateEpoch = getEpoch(rewardUpdate); uint256 currEpoch = getEpoch(block.timestamp); if (lastUpdateEpoch == currEpoch) { return (getRewardWeightWithoutAutoComp(), compoundLastAccRewardWeight, totalScore, compoundAmount); } unchecked { if ((currEpoch - lastUpdateEpoch) / EPOCH_DURATION > ALGORITHM_THRESHOLD_IN_EPOCHS) { return getRewardWeightOpt(); } } return getRewardWeightRegular(); } /// @notice calculates new accrued reward weight and does auto compound if needed in an optimized way /// @dev first finds intersections of lastRewardUpdate, block.timestamp and reward interval /// @dev then sorts them and calculates total reward per epoch for every period /// @dev then goes through epochs and compounds claimable amount to principal function getRewardWeightOpt() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 currTotalScore = totalScore; if (currTotalScore == 0) { return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount); } CompoundVars memory compVars; compVars.from = lastRewardUpdate; uint256 currAccRewardWeight = accRewardWeight; compVars.currCompLastAccRewardWeight = compoundLastAccRewardWeight; uint256 currCompoundAmount = compoundAmount; Reward[] memory rewardsMem = rewards; (uint256[] memory intersections, uint256 emptyIntersections) = getPeriodIntersections( compVars.from, block.timestamp, rewardsMem ); if (intersections.length == emptyIntersections) { return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, compoundAmount); } LibSort.insertionSort(intersections); (TotalReward[] memory periodsTotalReward, uint256 zeroPeriods) = getTotalRewardPeriods( intersections, rewardsMem, emptyIntersections ); compVars.to = getEpoch(compVars.from) + EPOCH_DURATION; while (compVars.to <= block.timestamp && compVars.currentPeriod < periodsTotalReward.length - zeroPeriods) { // reward period hasnt started, go to next epoch if (periodsTotalReward[compVars.currentPeriod].start > compVars.from) { (compVars.from, compVars.to) = goToNextEpoch(compVars.to); continue; } // reward period has ended, go to next reward period if (periodsTotalReward[compVars.currentPeriod].end < compVars.to) { unchecked { ++compVars.currentPeriod; } continue; } // reward period has 0 rewards, go to next epoch if (periodsTotalReward[compVars.currentPeriod].epochReward == 0) { (compVars.from, compVars.to) = goToNextEpoch(compVars.to); continue; } // for first period, epoch rewards might already be accounted for, so take just proportionaly if (compVars.currentPeriod == 0 && compVars.to - compVars.from < EPOCH_DURATION) { unchecked { compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward.mulDivDown( compVars.to - compVars.from, EPOCH_DURATION ); } } else { compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward; } // compound unchecked { currAccRewardWeight += compVars.epochRewards.divWadDown(currTotalScore); compVars.compoundClaimable = (currAccRewardWeight - compVars.currCompLastAccRewardWeight).mulWadDown( currCompoundAmount * MAX_MULTIPLIER ); compVars.currCompLastAccRewardWeight = currAccRewardWeight; currCompoundAmount += compVars.compoundClaimable; currTotalScore += compVars.compoundClaimable * MAX_MULTIPLIER; } (compVars.from, compVars.to) = goToNextEpoch(compVars.to); } // auto compound is over, calculate potential new accrued reward weight if (compVars.from < block.timestamp && compVars.currentPeriod < periodsTotalReward.length) { // if last reward period ended with last epoch, and new period exist, go to new period if ( periodsTotalReward[compVars.currentPeriod].end < block.timestamp && compVars.currentPeriod < periodsTotalReward.length - zeroPeriods - 1 ) { unchecked { ++compVars.currentPeriod; } } if (periodsTotalReward[compVars.currentPeriod].end >= block.timestamp) { unchecked { uint256 newRewards = (periodsTotalReward[compVars.currentPeriod].epochReward * (block.timestamp - compVars.from)) / EPOCH_DURATION; currAccRewardWeight += newRewards.divWadDown(currTotalScore); } } } return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, currCompoundAmount); } // calculates rewards weight function getRewardWeightWithoutAutoComp() internal view returns (uint256) { // to avoid div by zero on first lock uint256 _totalScore = totalScore; if (_totalScore == 0) { return accRewardWeight; } uint256 _lastRewardUpdate = lastRewardUpdate; uint256 length = rewards.length; uint256 newRewards; Reward storage reward; for (uint256 rewardId = 0; rewardId < length; ) { reward = rewards[rewardId]; unchecked { ++rewardId; } uint256 start = reward.start; uint256 end = reward.end; if (block.timestamp < start) continue; if (_lastRewardUpdate > end) continue; newRewards += (min(block.timestamp, end) - max(start, _lastRewardUpdate)) * reward.amountPerSecond; } return newRewards == 0 ? accRewardWeight : accRewardWeight + newRewards.divWadDown(_totalScore); } // returns users score for all locks function getUsersNoCompoundScore(address user) internal view returns (uint256 score) { uint256 lockLength = locks[user].length; Lock storage lock; for (uint256 lockId = 0; lockId < lockLength; ++lockId) { lock = locks[user][lockId]; if (lockCompoundedBitMap.get(getBitMapIndex(lockId, user))) { continue; } score += lock.amount * lock.multiplier; } } /// @notice returns users claimable amount, not taking auto compound enabled locks into account function calculateUserClaimable(address user, uint256 accRewardsWeight_) internal view returns (uint256 claimable) { uint256 userScore = getUsersNoCompoundScore(user); unchecked { return calculateClaimable(userScore, accRewardsWeight_ - userLastAccRewardsWeight[user]); } } /// @notice calculates claimable amount given score and accrued reward weight difference function calculateClaimable(uint256 score, uint256 accRewardWeightDiff) internal pure returns (uint256) { return score.mulWadDown(accRewardWeightDiff); } /// @notice returns smaller of two uint256 function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x < y ? x : y; } /// @notice return bigger of two uint256 function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x > y ? x : y; } // returns multiplier on amount locked for duration in seconds times 100 // aprox of function (2592000,1),(31536000,2),(94608000,5),(157680000,10) // 2.22574×10^-16 x^2 + 2.19094×10^-8 x + 0.993975 function getDurationMultiplier(uint256 duration) internal pure returns (uint16) { if (duration < 30 days || duration > 1825 days) revert DurationOutOfBounds(duration); return uint16((222574 * duration * duration + 21909400000000 * duration + 993975000000000000000) / 1e19); } /// @notice returns uint256 index for bitmap used to indicate whether lock is enabled for auto compound /// @dev first 160 bits are address, last 96 bits are index, index is currently never bigger than 5 function getBitMapIndex(uint256 index, address addr) internal pure returns (uint256) { return uint256(index | (uint160(addr) << 96)); } /// @notice calculates new compound accrued reward weight, to have the same claimable amount with added amount function calculateCompAccRewardWeightIn( uint256 currCompoundAmount, uint256 incomingAmount, uint256 lastAccRewardWeight, uint256 lastCompAccRewardWeight ) internal pure returns (uint256) { return lastAccRewardWeight - ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) / (currCompoundAmount + incomingAmount); } /// @notice calculates new compound accrued reward weight, to have the same claimable amount with substracted amount function calculateCompAccRewardWeightOut( uint256 currCompoundAmount, uint256 incomingAmount, uint256 lastAccRewardWeight, uint256 lastCompAccRewardWeight ) internal pure returns (uint256) { if (incomingAmount == currCompoundAmount) return lastAccRewardWeight; return lastAccRewardWeight - ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) / (currCompoundAmount - incomingAmount); } function getEpoch(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % EPOCH_DURATION); } } /// @notice calculates eligible rewards for given time interval function getPeriodRewards( Reward[] memory rewardsMem, uint256 from, uint256 to ) internal pure returns (uint256 epochRewards) { for (uint256 i = 0; i < rewardsMem.length; ) { if (to < rewardsMem[i].start) { unchecked { ++i; } continue; } if (from > rewardsMem[i].end) { unchecked { ++i; } continue; } unchecked { epochRewards += (min(to, rewardsMem[i].end) - max(rewardsMem[i].start, from)) * rewardsMem[i].amountPerSecond; ++i; } } } /// @notice calculates total reward per epoch for multiple rewards that change on intersections function getTotalRewardPeriods( uint256[] memory intersections, Reward[] memory rewardsMem, uint256 emptyIntersections ) internal pure returns (TotalReward[] memory totalRewards, uint256 zeroPeriods) { totalRewards = new TotalReward[](intersections.length - emptyIntersections - 1); uint256 start; uint256 end; uint256 epochReward; uint256 j; uint256 periodsIdx; for (uint256 i = emptyIntersections; i < intersections.length - 1; ) { start = intersections[i]; end = intersections[i + 1]; if (start == end) { unchecked { ++zeroPeriods; ++i; } continue; } epochReward = 0; for (j = 0; j < rewardsMem.length; ) { if (rewardsMem[j].start > start) { unchecked { ++j; } continue; } if (rewardsMem[j].end < end) { unchecked { ++j; } continue; } unchecked { epochReward += EPOCH_DURATION * rewardsMem[j].amountPerSecond; ++j; } } unchecked { ++i; totalRewards[periodsIdx++] = TotalReward(start, end, epochReward); } } return (totalRewards, zeroPeriods); } /// @notice gets intersections of reward intervals and arbitrary interval function getPeriodIntersections( uint256 from, uint256 to, Reward[] memory rewardsMem ) internal pure returns (uint256[] memory, uint256) { // in the worst case where all rewards are eligible we're going to have x2 intersections uint256[] memory intersections = new uint256[](rewardsMem.length * 2); uint256 emptyIntersections; uint256 start; uint256 end; uint256 intersectionsIdx; for (uint256 i; i < rewardsMem.length; ) { start = max(from, rewardsMem[i].start); end = min(to, rewardsMem[i].end); unchecked { if (start < end) { intersections[intersectionsIdx++] = start; intersections[intersectionsIdx++] = end; } else { emptyIntersections += 2; } ++i; } } return (intersections, emptyIntersections); } /// @notice return next epoch start and ending point function goToNextEpoch(uint256 to) internal pure returns (uint256, uint256) { unchecked { return (to, to + EPOCH_DURATION); } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyAutoCompound","type":"error"},{"inputs":[],"name":"AmountIsZero","type":"error"},{"inputs":[],"name":"CanOnlyAddFutureRewards","type":"error"},{"inputs":[],"name":"CantAutoCompound","type":"error"},{"inputs":[],"name":"CantChangePast","type":"error"},{"inputs":[],"name":"CantUpdateExpiredLock","type":"error"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"DurationOutOfBounds","type":"error"},{"inputs":[],"name":"IntervalNotRoundedWithEpoch","type":"error"},{"inputs":[],"name":"LockStillActive","type":"error"},{"inputs":[],"name":"MaxLocksSucceeded","type":"error"},{"inputs":[],"name":"MaxRewardsSucceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"oldDuration","type":"uint256"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"MustProlongLock","type":"error"},{"inputs":[],"name":"NotAutoCompoundEnabled","type":"error"},{"inputs":[],"name":"NotRewardoor","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"RewardStartEqEnd","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"uint16","name":"oldMultiplier","type":"uint16"},{"internalType":"uint16","name":"newMultiplier","type":"uint16"}],"name":"UpdateToSmallerMultiplier","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroPrecision","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AutoCompoundDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"AutoCompoundEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"compoundAmount","type":"uint256"}],"name":"AutoCompounded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint208","name":"amount","type":"uint208"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"multiplier","type":"uint16"}],"name":"LockAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint8","name":"index","type":"uint8"},{"indexed":false,"internalType":"uint208","name":"amount","type":"uint208"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"multiplier","type":"uint16"}],"name":"LockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerSecond","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"RewardRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerSecond","type":"uint256"}],"name":"RewardUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardoor","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"RewardoorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Unlock","type":"event"},{"inputs":[],"name":"ALGORITHM_THRESHOLD_IN_EPOCHS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EPOCH_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LOCK_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REWARD_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accRewardWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint208","name":"amount","type":"uint208"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"addLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compoundAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundLastAccRewardWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAutoCompoundAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToAutoCompoundShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"disableAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"enableAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getLockLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewards","outputs":[{"components":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"internalType":"struct LockedStaking.Reward[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserClaimable","outputs":[{"internalType":"uint256","name":"claimable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getUserLocks","outputs":[{"components":[{"internalType":"uint16","name":"multiplier","type":"uint16"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint208","name":"amount","type":"uint208"}],"internalType":"struct LockedStaking.Lock[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"hasLockAutoCompoundEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapToken","type":"address"},{"internalType":"uint256","name":"_precision","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRewardUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"locks","outputs":[{"internalType":"uint16","name":"multiplier","type":"uint16"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint208","name":"amount","type":"uint208"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardoors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setRewardoor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalScore","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint208","name":"amount","type":"uint208"}],"name":"updateLockAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"updateLockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"newStart","type":"uint256"},{"internalType":"uint256","name":"newEnd","type":"uint256"},{"internalType":"uint256","name":"newAmountPerSecond","type":"uint256"}],"name":"updateReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateRewardsWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userLastAccRewardsWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6145b280620000f36000396000f3fe608060405234801561001057600080fd5b50600436106102de5760003560e01c80638da5cb5b11610186578063cd6dc687116100e3578063dc73e49c11610097578063ea25afda11610071578063ea25afda146105bc578063f2fde38b146105cf578063f301af42146105e257600080fd5b8063dc73e49c14610583578063dca4c9f814610596578063e3a150da146105a957600080fd5b8063d3b5dc3b116100c8578063d3b5dc3b14610572578063d7da1dee1461057b578063dc36a3d31461032957600080fd5b8063cd6dc6871461054c578063d2d26c601461055f57600080fd5b8063abf7fa041161013a578063b425f8021161011f578063b425f802146104ef578063c006719f14610530578063c553173f1461053957600080fd5b8063abf7fa0414610329578063b0128d3f146104c657600080fd5b8063a3c2710d1161016b578063a3c2710d146104ab578063a70b9f0c146104b4578063a86572a0146104bd57600080fd5b80638da5cb5b1461047357806399fd29801461049857600080fd5b80634e71d92d1161023f57806367148931116101f35780637eed69b5116101cd5780637eed69b51461043757806388267c59146104575780638c614c7a1461046057600080fd5b80636714893114610409578063715018a61461041c5780637a3a58df1461042457600080fd5b80635b7917d9116102245780635b7917d9146103da5780635d6a618d146103ed5780636198e339146103f657600080fd5b80634e71d92d146103c95780635a8583fd146103d157600080fd5b8063253418bc116102965780633cdaccb61161027b5780633cdaccb61461037a578063405d0a25146103ad57806348dcb051146103c057600080fd5b8063253418bc1461035f578063325e04531461036757600080fd5b806306afa8ef116102c757806306afa8ef146103165780630e3cf4441461032957806323a35de91461033f57600080fd5b8063043c9693146102e35780630572b0cc146102f8575b600080fd5b6102f66102f13660046140a8565b610621565b005b61030061087d565b60405161030d91906140c3565b60405180910390f35b6102f6610324366004614153565b610909565b610331600581565b60405190815260200161030d565b61035261034d36600461418a565b61098f565b60405161030d91906141a5565b610331610a2f565b6102f6610375366004614218565b610aa7565b61039d61038836600461418a565b606d6020526000908152604090205460ff1681565b604051901515815260200161030d565b6103316103bb36600461426b565b610eb5565b610331606f5481565b6102f6610ede565b61033160715481565b6102f66103e836600461426b565b611022565b6103316103e681565b6102f661040436600461426b565b6112b6565b6102f661041736600461429b565b6117fa565b6102f6611b80565b61033161043236600461426b565b611b94565b61033161044536600461418a565b60696020526000908152604090205481565b61033160705481565b61033161046e36600461418a565b611bb0565b6033546001600160a01b03165b6040516001600160a01b03909116815260200161030d565b6102f66104a63660046142c7565b611bca565b610331606a5481565b61033161708081565b610331606c5481565b6103316104d436600461418a565b6001600160a01b031660009081526068602052604090205490565b6105026104fd3660046142f1565b611eed565b6040805161ffff909416845263ffffffff90921660208401526001600160d01b03169082015260600161030d565b610331606b5481565b6102f661054736600461426b565b611f40565b6102f661055a3660046142f1565b612248565b61039d61056d3660046142f1565b61248f565b61033160665481565b606754610331565b606554610480906001600160a01b031681565b6102f66105a436600461426b565b6124bf565b6102f66105b736600461430d565b612716565b6102f66105ca36600461433f565b612bd2565b6102f66105dd36600461418a565b612efd565b6105f56105f036600461426b565b612fa7565b6040805163ffffffff94851681529390921660208401526001600160c01b03169082015260600161030d565b60ff81163360601b73ffffffffffffffff000000000000000000000000168117600881901c6000908152606e602052604090205490916001901b1615610693576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061069d610a2f565b905060006106ab3383612fef565b9050806000036106e7576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260696020908152604080832085905560689091528120805460ff87169081106107185761071861435b565b60009182526020909120018054909150426201000090910463ffffffff16101561076e576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054600090610791908490660100000000000090046001600160d01b03166143b9565b82546001600160d01b03821666010000000000000265ffffffffffff821617845590915061ffff166107c381856143cc565b606b60008282546107d491906143b9565b909155505060405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a282546040805160ff8a1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080015b60405180910390a250505050505050565b60606067805480602002602001604051908101604052809291908181526020016000905b82821015610900576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b0316908201528252600190920191016108a1565b50505050905090565b61091161302c565b6001600160a01b0382166000818152606d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f2b8508073c9bd6054077cb8ab52c19b9616a8970f3fcc0a7163b082f16fd560a91015b60405180910390a25050565b6001600160a01b0381166000908152606860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a24576000848152602090819020604080516060810182529185015461ffff8116835262010000810463ffffffff1683850152660100000000000090046001600160d01b0316908201528252600190920191016109c7565b505050509050919050565b6000806000806000610a3f6130a0565b42606a55606c8490556071839055606b829055606f54939750919550935091508114610a9e57606f8190556040518181527fa803098eab41616e8c09907603003b82c457356a707199ad558994e6187830539060200160405180910390a15b50919392505050565b336000908152606d602052604090205460ff16610af0576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6067547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01610b4b576040517f44fea23a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160c01b0316600003610b8e576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8163ffffffff168363ffffffff1603610bd3576040517fb78de82800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428363ffffffff161080610bec5750428263ffffffff16105b15610c23576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3561708063ffffffff8516614412565b15610c6c576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c7e61708063ffffffff8416614412565b15610cb5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608101825263ffffffff8086168252848116602083019081526001600160c01b038086169484019485526067805460018101825560009190915293517f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae909401805492519551909116680100000000000000000267ffffffffffffffff958416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316949093169390931717929092169190911790556065546001600160a01b03166323b872dd333084610d968888614426565b63ffffffff16610da6919061444a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526001600160c01b031660448201526064016020604051808303816000875af1158015610e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3f919061447c565b610e5c576040516312171d8360e31b815260040160405180910390fd5b6040805163ffffffff8086168252841660208201526001600160c01b038316918101919091527f9795f222c951ae3e749f872dbe287f78d21fa52353e9175cb20ed3aa2b29b82b906060015b60405180910390a1505050565b6070546000908015610ed557606f54610ed090849083613146565b610ed7565b825b9392505050565b6000610ee8610a2f565b90506000610ef63383612fef565b905080600003610f32576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152606960205260409081902084905560655490517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810192909252602482018390526001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd3919061447c565b610ff0576040516312171d8360e31b815260040160405180910390fd5b60405181815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d490602001610983565b600061102c610a2f565b9050600061103a3383612fef565b33600090815260686020526040812080549293509091859081106110605761106061435b565b60009182526020822001915073ffffffffffffffff0000000000000000000000003360601b168517600881901c6000908152606e6020526040902054909150600160ff83161b166110dd576040517f18c62fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604090208054600160ff84161b191690558154660100000000000090046001600160d01b0316600061111d82610eb5565b905061112f606f548288607154613164565b60718190555080606f60008282546111479190614499565b9250508190555081607060008282546111609190614499565b9091555050835465ffffffffffff1666010000000000006001600160d01b03831602178455336000908152606960205260409020869055841561127e576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018790526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b919061447c565b611248576040516312171d8360e31b815260040160405180910390fd5b60405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f45f21e7b59d72f575ccab5204bfb96c1af1aee613cffb4d1b9db2e757c25e8c5910161086c565b60006112c0610a2f565b33600090815260686020526040812080549293509091849081106112e6576112e661435b565b60009182526020909120018054909150426201000090910463ffffffff16111561133c576040517fba8dbe4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffff0000000000000000000000003360601b168417905060006113683385612fef565b600883901c6000908152606e6020526040812054919250600160ff85161b90911615801591906113ff578454660100000000000090046001600160d01b03166113b081610eb5565b91506113c2606f548389607154613164565b60718190555081606f60008282546113da9190614499565b9250508190555080607060008282546113f39190614499565b90915550611416915050565b508354660100000000000090046001600160d01b03165b3360009081526069602090815260408083208990558754606b805461ffff909216860290910390556068909152902054600019810190880360010161148557821561148057600885901c6000908152606e602052604090208054600160ff88161b19169055611682565b611682565b3360009081526068602052604090208054829081106114a6576114a661435b565b9060005260206000200160686000336001600160a01b03166001600160a01b0316815260200190815260200160002089815481106114e6576114e661435b565b6000918252602082208354910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000811661ffff9093169283178255845463ffffffff620100009182900416027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000009091169092179190911780825592546001600160d01b03660100000000000091829004160265ffffffffffff909316929092179091556115ad823360601b73ffffffffffffffff000000000000000000000000161790565b9050831561161f57600881901c6000908152606e6020526040902054600160ff83161b166115fa57600886901c6000908152606e602052604090208054600160ff89161b19169055611680565b600881901c6000908152606e602052604090208054600160ff84161b19169055611680565b600881901c6000908152606e6020526040902054600160ff83161b161561168057600886901c6000908152606e602052604090208054600160ff89161b179055600881901c6000908152606e602052604090208054600160ff84161b191690555b505b3360009081526068602052604090208054806116a0576116a06144ac565b6000828152602081208201600019908101919091550190556065546001600160a01b031663a9059cbb336116d487866143b9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175b919061447c565b611778576040516312171d8360e31b815260040160405180910390fd5b83156117b45760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b60408051838152602081018a905233917ff7870c5b224cbc19873599e46ccfc7103934650509b1af0c3ce90138377c200491015b60405180910390a25050505050505050565b806001600160d01b031660000361183d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611847610a2f565b905060006118553383612fef565b9050600061186c826001600160d01b0386166143b9565b33600090815260686020526040812080549293509091879081106118925761189261435b565b60009182526020909120018054909150426201000090910463ffffffff1610156118e8576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f73ffffffffffffffff0000000000000000000000003360601b1688175b600881901c6000908152606e6020526040902054600160ff9092169190911b16151590565b156119a9576000606f5490506119498185886071546131b0565b607155600061195785611b94565b905061196385836143b9565b606f81905550806070600082825461197b91906143b9565b909155505083546119a0908290660100000000000090046001600160d01b03166143b9565b925050506119cc565b81546119c9908490660100000000000090046001600160d01b03166143b9565b90505b81546001600160d01b03821666010000000000000265ffffffffffff82168117845533600090815260696020526040902087905561ffff908116911617611a1381856143cc565b606b6000828254611a2491906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac5919061447c565b611ae2576040516312171d8360e31b815260040160405180910390fd5b8415611b1e5760405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b82546040805160ff8b1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080016117e8565b611b8861302c565b611b9260006131bc565b565b6070546000908015610ed557606f54610ed09084908390613146565b600080611bbb6130a0565b5050509050610ed78382612fef565b816001600160d01b0316600003611c0d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152606860205260409020547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01611c75576040517f5ad3064300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7f610a2f565b90506000611c8d3383612fef565b90506000611ca46001600160d01b038616836143b9565b336000908152606960205260408120859055909150611cc385426143b9565b90506000611cd086613226565b336000908152606860209081526040808320815160608101835261ffff80871680835263ffffffff808b168488019081526001600160d01b03808e169786019788528654600181018855968a529790982093519390940180549751955190961666010000000000000265ffffffffffff9590941662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090971692909116919091179490941791909116179055909150611d8e9084906143cc565b606b6000828254611d9f91906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e40919061447c565b611e5d576040516312171d8360e31b815260040160405180910390fd5b8315611e995760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080516001600160d01b038516815263ffffffff8416602082015261ffff83169181019190915233907f7b2d54511a19cedc58c31bf2a96ea21396676caf714de85f97ab140a3a4ff1129060600161086c565b60686020528160005260406000208181548110611f0957600080fd5b60009182526020909120015461ffff8116925062010000810463ffffffff169150660100000000000090046001600160d01b031683565b336000908152606d602052604090205460ff16611f89576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f91610a2f565b50600060678281548110611fa757611fa761435b565b600091825260209182902060408051606081018252919092015463ffffffff8082168352640100000000820416938201939093526001600160c01b03680100000000000000009093049290921690820152606780549192509061200c90600190614499565b8154811061201c5761201c61435b565b90600052602060002001606783815481106120395761203961435b565b6000918252602090912082549101805463ffffffff9283167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082168117835584547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921617640100000000918290049093160291909117808255915467ffffffffffffffff90921668010000000000000000928390046001600160c01b031690920291909117905560678054806120f3576120f36144ac565b6000828152602080822060001990840181019290925591019091558101514263ffffffff909116111561221157600081604001516001600160c01b031661214442846000015163ffffffff166132ce565b836020015163ffffffff166121599190614499565b61216391906143cc565b6065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390529192506001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156121ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f2919061447c565b61220f576040516312171d8360e31b815260040160405180910390fd5b505b6040518281527f5d3a571a89edce81bd931e9d740ff7f0560940fc502a27f178f002eca691dfd99060200160405180910390a15050565b600054610100900460ff16158080156122685750600054600160ff909116105b806122825750303b158015612282575060005460ff166001145b612313576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561237157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0383166123b1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036123eb576040517fd41c43dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516179055606682905561242b6132e4565b801561248a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610ea8565b505050565b60006124b661190a838560601b73ffffffffffffffff000000000000000000000000161790565b90505b92915050565b60006124c9610a2f565b905060006124d73383612fef565b33600090815260686020526040812080549293509091859081106124fd576124fd61435b565b6000918252602090912001805490915061ffff166103e61461254b576040517fbe53ebc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360601b73ffffffffffffffff000000000000000000000000168417600881901c6000908152606e6020526040902054600160ff87161b16156125ba576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604081208054600160ff85161b17905582546125f9908590660100000000000090046001600160d01b03166143b9565b9050600061260682611b94565b9050612618606f5483886071546131b0565b60718190555081606f600082825461263091906143b9565b92505081905550806070600082825461264991906143b9565b9091555050835465ffffffffffff1666010000000000006001600160d01b0383160217845533600090815260696020526040902086905584156126de576126926103e6866143cc565b606b60008282546126a391906143b9565b909155505060405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f49311a438ed24b95a0b16011315cf7525bb5b88be477d6d37b57aabc85017c08910161086c565b336000908152606d602052604090205460ff1661275f576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61276b61708084614412565b156127a2576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ae61708083614412565b156127e5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361281f576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612827610a2f565b5060006067858154811061283d5761283d61435b565b60009182526020909120018054909150640100000000900463ffffffff1642811015612895576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428410156128cf576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815463ffffffff16428110806128e457504286105b80156128f05750808614155b15612927576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846129348888614499565b61293e91906143cc565b84549091506000906801000000000000000090046001600160c01b03166129658486614499565b61296f91906143cc565b90508288146129a75784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff89161785555b845463ffffffff9081166401000000009189169190910267ffffffffffffffff1617680100000000000000006001600160c01b0388160217855581811115612aae576065546001600160a01b031663a9059cbb33612a058585614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061447c565b612aa9576040516312171d8360e31b815260040160405180910390fd5b612b7f565b818114612b7f576065546001600160a01b03166323b872dd3330612ad28587614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b62919061447c565b612b7f576040516312171d8360e31b815260040160405180910390fd5b604080518a8152602081018a9052908101889052606081018790527fce702e82d3aef8d6cd9b4dc0baace0b1e11e83af272382cd526d351c5162d1e09060800160405180910390a1505050505050505050565b6000612bdc610a2f565b3360009081526068602052604081208054929350909160ff8616908110612c0557612c0561435b565b600091825260208220019150612c1b84426143b9565b825490915063ffffffff808316620100009092041610612c805781546040517f1e96fff80000000000000000000000000000000000000000000000000000000081526201000090910463ffffffff90811660048301528216602482015260440161230a565b6000612c8c3385612fef565b336000908152606960205260408120869055909150612caa86613226565b845463ffffffff851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff82168117875591925061ffff91821690821617908216811115612d36576040517f2759864a00000000000000000000000000000000000000000000000000000000815261ffff80831660048301528316602482015260440161230a565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff831617808655660100000000000090046001600160d01b031680612d8183856144db565b61ffff16612d8f91906144f6565b6001600160d01b0316606b6000828254612da991906143b9565b90915550508315612e95576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061447c565b612e5f576040516312171d8360e31b815260040160405180910390fd5b60405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b6040805160ff8b1681526001600160d01b038316602082015263ffffffff87168183015261ffff85166060820152905133917fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2919081900360800190a2505050505050505050565b612f0561302c565b6001600160a01b038116612f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161230a565b612fa4816131bc565b50565b60678181548110612fb757600080fd5b60009182526020909120015463ffffffff8082169250640100000000820416906801000000000000000090046001600160c01b031683565b600080612ffb84613383565b6001600160a01b0385166000908152606960205260409020549091506130249082908503613458565b949350505050565b6033546001600160a01b03163314611b92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161230a565b6000806000806000606a5490504281036130ce57606c54607154606b54606f54945094509450945050613140565b617080808206820390429081069003808203613105576130ec613464565b607154606b54606f549650965096509650505050613140565b600561708083830304111561312c5761311c613568565b9650965096509650505050613140565b6131346139b5565b96509650965096505050505b90919293565b600082600019048411830215820261315d57600080fd5b5091020490565b6000848403613174575081613024565b61317e8486614499565b856131898486614499565b61319391906143cc565b61319d919061451f565b6131a79084614499565b95945050505050565b600061317e84866143b9565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062278d0082108061323c5750630966018082115b15613276576040517f91aaaf240000000000000000000000000000000000000000000000000000000081526004810183905260240161230a565b678ac7230489e8000061328f836513ed2e0116006143cc565b8361329d816203656e6143cc565b6132a791906143cc565b6132b191906143b9565b6132c4906835e22c9431dae580006143b9565b6124b9919061451f565b60008183116132dd57816124b6565b5090919050565b600054610100900460ff1661337b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92613b26565b6001600160a01b03811660009081526068602052604081205481805b82811015613450576001600160a01b03851660009081526068602052604090208054829081106133d1576133d161435b565b90600052602060002001915061340261190a828760601b73ffffffffffffffff000000000000000000000000161790565b61344057815461342a9061ffff811690660100000000000090046001600160d01b03166144f6565b61343d906001600160d01b0316856143b9565b93505b61344981614533565b905061339f565b505050919050565b60006124b68383613bc6565b606b54600090808203613479575050606c5490565b606a54606754600080805b83811015613537576067818154811061349f5761349f61435b565b6000918252602090912001805490925060019091019063ffffffff80821691640100000000900416428211156134d6575050613484565b808711156134e5575050613484565b83546801000000000000000090046001600160c01b031661350683896132ce565b6135104284613bdb565b61351a9190614499565b61352491906143cc565b61352e90866143b9565b94505050613484565b50811561355a576135488286613bea565b606c5461355591906143b9565b61355e565b606c545b9550505050505090565b6000806000806000606b5490508060000361359557606c5460715482606f54945094509450945050613140565b6135ce6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b606a548152606c5460715460a0830152606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613663576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613604565b50505050905060008061367b86600001514285613bff565b91509150808251036136a557848660a0015188606f549a509a509a509a5050505050505050613140565b6136ae82613d3d565b6000806136bc848685613d92565b895191935091506136d5906170809081810690036143b9565b60208901525b428860200151111580156136fe57508082516136f79190614499565b8860400151105b156138ad5787600001518289604001518151811061371e5761371e61435b565b602002602001015160000151111561374757602088015161708081015b60208a015288526136db565b8760200151828960400151815181106137625761376261435b565b60200260200101516020015110156137845760408801805160010190526136db565b8188604001518151811061379a5761379a61435b565b6020026020010151604001516000036137bc576020880151617080810161373b565b60408801511580156137df575087516020890151617080916137dd91614499565b105b15613830576138268860000151896020015103617080848b604001518151811061380b5761380b61435b565b6020026020010151604001516131469092919063ffffffff16565b608089015261385c565b818860400151815181106138465761384661435b565b6020026020010151604001518860800181815250505b608088015161386b908a613bea565b60a08901519701966138839088036103e68802613bc6565b6060890181905260a0890188905260208901516103e682029a909a0199960195617080810161373b565b8751421180156138c1575081518860400151105b156139995742828960400151815181106138dd576138dd61435b565b602002602001015160200151108015613911575060018183516139009190614499565b61390a9190614499565b8860400151105b156139225760408801805160010190525b42828960400151815181106139395761393961435b565b6020026020010151602001511061399957600061708089600001514203848b604001518151811061396c5761396c61435b565b6020026020010151604001510281613986576139866143e3565b049050613993818b613bea565b88019750505b5050505060a09390930151919891975092955091935090915050565b6000806000806000606b549050806000036139e257606c5460715482606f54945094509450945050613140565b606a54606c54607154606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613a70576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613a11565b509293508792506000915081905080613a8f61708080860686036143b9565b92505b428311613ae457613aa4858585613f9e565b9150613ab0828b613bea565b90970196613ac48789036103e68802613bc6565b6103e681029a909a01998897509586019592935050617080830191613a92565b42841015613b1057613af7858542613f9e565b9150613b03828b613bea565b613b0d90896143b9565b97505b50959c949b509699509197509195505050505050565b600054610100900460ff16613bbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92336131bc565b60006124b68383670de0b6b3a7640000613146565b60008183106132dd57816124b6565b60006124b683670de0b6b3a764000084613146565b606060008083516002613c1291906143cc565b67ffffffffffffffff811115613c2a57613c2a61454d565b604051908082528060200260200182016040528015613c53578160200160208202803683370190505b50905060008060008060005b8851811015613d2c57613c958b8a8381518110613c7e57613c7e61435b565b60200260200101516000015163ffffffff166132ce565b9350613cc48a8a8381518110613cad57613cad61435b565b60200260200101516020015163ffffffff16613bdb565b925082841015613d1d5783868380600101945081518110613ce757613ce761435b565b60200260200101818152505082868380600101945081518110613d0c57613d0c61435b565b602002602001018181525050613d24565b6002850194505b600101613c5f565b509399929850919650505050505050565b8051600082528060051b82016020601f198185015b8201838111613d8a5780518282018051828111613d7157505050613d52565b5b8186015283018051828111613d725750840152613d52565b505050915250565b606060006001838651613da59190614499565b613daf9190614499565b67ffffffffffffffff811115613dc757613dc761454d565b604051908082528060200260200182016040528015613e1c57816020015b613e0960405180606001604052806000815260200160008152602001600081525090565b815260200190600190039081613de55790505b509150600080808080875b60018b51613e359190614499565b811015613f90578a8181518110613e4e57613e4e61435b565b602002602001015195508a816001613e6691906143b9565b81518110613e7657613e7661435b565b60200260200101519450848603613e935760019687019601613e27565b60009350600092505b8951831015613f4b57858a8481518110613eb857613eb861435b565b60200260200101516000015163ffffffff161115613edb57826001019250613e9c565b848a8481518110613eee57613eee61435b565b60200260200101516020015163ffffffff161015613f1157826001019250613e9c565b898381518110613f2357613f2361435b565b6020026020010151604001516001600160c01b03166170800284019350826001019250613e9c565b604080516060810182528781526020810187905290810185905288516001848101949301928a918110613f8057613f8061435b565b6020026020010181905250613e27565b505050505050935093915050565b6000805b845181101561408a57848181518110613fbd57613fbd61435b565b60200260200101516000015163ffffffff16831015613fde57600101613fa2565b848181518110613ff057613ff061435b565b60200260200101516020015163ffffffff1684111561401157600101613fa2565b8481815181106140235761402361435b565b6020026020010151604001516001600160c01b031661406586838151811061404d5761404d61435b565b60200260200101516000015163ffffffff16866132ce565b61407b85888581518110613cad57613cad61435b565b03029190910190600101613fa2565b509392505050565b803560ff811681146140a357600080fd5b919050565b6000602082840312156140ba57600080fd5b6124b682614092565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805163ffffffff90811686528782015116878601528501516001600160c01b031685850152606090930192908501906001016140e0565b5091979650505050505050565b80356001600160a01b03811681146140a357600080fd5b8015158114612fa457600080fd5b6000806040838503121561416657600080fd5b61416f8361412e565b9150602083013561417f81614145565b809150509250929050565b60006020828403121561419c57600080fd5b6124b68261412e565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805161ffff1685528681015163ffffffff16878601528501516001600160d01b031685850152606090930192908501906001016141c2565b803563ffffffff811681146140a357600080fd5b60008060006060848603121561422d57600080fd5b61423684614204565b925061424460208501614204565b915060408401356001600160c01b038116811461426057600080fd5b809150509250925092565b60006020828403121561427d57600080fd5b5035919050565b80356001600160d01b03811681146140a357600080fd5b600080604083850312156142ae57600080fd5b823591506142be60208401614284565b90509250929050565b600080604083850312156142da57600080fd5b6142e383614284565b946020939093013593505050565b6000806040838503121561430457600080fd5b6142e38361412e565b6000806000806080858703121561432357600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121561435257600080fd5b6142e383614092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156124b9576124b961438a565b80820281158282048414176124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614421576144216143e3565b500690565b63ffffffff8281168282160390808211156144435761444361438a565b5092915050565b6001600160c01b038281168282168181028316929181158285048214176144735761447361438a565b50505092915050565b60006020828403121561448e57600080fd5b8151610ed781614145565b818103818111156124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61ffff8281168282160390808211156144435761444361438a565b6001600160d01b038281168282168181028316929181158285048214176144735761447361438a565b60008261452e5761452e6143e3565b500490565b600060001982036145465761454661438a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212209d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea24364736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102de5760003560e01c80638da5cb5b11610186578063cd6dc687116100e3578063dc73e49c11610097578063ea25afda11610071578063ea25afda146105bc578063f2fde38b146105cf578063f301af42146105e257600080fd5b8063dc73e49c14610583578063dca4c9f814610596578063e3a150da146105a957600080fd5b8063d3b5dc3b116100c8578063d3b5dc3b14610572578063d7da1dee1461057b578063dc36a3d31461032957600080fd5b8063cd6dc6871461054c578063d2d26c601461055f57600080fd5b8063abf7fa041161013a578063b425f8021161011f578063b425f802146104ef578063c006719f14610530578063c553173f1461053957600080fd5b8063abf7fa0414610329578063b0128d3f146104c657600080fd5b8063a3c2710d1161016b578063a3c2710d146104ab578063a70b9f0c146104b4578063a86572a0146104bd57600080fd5b80638da5cb5b1461047357806399fd29801461049857600080fd5b80634e71d92d1161023f57806367148931116101f35780637eed69b5116101cd5780637eed69b51461043757806388267c59146104575780638c614c7a1461046057600080fd5b80636714893114610409578063715018a61461041c5780637a3a58df1461042457600080fd5b80635b7917d9116102245780635b7917d9146103da5780635d6a618d146103ed5780636198e339146103f657600080fd5b80634e71d92d146103c95780635a8583fd146103d157600080fd5b8063253418bc116102965780633cdaccb61161027b5780633cdaccb61461037a578063405d0a25146103ad57806348dcb051146103c057600080fd5b8063253418bc1461035f578063325e04531461036757600080fd5b806306afa8ef116102c757806306afa8ef146103165780630e3cf4441461032957806323a35de91461033f57600080fd5b8063043c9693146102e35780630572b0cc146102f8575b600080fd5b6102f66102f13660046140a8565b610621565b005b61030061087d565b60405161030d91906140c3565b60405180910390f35b6102f6610324366004614153565b610909565b610331600581565b60405190815260200161030d565b61035261034d36600461418a565b61098f565b60405161030d91906141a5565b610331610a2f565b6102f6610375366004614218565b610aa7565b61039d61038836600461418a565b606d6020526000908152604090205460ff1681565b604051901515815260200161030d565b6103316103bb36600461426b565b610eb5565b610331606f5481565b6102f6610ede565b61033160715481565b6102f66103e836600461426b565b611022565b6103316103e681565b6102f661040436600461426b565b6112b6565b6102f661041736600461429b565b6117fa565b6102f6611b80565b61033161043236600461426b565b611b94565b61033161044536600461418a565b60696020526000908152604090205481565b61033160705481565b61033161046e36600461418a565b611bb0565b6033546001600160a01b03165b6040516001600160a01b03909116815260200161030d565b6102f66104a63660046142c7565b611bca565b610331606a5481565b61033161708081565b610331606c5481565b6103316104d436600461418a565b6001600160a01b031660009081526068602052604090205490565b6105026104fd3660046142f1565b611eed565b6040805161ffff909416845263ffffffff90921660208401526001600160d01b03169082015260600161030d565b610331606b5481565b6102f661054736600461426b565b611f40565b6102f661055a3660046142f1565b612248565b61039d61056d3660046142f1565b61248f565b61033160665481565b606754610331565b606554610480906001600160a01b031681565b6102f66105a436600461426b565b6124bf565b6102f66105b736600461430d565b612716565b6102f66105ca36600461433f565b612bd2565b6102f66105dd36600461418a565b612efd565b6105f56105f036600461426b565b612fa7565b6040805163ffffffff94851681529390921660208401526001600160c01b03169082015260600161030d565b60ff81163360601b73ffffffffffffffff000000000000000000000000168117600881901c6000908152606e602052604090205490916001901b1615610693576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061069d610a2f565b905060006106ab3383612fef565b9050806000036106e7576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260696020908152604080832085905560689091528120805460ff87169081106107185761071861435b565b60009182526020909120018054909150426201000090910463ffffffff16101561076e576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054600090610791908490660100000000000090046001600160d01b03166143b9565b82546001600160d01b03821666010000000000000265ffffffffffff821617845590915061ffff166107c381856143cc565b606b60008282546107d491906143b9565b909155505060405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a282546040805160ff8a1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080015b60405180910390a250505050505050565b60606067805480602002602001604051908101604052809291908181526020016000905b82821015610900576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b0316908201528252600190920191016108a1565b50505050905090565b61091161302c565b6001600160a01b0382166000818152606d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f2b8508073c9bd6054077cb8ab52c19b9616a8970f3fcc0a7163b082f16fd560a91015b60405180910390a25050565b6001600160a01b0381166000908152606860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a24576000848152602090819020604080516060810182529185015461ffff8116835262010000810463ffffffff1683850152660100000000000090046001600160d01b0316908201528252600190920191016109c7565b505050509050919050565b6000806000806000610a3f6130a0565b42606a55606c8490556071839055606b829055606f54939750919550935091508114610a9e57606f8190556040518181527fa803098eab41616e8c09907603003b82c457356a707199ad558994e6187830539060200160405180910390a15b50919392505050565b336000908152606d602052604090205460ff16610af0576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6067547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01610b4b576040517f44fea23a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160c01b0316600003610b8e576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8163ffffffff168363ffffffff1603610bd3576040517fb78de82800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428363ffffffff161080610bec5750428263ffffffff16105b15610c23576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3561708063ffffffff8516614412565b15610c6c576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c7e61708063ffffffff8416614412565b15610cb5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608101825263ffffffff8086168252848116602083019081526001600160c01b038086169484019485526067805460018101825560009190915293517f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae909401805492519551909116680100000000000000000267ffffffffffffffff958416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316949093169390931717929092169190911790556065546001600160a01b03166323b872dd333084610d968888614426565b63ffffffff16610da6919061444a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526001600160c01b031660448201526064016020604051808303816000875af1158015610e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3f919061447c565b610e5c576040516312171d8360e31b815260040160405180910390fd5b6040805163ffffffff8086168252841660208201526001600160c01b038316918101919091527f9795f222c951ae3e749f872dbe287f78d21fa52353e9175cb20ed3aa2b29b82b906060015b60405180910390a1505050565b6070546000908015610ed557606f54610ed090849083613146565b610ed7565b825b9392505050565b6000610ee8610a2f565b90506000610ef63383612fef565b905080600003610f32576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152606960205260409081902084905560655490517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810192909252602482018390526001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd3919061447c565b610ff0576040516312171d8360e31b815260040160405180910390fd5b60405181815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d490602001610983565b600061102c610a2f565b9050600061103a3383612fef565b33600090815260686020526040812080549293509091859081106110605761106061435b565b60009182526020822001915073ffffffffffffffff0000000000000000000000003360601b168517600881901c6000908152606e6020526040902054909150600160ff83161b166110dd576040517f18c62fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604090208054600160ff84161b191690558154660100000000000090046001600160d01b0316600061111d82610eb5565b905061112f606f548288607154613164565b60718190555080606f60008282546111479190614499565b9250508190555081607060008282546111609190614499565b9091555050835465ffffffffffff1666010000000000006001600160d01b03831602178455336000908152606960205260409020869055841561127e576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018790526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b919061447c565b611248576040516312171d8360e31b815260040160405180910390fd5b60405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f45f21e7b59d72f575ccab5204bfb96c1af1aee613cffb4d1b9db2e757c25e8c5910161086c565b60006112c0610a2f565b33600090815260686020526040812080549293509091849081106112e6576112e661435b565b60009182526020909120018054909150426201000090910463ffffffff16111561133c576040517fba8dbe4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffff0000000000000000000000003360601b168417905060006113683385612fef565b600883901c6000908152606e6020526040812054919250600160ff85161b90911615801591906113ff578454660100000000000090046001600160d01b03166113b081610eb5565b91506113c2606f548389607154613164565b60718190555081606f60008282546113da9190614499565b9250508190555080607060008282546113f39190614499565b90915550611416915050565b508354660100000000000090046001600160d01b03165b3360009081526069602090815260408083208990558754606b805461ffff909216860290910390556068909152902054600019810190880360010161148557821561148057600885901c6000908152606e602052604090208054600160ff88161b19169055611682565b611682565b3360009081526068602052604090208054829081106114a6576114a661435b565b9060005260206000200160686000336001600160a01b03166001600160a01b0316815260200190815260200160002089815481106114e6576114e661435b565b6000918252602082208354910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000811661ffff9093169283178255845463ffffffff620100009182900416027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000009091169092179190911780825592546001600160d01b03660100000000000091829004160265ffffffffffff909316929092179091556115ad823360601b73ffffffffffffffff000000000000000000000000161790565b9050831561161f57600881901c6000908152606e6020526040902054600160ff83161b166115fa57600886901c6000908152606e602052604090208054600160ff89161b19169055611680565b600881901c6000908152606e602052604090208054600160ff84161b19169055611680565b600881901c6000908152606e6020526040902054600160ff83161b161561168057600886901c6000908152606e602052604090208054600160ff89161b179055600881901c6000908152606e602052604090208054600160ff84161b191690555b505b3360009081526068602052604090208054806116a0576116a06144ac565b6000828152602081208201600019908101919091550190556065546001600160a01b031663a9059cbb336116d487866143b9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175b919061447c565b611778576040516312171d8360e31b815260040160405180910390fd5b83156117b45760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b60408051838152602081018a905233917ff7870c5b224cbc19873599e46ccfc7103934650509b1af0c3ce90138377c200491015b60405180910390a25050505050505050565b806001600160d01b031660000361183d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611847610a2f565b905060006118553383612fef565b9050600061186c826001600160d01b0386166143b9565b33600090815260686020526040812080549293509091879081106118925761189261435b565b60009182526020909120018054909150426201000090910463ffffffff1610156118e8576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f73ffffffffffffffff0000000000000000000000003360601b1688175b600881901c6000908152606e6020526040902054600160ff9092169190911b16151590565b156119a9576000606f5490506119498185886071546131b0565b607155600061195785611b94565b905061196385836143b9565b606f81905550806070600082825461197b91906143b9565b909155505083546119a0908290660100000000000090046001600160d01b03166143b9565b925050506119cc565b81546119c9908490660100000000000090046001600160d01b03166143b9565b90505b81546001600160d01b03821666010000000000000265ffffffffffff82168117845533600090815260696020526040902087905561ffff908116911617611a1381856143cc565b606b6000828254611a2491906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac5919061447c565b611ae2576040516312171d8360e31b815260040160405180910390fd5b8415611b1e5760405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b82546040805160ff8b1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080016117e8565b611b8861302c565b611b9260006131bc565b565b6070546000908015610ed557606f54610ed09084908390613146565b600080611bbb6130a0565b5050509050610ed78382612fef565b816001600160d01b0316600003611c0d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152606860205260409020547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01611c75576040517f5ad3064300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7f610a2f565b90506000611c8d3383612fef565b90506000611ca46001600160d01b038616836143b9565b336000908152606960205260408120859055909150611cc385426143b9565b90506000611cd086613226565b336000908152606860209081526040808320815160608101835261ffff80871680835263ffffffff808b168488019081526001600160d01b03808e169786019788528654600181018855968a529790982093519390940180549751955190961666010000000000000265ffffffffffff9590941662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090971692909116919091179490941791909116179055909150611d8e9084906143cc565b606b6000828254611d9f91906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e40919061447c565b611e5d576040516312171d8360e31b815260040160405180910390fd5b8315611e995760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080516001600160d01b038516815263ffffffff8416602082015261ffff83169181019190915233907f7b2d54511a19cedc58c31bf2a96ea21396676caf714de85f97ab140a3a4ff1129060600161086c565b60686020528160005260406000208181548110611f0957600080fd5b60009182526020909120015461ffff8116925062010000810463ffffffff169150660100000000000090046001600160d01b031683565b336000908152606d602052604090205460ff16611f89576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f91610a2f565b50600060678281548110611fa757611fa761435b565b600091825260209182902060408051606081018252919092015463ffffffff8082168352640100000000820416938201939093526001600160c01b03680100000000000000009093049290921690820152606780549192509061200c90600190614499565b8154811061201c5761201c61435b565b90600052602060002001606783815481106120395761203961435b565b6000918252602090912082549101805463ffffffff9283167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082168117835584547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921617640100000000918290049093160291909117808255915467ffffffffffffffff90921668010000000000000000928390046001600160c01b031690920291909117905560678054806120f3576120f36144ac565b6000828152602080822060001990840181019290925591019091558101514263ffffffff909116111561221157600081604001516001600160c01b031661214442846000015163ffffffff166132ce565b836020015163ffffffff166121599190614499565b61216391906143cc565b6065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390529192506001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156121ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f2919061447c565b61220f576040516312171d8360e31b815260040160405180910390fd5b505b6040518281527f5d3a571a89edce81bd931e9d740ff7f0560940fc502a27f178f002eca691dfd99060200160405180910390a15050565b600054610100900460ff16158080156122685750600054600160ff909116105b806122825750303b158015612282575060005460ff166001145b612313576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561237157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0383166123b1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036123eb576040517fd41c43dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516179055606682905561242b6132e4565b801561248a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610ea8565b505050565b60006124b661190a838560601b73ffffffffffffffff000000000000000000000000161790565b90505b92915050565b60006124c9610a2f565b905060006124d73383612fef565b33600090815260686020526040812080549293509091859081106124fd576124fd61435b565b6000918252602090912001805490915061ffff166103e61461254b576040517fbe53ebc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360601b73ffffffffffffffff000000000000000000000000168417600881901c6000908152606e6020526040902054600160ff87161b16156125ba576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604081208054600160ff85161b17905582546125f9908590660100000000000090046001600160d01b03166143b9565b9050600061260682611b94565b9050612618606f5483886071546131b0565b60718190555081606f600082825461263091906143b9565b92505081905550806070600082825461264991906143b9565b9091555050835465ffffffffffff1666010000000000006001600160d01b0383160217845533600090815260696020526040902086905584156126de576126926103e6866143cc565b606b60008282546126a391906143b9565b909155505060405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f49311a438ed24b95a0b16011315cf7525bb5b88be477d6d37b57aabc85017c08910161086c565b336000908152606d602052604090205460ff1661275f576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61276b61708084614412565b156127a2576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ae61708083614412565b156127e5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361281f576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612827610a2f565b5060006067858154811061283d5761283d61435b565b60009182526020909120018054909150640100000000900463ffffffff1642811015612895576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428410156128cf576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815463ffffffff16428110806128e457504286105b80156128f05750808614155b15612927576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846129348888614499565b61293e91906143cc565b84549091506000906801000000000000000090046001600160c01b03166129658486614499565b61296f91906143cc565b90508288146129a75784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff89161785555b845463ffffffff9081166401000000009189169190910267ffffffffffffffff1617680100000000000000006001600160c01b0388160217855581811115612aae576065546001600160a01b031663a9059cbb33612a058585614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061447c565b612aa9576040516312171d8360e31b815260040160405180910390fd5b612b7f565b818114612b7f576065546001600160a01b03166323b872dd3330612ad28587614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b62919061447c565b612b7f576040516312171d8360e31b815260040160405180910390fd5b604080518a8152602081018a9052908101889052606081018790527fce702e82d3aef8d6cd9b4dc0baace0b1e11e83af272382cd526d351c5162d1e09060800160405180910390a1505050505050505050565b6000612bdc610a2f565b3360009081526068602052604081208054929350909160ff8616908110612c0557612c0561435b565b600091825260208220019150612c1b84426143b9565b825490915063ffffffff808316620100009092041610612c805781546040517f1e96fff80000000000000000000000000000000000000000000000000000000081526201000090910463ffffffff90811660048301528216602482015260440161230a565b6000612c8c3385612fef565b336000908152606960205260408120869055909150612caa86613226565b845463ffffffff851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff82168117875591925061ffff91821690821617908216811115612d36576040517f2759864a00000000000000000000000000000000000000000000000000000000815261ffff80831660048301528316602482015260440161230a565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff831617808655660100000000000090046001600160d01b031680612d8183856144db565b61ffff16612d8f91906144f6565b6001600160d01b0316606b6000828254612da991906143b9565b90915550508315612e95576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061447c565b612e5f576040516312171d8360e31b815260040160405180910390fd5b60405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b6040805160ff8b1681526001600160d01b038316602082015263ffffffff87168183015261ffff85166060820152905133917fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2919081900360800190a2505050505050505050565b612f0561302c565b6001600160a01b038116612f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161230a565b612fa4816131bc565b50565b60678181548110612fb757600080fd5b60009182526020909120015463ffffffff8082169250640100000000820416906801000000000000000090046001600160c01b031683565b600080612ffb84613383565b6001600160a01b0385166000908152606960205260409020549091506130249082908503613458565b949350505050565b6033546001600160a01b03163314611b92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161230a565b6000806000806000606a5490504281036130ce57606c54607154606b54606f54945094509450945050613140565b617080808206820390429081069003808203613105576130ec613464565b607154606b54606f549650965096509650505050613140565b600561708083830304111561312c5761311c613568565b9650965096509650505050613140565b6131346139b5565b96509650965096505050505b90919293565b600082600019048411830215820261315d57600080fd5b5091020490565b6000848403613174575081613024565b61317e8486614499565b856131898486614499565b61319391906143cc565b61319d919061451f565b6131a79084614499565b95945050505050565b600061317e84866143b9565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062278d0082108061323c5750630966018082115b15613276576040517f91aaaf240000000000000000000000000000000000000000000000000000000081526004810183905260240161230a565b678ac7230489e8000061328f836513ed2e0116006143cc565b8361329d816203656e6143cc565b6132a791906143cc565b6132b191906143b9565b6132c4906835e22c9431dae580006143b9565b6124b9919061451f565b60008183116132dd57816124b6565b5090919050565b600054610100900460ff1661337b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92613b26565b6001600160a01b03811660009081526068602052604081205481805b82811015613450576001600160a01b03851660009081526068602052604090208054829081106133d1576133d161435b565b90600052602060002001915061340261190a828760601b73ffffffffffffffff000000000000000000000000161790565b61344057815461342a9061ffff811690660100000000000090046001600160d01b03166144f6565b61343d906001600160d01b0316856143b9565b93505b61344981614533565b905061339f565b505050919050565b60006124b68383613bc6565b606b54600090808203613479575050606c5490565b606a54606754600080805b83811015613537576067818154811061349f5761349f61435b565b6000918252602090912001805490925060019091019063ffffffff80821691640100000000900416428211156134d6575050613484565b808711156134e5575050613484565b83546801000000000000000090046001600160c01b031661350683896132ce565b6135104284613bdb565b61351a9190614499565b61352491906143cc565b61352e90866143b9565b94505050613484565b50811561355a576135488286613bea565b606c5461355591906143b9565b61355e565b606c545b9550505050505090565b6000806000806000606b5490508060000361359557606c5460715482606f54945094509450945050613140565b6135ce6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b606a548152606c5460715460a0830152606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613663576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613604565b50505050905060008061367b86600001514285613bff565b91509150808251036136a557848660a0015188606f549a509a509a509a5050505050505050613140565b6136ae82613d3d565b6000806136bc848685613d92565b895191935091506136d5906170809081810690036143b9565b60208901525b428860200151111580156136fe57508082516136f79190614499565b8860400151105b156138ad5787600001518289604001518151811061371e5761371e61435b565b602002602001015160000151111561374757602088015161708081015b60208a015288526136db565b8760200151828960400151815181106137625761376261435b565b60200260200101516020015110156137845760408801805160010190526136db565b8188604001518151811061379a5761379a61435b565b6020026020010151604001516000036137bc576020880151617080810161373b565b60408801511580156137df575087516020890151617080916137dd91614499565b105b15613830576138268860000151896020015103617080848b604001518151811061380b5761380b61435b565b6020026020010151604001516131469092919063ffffffff16565b608089015261385c565b818860400151815181106138465761384661435b565b6020026020010151604001518860800181815250505b608088015161386b908a613bea565b60a08901519701966138839088036103e68802613bc6565b6060890181905260a0890188905260208901516103e682029a909a0199960195617080810161373b565b8751421180156138c1575081518860400151105b156139995742828960400151815181106138dd576138dd61435b565b602002602001015160200151108015613911575060018183516139009190614499565b61390a9190614499565b8860400151105b156139225760408801805160010190525b42828960400151815181106139395761393961435b565b6020026020010151602001511061399957600061708089600001514203848b604001518151811061396c5761396c61435b565b6020026020010151604001510281613986576139866143e3565b049050613993818b613bea565b88019750505b5050505060a09390930151919891975092955091935090915050565b6000806000806000606b549050806000036139e257606c5460715482606f54945094509450945050613140565b606a54606c54607154606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613a70576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613a11565b509293508792506000915081905080613a8f61708080860686036143b9565b92505b428311613ae457613aa4858585613f9e565b9150613ab0828b613bea565b90970196613ac48789036103e68802613bc6565b6103e681029a909a01998897509586019592935050617080830191613a92565b42841015613b1057613af7858542613f9e565b9150613b03828b613bea565b613b0d90896143b9565b97505b50959c949b509699509197509195505050505050565b600054610100900460ff16613bbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92336131bc565b60006124b68383670de0b6b3a7640000613146565b60008183106132dd57816124b6565b60006124b683670de0b6b3a764000084613146565b606060008083516002613c1291906143cc565b67ffffffffffffffff811115613c2a57613c2a61454d565b604051908082528060200260200182016040528015613c53578160200160208202803683370190505b50905060008060008060005b8851811015613d2c57613c958b8a8381518110613c7e57613c7e61435b565b60200260200101516000015163ffffffff166132ce565b9350613cc48a8a8381518110613cad57613cad61435b565b60200260200101516020015163ffffffff16613bdb565b925082841015613d1d5783868380600101945081518110613ce757613ce761435b565b60200260200101818152505082868380600101945081518110613d0c57613d0c61435b565b602002602001018181525050613d24565b6002850194505b600101613c5f565b509399929850919650505050505050565b8051600082528060051b82016020601f198185015b8201838111613d8a5780518282018051828111613d7157505050613d52565b5b8186015283018051828111613d725750840152613d52565b505050915250565b606060006001838651613da59190614499565b613daf9190614499565b67ffffffffffffffff811115613dc757613dc761454d565b604051908082528060200260200182016040528015613e1c57816020015b613e0960405180606001604052806000815260200160008152602001600081525090565b815260200190600190039081613de55790505b509150600080808080875b60018b51613e359190614499565b811015613f90578a8181518110613e4e57613e4e61435b565b602002602001015195508a816001613e6691906143b9565b81518110613e7657613e7661435b565b60200260200101519450848603613e935760019687019601613e27565b60009350600092505b8951831015613f4b57858a8481518110613eb857613eb861435b565b60200260200101516000015163ffffffff161115613edb57826001019250613e9c565b848a8481518110613eee57613eee61435b565b60200260200101516020015163ffffffff161015613f1157826001019250613e9c565b898381518110613f2357613f2361435b565b6020026020010151604001516001600160c01b03166170800284019350826001019250613e9c565b604080516060810182528781526020810187905290810185905288516001848101949301928a918110613f8057613f8061435b565b6020026020010181905250613e27565b505050505050935093915050565b6000805b845181101561408a57848181518110613fbd57613fbd61435b565b60200260200101516000015163ffffffff16831015613fde57600101613fa2565b848181518110613ff057613ff061435b565b60200260200101516020015163ffffffff1684111561401157600101613fa2565b8481815181106140235761402361435b565b6020026020010151604001516001600160c01b031661406586838151811061404d5761404d61435b565b60200260200101516000015163ffffffff16866132ce565b61407b85888581518110613cad57613cad61435b565b03029190910190600101613fa2565b509392505050565b803560ff811681146140a357600080fd5b919050565b6000602082840312156140ba57600080fd5b6124b682614092565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805163ffffffff90811686528782015116878601528501516001600160c01b031685850152606090930192908501906001016140e0565b5091979650505050505050565b80356001600160a01b03811681146140a357600080fd5b8015158114612fa457600080fd5b6000806040838503121561416657600080fd5b61416f8361412e565b9150602083013561417f81614145565b809150509250929050565b60006020828403121561419c57600080fd5b6124b68261412e565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805161ffff1685528681015163ffffffff16878601528501516001600160d01b031685850152606090930192908501906001016141c2565b803563ffffffff811681146140a357600080fd5b60008060006060848603121561422d57600080fd5b61423684614204565b925061424460208501614204565b915060408401356001600160c01b038116811461426057600080fd5b809150509250925092565b60006020828403121561427d57600080fd5b5035919050565b80356001600160d01b03811681146140a357600080fd5b600080604083850312156142ae57600080fd5b823591506142be60208401614284565b90509250929050565b600080604083850312156142da57600080fd5b6142e383614284565b946020939093013593505050565b6000806040838503121561430457600080fd5b6142e38361412e565b6000806000806080858703121561432357600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121561435257600080fd5b6142e383614092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156124b9576124b961438a565b80820281158282048414176124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614421576144216143e3565b500690565b63ffffffff8281168282160390808211156144435761444361438a565b5092915050565b6001600160c01b038281168282168181028316929181158285048214176144735761447361438a565b50505092915050565b60006020828403121561448e57600080fd5b8151610ed781614145565b818103818111156124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61ffff8281168282160390808211156144435761444361438a565b6001600160d01b038281168282168181028316929181158285048214176144735761447361438a565b60008261452e5761452e6143e3565b500490565b600060001982036145465761454661438a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212209d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea24364736f6c63430008110033
Deployed Bytecode Sourcemap
60166:38861:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68874:926;;;;;;:::i;:::-;;:::i;:::-;;79284:95;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;67544:153;;;;;;:::i;:::-;;:::i;61567:44::-;;61610:1;61567:44;;;;;2106:25:1;;;2094:2;2079:18;61567:44:0;1960:177:1;79044:111:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;80249:694::-;;;:::i;64174:847::-;;;;;;:::i;:::-;;:::i;63058:42::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4065:14:1;;4058:22;4040:41;;4028:2;4013:18;63058:42:0;3900:187:1;81176:217:0;;;;;;:::i;:::-;;:::i;63159:29::-;;;;;;72995:447;;;:::i;63231:42::-;;;;;;77683:1245;;;;;;:::i;:::-;;:::i;61618:44::-;;61659:3;61618:44;;73547:2405;;;;;;:::i;:::-;;:::i;70029:1692::-;;;;;;:::i;:::-;;:::i;19407:103::-;;;:::i;80951:217::-;;;;;;:::i;:::-;;:::i;62881:59::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63195:29;;;;;;79728:219;;;;;;:::i;:::-;;:::i;18759:87::-;18832:6;;-1:-1:-1;;;;;18832:6:0;18759:87;;;-1:-1:-1;;;;;4913:55:1;;;4895:74;;4883:2;4868:18;18759:87:0;4749:226:1;67789:1007:0;;;;;;:::i;:::-;;:::i;62949:31::-;;;;;;61669:52;;61710:11;61669:52;;63019:30;;;;;;79163:113;;;;;;:::i;:::-;-1:-1:-1;;;;;79250:11:0;79223:7;79250:11;;;:5;:11;;;;;:18;;79163:113;62835:39;;;;;;:::i;:::-;;:::i;:::-;;;;5726:6:1;5714:19;;;5696:38;;5782:10;5770:23;;;5765:2;5750:18;;5743:51;-1:-1:-1;;;;;5830:67:1;5810:18;;;5803:95;5684:2;5669:18;62835:39:0;5498:406:1;62987:25:0;;;;;;65106:616;;;;;;:::i;:::-;;:::i;63824:309::-;;;;;;:::i;:::-;;:::i;79486:173::-;;;;;;:::i;:::-;;:::i;62728:24::-;;;;;;78936:100;79014:7;:14;78936:100;;62698:23;;;;;-1:-1:-1;;;;;62698:23:0;;;76173:1282;;;;;;:::i;:::-;;:::i;65820:1652::-;;;;;;:::i;:::-;;:::i;71811:1134::-;;;;;;:::i;:::-;;:::i;19665:201::-;;;;;;:::i;:::-;;:::i;62805:23::-;;;;;;:::i;:::-;;:::i;:::-;;;;7006:10:1;7043:15;;;7025:34;;7095:15;;;;7090:2;7075:18;;7068:43;-1:-1:-1;;;;;7147:63:1;7127:18;;;7120:91;6984:2;6969:18;62805:23:0;6798:419:1;68874:926:0;68947:33;;;68969:10;93705:2;93688:19;93679:29;;;;21165:1;21156:10;;;68925:19;21229:20;;;68995;21229;;;;;;93679:29;;21192:1;:19;;21229:27;:32;68991:71;;69041:21;;;;;;;;;;;;;;68991:71;69075:27;69105:21;:19;:21::i;:::-;69075:51;;69139:17;69159:55;69182:10;69194:19;69159:22;:55::i;:::-;69139:75;;69229:9;69242:1;69229:14;69225:43;;69252:16;;;;;;;;;;;;;;69225:43;69306:10;69281:36;;;;:24;:36;;;;;;;;:58;;;69372:5;:17;;;;;:24;;;;;;;;;;;;:::i;:::-;;;;;;;;;;69413:8;;69372:24;;-1:-1:-1;69424:15:0;69413:8;;;;;;:26;69409:62;;;69448:23;;;;;;;;;;;;;;69409:62;69512:11;;69484:17;;69512:23;;69526:9;;69512:11;;;-1:-1:-1;;;;;69512:11:0;:23;:::i;:::-;69567:15;;-1:-1:-1;;;;;69595:23:0;;;;;;;;;;69484:52;;-1:-1:-1;69567:15:0;;69643:22;69567:15;69643:9;:22;:::i;:::-;69629:10;;:36;;;;;;;:::i;:::-;;;;-1:-1:-1;;69683:28:0;;2106:25:1;;;69689:10:0;;69683:28;;2094:2:1;2079:18;69683:28:0;;;;;;;69771:8;;69729:63;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;69771:8:0;;;;;;8282:18:1;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;69741:10:0;;69729:63;;8113:3:1;8098:19;69729:63:0;;;;;;;;68914:886;;;;;;68874:926;:::o;79284:95::-;79329:15;79364:7;79357:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;79357:14:0;;;;;;;;;;;;;;;;;;;;;;79284:95;:::o;67544:153::-;18645:13;:11;:13::i;:::-;-1:-1:-1;;;;;67622:16:0;::::1;;::::0;;;:10:::1;:16;::::0;;;;;;;;:24;;;::::1;::::0;::::1;;::::0;;::::1;::::0;;;67664:25;;4040:41:1;;;67664:25:0::1;::::0;4013:18:1;67664:25:0::1;;;;;;;;67544:153:::0;;:::o;79044:111::-;-1:-1:-1;;;;;79136:11:0;;;;;;:5;:11;;;;;;;;79129:18;;;;;;;;;;;;;;;;;79103:13;;79129:18;;79136:11;;79129:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;79129:18:0;;;;;;;;;;;;;;;;;;;;;;79044:111;;;:::o;80249:694::-;80296:7;80331:27;80373:39;80427:22;80464:26;80504:17;:15;:17::i;:::-;80553:15;80534:16;:34;80579:15;:37;;;80627:27;:61;;;80699:10;:27;;;80765:14;;80316:205;;-1:-1:-1;80316:205:0;;-1:-1:-1;80316:205:0;-1:-1:-1;80316:205:0;-1:-1:-1;80743:36:0;;80739:158;;80796:14;:35;;;80851:34;;2106:25:1;;;80851:34:0;;2094:2:1;2079:18;80851:34:0;;;;;;;80739:158;-1:-1:-1;80916:19:0;;80249:694;-1:-1:-1;;;80249:694:0:o;64174:847::-;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;64316:7:::1;:14:::0;:34;;64312:68:::1;;64359:21;;;;;;;;;;;;;;64312:68;64395:15;-1:-1:-1::0;;;;;64395:20:0::1;64414:1;64395:20:::0;64391:47:::1;;64424:14;;;;;;;;;;;;;;64391:47;64462:3;64453:12;;:5;:12;;::::0;64449:43:::1;;64474:18;;;;;;;;;;;;;;64449:43;64515:15;64507:5;:23;;;:48;;;;64540:15;64534:3;:21;;;64507:48;64503:86;;;64564:25;;;;;;;;;;;;;;64503:86;64604:22;61710:11;64604:22;::::0;::::1;;:::i;:::-;:27:::0;64600:69:::1;;64640:29;;;;;;;;;;;;;;64600:69;64684:20;61710:11;64684:20;::::0;::::1;;:::i;:::-;:25:::0;64680:67:::1;;64718:29;;;;;;;;;;;;;;64680:67;64773:35;::::0;;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;::::1;;::::0;::::1;::::0;;;-1:-1:-1;;;;;64773:35:0;;::::1;::::0;;;;;;64760:7:::1;:49:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;64760:49:0;;;;;;;;;::::1;::::0;;;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;64834:9:::1;::::0;-1:-1:-1;;;;;64834:9:0::1;64827:30;64858:10;64878:4;64792:15:::0;64886:11:::1;64780:5:::0;64787:3;64886:11:::1;:::i;:::-;64885:31;;;;;;:::i;:::-;64827:90;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;9481:15:1;;;64827:90:0::1;::::0;::::1;9463:34:1::0;9533:15;;;;9513:18;;;9506:43;-1:-1:-1;;;;;9585:63:1;9565:18;;;9558:91;9375:18;;64827:90:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64822:133;;64939:16;;-1:-1:-1::0;;;64939:16:0::1;;;;;;;;;;;64822:133;64973:40;::::0;;7006:10:1;7043:15;;;7025:34;;7095:15;;7090:2;7075:18;;7068:43;-1:-1:-1;;;;;7147:63:1;;7127:18;;;7120:91;;;;64973:40:0::1;::::0;6984:2:1;6969:18;64973:40:0::1;;;;;;;;64174:847:::0;;;:::o;81176:217::-;81287:14;;81250:7;;81321:11;;:64;;81362:14;;81344:41;;:6;;81378;81344:17;:41::i;:::-;81321:64;;;81335:6;81321:64;81314:71;81176:217;-1:-1:-1;;;81176:217:0:o;72995:447::-;73032:27;73062:21;:19;:21::i;:::-;73032:51;;73096:17;73116:55;73139:10;73151:19;73116:22;:55::i;:::-;73096:75;;73186:9;73199:1;73186:14;73182:43;;73209:16;;;;;;;;;;;;;;73182:43;73263:10;73238:36;;;;:24;:36;;;;;;;:58;;;73321:9;;73314:49;;;;;;;;10510:74:1;;;;10600:18;;;10593:34;;;-1:-1:-1;;;;;73321:9:0;;73314:26;;10483:18:1;;73314:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73309:79;;73372:16;;-1:-1:-1;;;73372:16:0;;;;;;;;;;;73309:79;73406:28;;2106:25:1;;;73412:10:0;;73406:28;;2094:2:1;2079:18;73406:28:0;1960:177:1;77683:1245:0;77747:27;77777:21;:19;:21::i;:::-;77747:51;;77809:17;77829:55;77852:10;77864:19;77829:22;:55::i;:::-;77923:10;77897:17;77917;;;:5;:17;;;;;:24;;77809:75;;-1:-1:-1;77897:17:0;;77935:5;;77917:24;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;93679:29:0;77998:10;93705:2;93688:19;93679:29;;;21165:1;21156:10;;;21122:4;21229:20;;;78025;21229;;;;;;77954:55;;-1:-1:-1;21192:1:0;21206:4;21198:12;;21192:19;21229:27;78020:75;;78071:24;;;;;;;;;;;;;;78020:75;21976:1;21967:10;;;21950:14;22033:20;;;78108;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;78183:11;;;;;-1:-1:-1;;;;;78183:11:0;78160:20;78224:41;78183:11;78224:27;:41::i;:::-;78207:58;;78308:168;78354:14;;78383:6;78404:19;78438:27;;78308:31;:168::i;:::-;78278:27;:198;;;;78507:6;78489:14;;:24;;;;;;;:::i;:::-;;;;;;;;78544:12;78526:14;;:30;;;;;;;:::i;:::-;;;;-1:-1:-1;;78569:29:0;;;;;-1:-1:-1;;;;;78569:29:0;;;;;;78636:10;-1:-1:-1;78611:36:0;;;:24;:36;;;;;:58;;;78686:14;;78682:174;;78729:9;;78722:49;;;;;78749:10;78722:49;;;10510:74:1;10600:18;;;10593:34;;;-1:-1:-1;;;;;78729:9:0;;;;78722:26;;10483:18:1;;78722:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78717:79;;78780:16;;-1:-1:-1;;;78780:16:0;;;;;;;;;;;78717:79;78816:28;;2106:25:1;;;78822:10:0;;78816:28;;2094:2:1;2079:18;78816:28:0;;;;;;;78682:174;78873:47;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;78894:10:0;;78873:47;;10918:18:1;78873:47:0;10771:248:1;73547:2405:0;73598:27;73628:21;:19;:21::i;:::-;73686:10;73660:17;73680;;;:5;:17;;;;;:24;;73598:51;;-1:-1:-1;73660:17:0;;73698:5;;73680:24;;;;;;:::i;:::-;;;;;;;;;;73721:8;;73680:24;;-1:-1:-1;73732:15:0;73721:8;;;;;;:26;73717:56;;;73756:17;;;;;;;;;;;;;;73717:56;73786:19;93679:29;73830:10;93705:2;93688:19;93679:29;;;73786:55;;73854:17;73874:55;73897:10;73909:19;73874:22;:55::i;:::-;21165:1;21156:10;;;73942:23;21229:20;;;73968;21229;;;;;;73854:75;;-1:-1:-1;21192:1:0;21206:4;21198:12;;21192:19;21229:27;;;:32;;;;73942:23;74041:502;;74097:11;;;;;-1:-1:-1;;;;;74097:11:0;74132:35;74097:11;74132:27;:35::i;:::-;74123:44;;74212:188;74262:14;;74295:6;74320:19;74358:27;;74212:31;:188::i;:::-;74182:27;:218;;;;74433:6;74415:14;;:24;;;;;;;:::i;:::-;;;;;;;;74472:6;74454:14;;:24;;;;;;;:::i;:::-;;;;-1:-1:-1;74041:502:0;;-1:-1:-1;;74041:502:0;;-1:-1:-1;74520:11:0;;;;;-1:-1:-1;;;;;74520:11:0;74041:502;74580:10;74555:36;;;;:24;:36;;;;;;;;:58;;;74674:15;;74651:10;:38;;74674:15;;;;74665:24;;74651:38;;;;;74786:5;:17;;;;;:24;-1:-1:-1;;74786:28:0;;;74842:22;;74674:15;74842:22;74838:827;;74885:18;74881:98;;;21976:1;21967:10;;;21950:14;22033:20;;;74924;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;74838:827;;74924:39;74838:827;;;75044:10;75038:17;;;;:5;:17;;;;;:32;;75056:13;;75038:32;;;;;;:::i;:::-;;;;;;;;75011:5;:17;75017:10;-1:-1:-1;;;;;75011:17:0;-1:-1:-1;;;;;75011:17:0;;;;;;;;;;;;75029:5;75011:24;;;;;;;;:::i;:::-;;;;;;;;:59;;:24;;:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75011:59:0;;;;;;;;;;;;;;;;;;75115:41;75130:13;75145:10;93705:2;93688:19;93679:29;;;;93568:149;75115:41;75085:71;;75175:18;75171:483;;;21165:1;21156:10;;;21122:4;21229:20;;;75219;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;75214:230;;21976:1;21967:10;;;21950:14;22033:20;;;75289;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75171:483;;75214:230;21976:1;21967:10;;;21950:14;22033:20;;;75377;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75171:483;;;21165:1;21156:10;;;21122:4;21229:20;;;75469;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;:32;75465:189;;21718:1;21709:10;;;21692:14;21775:20;;;75535;21775;;;;;:28;;21745:1;21759:4;21751:12;;21745:19;21775:28;;;21976:1;21967:10;;;21950:14;22033:20;;;75591;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75591:47;74996:669;74838:827;75683:10;75677:17;;;;:5;:17;;;;;:23;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;75677:23:0;;;;;;;;;;75725:9;;-1:-1:-1;;;;;75725:9:0;75718:26;75745:10;75757:18;75766:9;75757:6;:18;:::i;:::-;75718:58;;;;;;;;;;-1:-1:-1;;;;;10528:55:1;;;75718:58:0;;;10510:74:1;10600:18;;;10593:34;10483:18;;75718:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75713:88;;75785:16;;-1:-1:-1;;;75785:16:0;;;;;;;;;;;75713:88;75818:14;;75814:80;;75854:28;;2106:25:1;;;75860:10:0;;75854:28;;2094:2:1;2079:18;75854:28:0;;;;;;;75814:80;75911:33;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;75918:10:0;;75911:33;;10918:18:1;75911:33:0;;;;;;;;73587:2365;;;;;;;73547:2405;:::o;70029:1692::-;70110:6;-1:-1:-1;;;;;70110:11:0;70120:1;70110:11;70106:38;;70130:14;;;;;;;;;;;;;;70106:38;70157:27;70187:21;:19;:21::i;:::-;70157:51;;70221:17;70241:55;70264:10;70276:19;70241:22;:55::i;:::-;70221:75;-1:-1:-1;70307:19:0;70329:18;70221:75;-1:-1:-1;;;;;70329:18:0;;;:::i;:::-;70386:10;70360:17;70380;;;:5;:17;;;;;:24;;70307:40;;-1:-1:-1;70360:17:0;;70398:5;;70380:24;;;;;;:::i;:::-;;;;;;;;;;70421:8;;70380:24;;-1:-1:-1;70432:15:0;70421:8;;;;;;:26;70417:62;;;70456:23;;;;;;;;;;;;;;70417:62;70492:17;70524:59;93679:29;70571:10;93705:2;93688:19;93679:29;;;70549:33;21165:1;21156:10;;;21122:4;21229:20;;;70524;21229;;;;;;21192:1;21206:4;21198:12;;;21192:19;;;;21229:27;:32;;;21048:221;70524:59;70520:700;;;70600:25;70628:14;;70600:42;;70689:195;70738:17;70774:11;70804:19;70842:27;;70689:30;:195::i;:::-;70659:27;:225;70901:17;70921:40;70949:11;70921:27;:40::i;:::-;70901:60;-1:-1:-1;70995:31:0;71015:11;70995:17;:31;:::i;:::-;70978:14;:48;;;;71059:9;71041:14;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;71105:11:0;;:23;;71119:9;;71105:11;;;-1:-1:-1;;;;;71105:11:0;:23;:::i;:::-;71085:44;;70585:556;;70520:700;;;71182:11;;:25;;71196:11;;71182;;;-1:-1:-1;;;;;71182:11:0;:25;:::i;:::-;71162:46;;70520:700;71232:23;;-1:-1:-1;;;;;71232:23:0;;;;;;;;;;;71341:10;71232:11;71316:36;;;:24;:36;;;;;:58;;;71288:15;;;;;;;71401:24;71288:15;71401:11;:24;:::i;:::-;71387:10;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;71450:9:0;;71443:65;;;;;71474:10;71443:65;;;11476:34:1;71494:4:0;11526:18:1;;;11519:43;-1:-1:-1;;;;;11598:67:1;;11578:18;;;11571:95;-1:-1:-1;;;;;71450:9:0;;;;71443:30;;11388:18:1;;71443:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71438:95;;71517:16;;-1:-1:-1;;;71517:16:0;;;;;;;;;;;71438:95;71550:14;;71546:80;;71586:28;;2106:25:1;;;71592:10:0;;71586:28;;2094:2:1;2079:18;71586:28:0;;;;;;;71546:80;71692:8;;71643:70;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;71692:8:0;;;;;;8282:18:1;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;71655:10:0;;71643:70;;8113:3:1;8098:19;71643:70:0;7903:485:1;19407:103:0;18645:13;:11;:13::i;:::-;19472:30:::1;19499:1;19472:18;:30::i;:::-;19407:103::o:0;80951:217::-;81062:14;;81025:7;;81096:11;;:64;;81145:14;;81119:41;;:6;;81137;;81119:17;:41::i;79728:219::-;79791:17;79822:24;79856:17;:15;:17::i;:::-;79821:52;;;;;79893:46;79916:4;79922:16;79893:22;:46::i;67789:1007::-;67864:6;-1:-1:-1;;;;;67864:11:0;67874:1;67864:11;67860:38;;67884:14;;;;;;;;;;;;;;67860:38;67919:10;67913:17;;;;:5;:17;;;;;:24;:42;;67909:74;;67964:19;;;;;;;;;;;;;;67909:74;67996:27;68026:21;:19;:21::i;:::-;67996:51;;68060:17;68080:55;68103:10;68115:19;68080:22;:55::i;:::-;68060:75;-1:-1:-1;68146:19:0;68168:18;-1:-1:-1;;;;;68168:18:0;;68060:75;68168:18;:::i;:::-;68224:10;68199:36;;;;:24;:36;;;;;:58;;;68146:40;;-1:-1:-1;68290:26:0;68308:8;68290:15;:26;:::i;:::-;68270:47;;68328:17;68348:31;68370:8;68348:21;:31::i;:::-;68398:10;68392:17;;;;:5;:17;;;;;;;;68415:43;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;68415:43:0;;;;;;;;;68392:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68328:51;;-1:-1:-1;68486:24:0;;68445:11;;68486:24;:::i;:::-;68472:10;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;68535:9:0;;68528:65;;;;;68559:10;68528:65;;;11476:34:1;68579:4:0;11526:18:1;;;11519:43;-1:-1:-1;;;;;11598:67:1;;11578:18;;;11571:95;-1:-1:-1;;;;;68535:9:0;;;;68528:30;;11388:18:1;;68528:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68523:95;;68602:16;;-1:-1:-1;;;68602:16:0;;;;;;;;;;;68523:95;68635:14;;68631:80;;68671:28;;2106:25:1;;;68677:10:0;;68671:28;;2094:2:1;2079:18;68671:28:0;;;;;;;68631:80;68728:60;;;-1:-1:-1;;;;;11893:67:1;;11875:86;;12009:10;11997:23;;11992:2;11977:18;;11970:51;12069:6;12057:19;;12037:18;;;12030:47;;;;68738:10:0;;68728:60;;11863:2:1;11848:18;68728:60:0;11677:406:1;62835:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62835:39:0;;;;;;-1:-1:-1;62835:39:0;;;-1:-1:-1;;;;;62835:39:0;;:::o;65106:616::-;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;65177:21:::1;:19;:21::i;:::-;;65211:20;65234:7;65242:5;65234:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;65211:37:::1;::::0;;::::1;::::0;::::1;::::0;;65234:14;;;::::1;65211:37:::0;::::1;::::0;;::::1;::::0;;;;::::1;;::::0;;::::1;::::0;;;;-1:-1:-1;;;;;65211:37:0;;;::::1;::::0;;;::::1;::::0;;;;65278:7:::1;65286:14:::0;;65211:37;;-1:-1:-1;65278:7:0;65286:18:::1;::::0;65211:37;;65286:18:::1;:::i;:::-;65278:27;;;;;;;;:::i;:::-;;;;;;;;65261:7;65269:5;65261:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;:44;;:14;::::1;:44:::0;;::::1;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;::::1;::::0;;::::1;;::::0;;;::::1;::::0;;;;;;;;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;65261:44:0::1;::::0;;::::1;::::0;;;::::1;::::0;;65316:7:::1;:13:::0;;;::::1;;;;:::i;:::-;;::::0;;;::::1;::::0;;;-1:-1:-1;;65316:13:0;;;;;;;;;;;;;;65422:10;::::1;::::0;65435:15:::1;65316:13;65422:28:::0;;::::1;;65418:259;;;65467:21;65543:6;:22;;;-1:-1:-1::0;;;;;65491:74:0::1;65505:34;65509:15;65526:6;:12;;;65505:34;;:3;:34::i;:::-;65492:6;:10;;;:47;;;;;;:::i;:::-;65491:74;;;;:::i;:::-;65594:9;::::0;65587:53:::1;::::0;;;;65614:10:::1;65587:53;::::0;::::1;10510:74:1::0;10600:18;;;10593:34;;;65467:98:0;;-1:-1:-1;;;;;;65594:9:0::1;::::0;65587:26:::1;::::0;10483:18:1;;65587:53:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65582:83;;65649:16;;-1:-1:-1::0;;;65649:16:0::1;;;;;;;;;;;65582:83;65452:225;65418:259;65694:20;::::0;2106:25:1;;;65694:20:0::1;::::0;2094:2:1;2079:18;65694:20:0::1;;;;;;;65166:556;65106:616:::0;:::o;63824:309::-;12694:19;12717:13;;;;;;12716:14;;12764:34;;;;-1:-1:-1;12782:12:0;;12797:1;12782:12;;;;:16;12764:34;12763:108;;;-1:-1:-1;12843:4:0;2570:19;:23;;;12804:66;;-1:-1:-1;12853:12:0;;;;;:17;12804:66;12741:204;;;;;;;12290:2:1;12741:204:0;;;12272:21:1;12329:2;12309:18;;;12302:30;12368:34;12348:18;;;12341:62;12439:16;12419:18;;;12412:44;12473:19;;12741:204:0;;;;;;;;;12956:12;:16;;;;12971:1;12956:16;;;12983:67;;;;13018:13;:20;;;;;;;;12983:67;-1:-1:-1;;;;;63920:24:0;::::1;63916:50;;63953:13;;;;;;;;;;;;;;63916:50;63981:10;63995:1;63981:15:::0;63977:43:::1;;64005:15;;;;;;;;;;;;;;63977:43;64033:9;:30:::0;;;::::1;-1:-1:-1::0;;;;;64033:30:0;::::1;;::::0;;64074:9:::1;:22:::0;;;64109:16:::1;:14;:16::i;:::-;13076:14:::0;13072:102;;;13123:5;13107:21;;;;;;13148:14;;-1:-1:-1;12655:36:1;;13148:14:0;;12643:2:1;12628:18;13148:14:0;12503:194:1;13072:102:0;12683:498;63824:309;;:::o;79486:173::-;79574:4;79598:53;79623:27;79638:5;79645:4;93705:2;93688:19;93679:29;;;;93568:149;79598:53;79591:60;;79486:173;;;;;:::o;76173:1282::-;76236:27;76266:21;:19;:21::i;:::-;76236:51;;76298:17;76318:55;76341:10;76353:19;76318:22;:55::i;:::-;76412:10;76386:17;76406;;;:5;:17;;;;;:24;;76298:75;;-1:-1:-1;76386:17:0;;76424:5;;76406:24;;;;;;:::i;:::-;;;;;;;;;;76445:15;;76406:24;;-1:-1:-1;76445:15:0;;61659:3;76445:33;76441:64;;76487:18;;;;;;;;;;;;;;76441:64;76562:10;93705:2;93688:19;93679:29;;;;21165:1;21156:10;;;76518:19;21229:20;;;76588;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;:32;76584:71;;76634:21;;;;;;;;;;;;;;76584:71;21718:1;21709:10;;;21692:14;21775:20;;;76668;21775;;;;;:28;;21745:1;21759:4;21751:12;;21745:19;21775:28;;;76739:11;;:23;;76753:9;;76739:11;;;-1:-1:-1;;;;;76739:11:0;:23;:::i;:::-;76718:44;;76775:14;76792:39;76820:10;76792:27;:39::i;:::-;76775:56;;76874:171;76919:14;;76948:10;76973:19;77007:27;;76874:30;:171::i;:::-;76844:27;:201;;;;77076:10;77058:14;;:28;;;;;;;:::i;:::-;;;;;;;;77117:6;77099:14;;:24;;;;;;;:::i;:::-;;;;-1:-1:-1;;77136:29:0;;;;;-1:-1:-1;;;;;77136:29:0;;;;;;77203:10;-1:-1:-1;77178:36:0;;;:24;:36;;;;;:58;;;77253:14;;77249:135;;77298:26;61659:3;77298:9;:26;:::i;:::-;77284:10;;:40;;;;;;;:::i;:::-;;;;-1:-1:-1;;77344:28:0;;2106:25:1;;;77350:10:0;;77344:28;;2094:2:1;2079:18;77344:28:0;;;;;;;77249:135;77401:46;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;77421:10:0;;77401:46;;10918:18:1;77401:46:0;10771:248:1;65820:1652:0;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;66000:25:::1;61710:11;66000:8:::0;:25:::1;:::i;:::-;:30:::0;65996:72:::1;;66039:29;;;;;;;;;;;;;;65996:72;66083:23;61710:11;66083:6:::0;:23:::1;:::i;:::-;:28:::0;66079:70:::1;;66120:29;;;;;;;;;;;;;;66079:70;66164:18;66186:1;66164:23:::0;66160:48:::1;;66196:12;;;;;;;;;;;;;;66160:48;66221:21;:19;:21::i;:::-;;66255;66279:7;66287:5;66279:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;66323:10:::0;;66279:14;;-1:-1:-1;66323:10:0;;::::1;;;66357:15;66348:24:::0;::::1;66344:53;;;66381:16;;;;;;;;;;;;;;66344:53;66421:15;66412:6;:24;66408:62;;;66445:25;;;;;;;;;;;;;;66408:62;66502:12:::0;;::::1;;66541:15;66530:26:::0;::::1;::::0;:56:::1;;;66571:15;66560:8;:26;66530:56;66529:82;;;;;66603:8;66591;:20;;66529:82;66525:111;;;66620:16;;;;;;;;;;;;;;66525:111;66649:23;66697:18:::0;66676:17:::1;66685:8:::0;66676:6;:17:::1;:::i;:::-;66675:40;;;;:::i;:::-;66774:22:::0;;66649:66;;-1:-1:-1;66726:23:0::1;::::0;66774:22;;::::1;-1:-1:-1::0;;;;;66774:22:0::1;66753:17;66762:8:::0;66753:6;:17:::1;:::i;:::-;66752:44;;;;:::i;:::-;66726:70;;66825:8;66813;:20;66809:84;;66850:31:::0;;;::::1;;::::0;::::1;;::::0;;66809:84:::1;66905:27:::0;;::::1;66943:52:::0;;;66905:27;;;::::1;::::0;;;::::1;66943:52:::0;;;;-1:-1:-1;;;;;66943:52:0;::::1;;;::::0;;67012:33;;::::1;67008:381;;;67074:9;::::0;-1:-1:-1;;;;;67074:9:0::1;67067:26;67094:10;67106:33;67124:15:::0;67106;:33:::1;:::i;:::-;67067:73;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;10528:55:1;;;67067:73:0::1;::::0;::::1;10510:74:1::0;10600:18;;;10593:34;10483:18;;67067:73:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67062:103;;67149:16;;-1:-1:-1::0;;;67149:16:0::1;;;;;;;;;;;67062:103;67008:381;;;67206:15;67187;:34;67183:206;;67250:9;::::0;-1:-1:-1;;;;;67250:9:0::1;67243:30;67274:10;67294:4;67301:33;67319:15:::0;67301;:33:::1;:::i;:::-;67243:92;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;12983:15:1;;;67243:92:0::1;::::0;::::1;12965:34:1::0;13035:15;;;;13015:18;;;13008:43;13067:18;;;13060:34;12877:18;;67243:92:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67238:139;;67361:16;;-1:-1:-1::0;;;67361:16:0::1;;;;;;;;;;;67238:139;67406:58;::::0;;13336:25:1;;;13392:2;13377:18;;13370:34;;;13420:18;;;13413:34;;;13478:2;13463:18;;13456:34;;;67406:58:0::1;::::0;13323:3:1;13308:19;67406:58:0::1;;;;;;;65985:1487;;;;;65820:1652:::0;;;;:::o;71811:1134::-;71890:27;71920:21;:19;:21::i;:::-;71980:10;71954:17;71974;;;:5;:17;;;;;:24;;71890:51;;-1:-1:-1;71954:17:0;;71974:24;;;;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;72031:26:0;72049:8;72031:15;:26;:::i;:::-;72073:8;;72011:47;;-1:-1:-1;72073:15:0;;;;:8;;;;;:15;72069:58;;72113:8;;72097:30;;;;;72113:8;;;;;;;;72097:30;;;13702:34:1;13772:15;;13752:18;;;13745:43;13646:18;;72097:30:0;13501:293:1;72069:58:0;72140:17;72160:55;72183:10;72195:19;72160:22;:55::i;:::-;72253:10;72228:36;;;;:24;:36;;;;;:58;;;72140:75;;-1:-1:-1;72319:31:0;72341:8;72319:21;:31::i;:::-;72363:14;;;;;;;;;;;;;;72299:51;;-1:-1:-1;72413:15:0;;;;;;;;;72445:26;;;;72441:91;;;72480:52;;;;;13979:6:1;14012:15;;;72480:52:0;;;13994:34:1;14064:15;;14044:18;;;14037:43;13942:18;;72480:52:0;13799:287:1;72441:91:0;72545:28;;;;;;;;;;;72603:11;;;-1:-1:-1;;;;;72603:11:0;;72640:26;72653:13;72545:28;72640:26;:::i;:::-;72639:37;;;;;;:::i;:::-;-1:-1:-1;;;;;72625:51:0;:10;;:51;;;;;;;:::i;:::-;;;;-1:-1:-1;;72693:14:0;;72689:176;;72736:9;;72729:49;;;;;72756:10;72729:49;;;10510:74:1;10600:18;;;10593:34;;;-1:-1:-1;;;;;72736:9:0;;;;72729:26;;10483:18:1;;72729:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;72724:79;;72787:16;;-1:-1:-1;;;72787:16:0;;;;;;;;;;;72724:79;72825:28;;2106:25:1;;;72831:10:0;;72825:28;;2094:2:1;2079:18;72825:28:0;;;;;;;72689:176;72882:55;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;8314:10;8302:23;;8282:18;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;72882:55:0;;72894:10;;72882:55;;;;;;8113:3:1;72882:55:0;;;71879:1066;;;;;;;71811:1134;;:::o;19665:201::-;18645:13;:11;:13::i;:::-;-1:-1:-1;;;;;19754:22:0;::::1;19746:73;;;::::0;::::1;::::0;;14794:2:1;19746:73:0::1;::::0;::::1;14776:21:1::0;14833:2;14813:18;;;14806:30;14872:34;14852:18;;;14845:62;14943:8;14923:18;;;14916:36;14969:19;;19746:73:0::1;14592:402:1::0;19746:73:0::1;19830:28;19849:8;19830:18;:28::i;:::-;19665:201:::0;:::o;62805:23::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62805:23:0;;;;;;;;-1:-1:-1;;;;;62805:23:0;;:::o;91908:320::-;92004:17;92034;92054:29;92078:4;92054:23;:29::i;:::-;-1:-1:-1;;;;;92178:30:0;;;;;;:24;:30;;;;;;92034:49;;-1:-1:-1;92128:81:0;;92034:49;;92158:50;;92128:18;:81::i;:::-;92121:88;91908:320;-1:-1:-1;;;;91908:320:0:o;18924:132::-;18832:6;;-1:-1:-1;;;;;18832:6:0;17060:10;18988:23;18980:68;;;;;;;15201:2:1;18980:68:0;;;15183:21:1;;;15220:18;;;15213:30;15279:34;15259:18;;;15252:62;15331:18;;18980:68:0;14999:356:1;84188:924:0;84279:7;84301;84323;84345;84380:20;84403:16;;84380:39;;84450:15;84434:12;:31;84430:145;;84490:15;;84507:27;;84536:10;;84548:14;;84482:81;;;;;;;;;;;84430:145;61710:11;95036:26;;;95023:40;;;84675:15;95036:26;;;95023:40;;84708:28;;;84704:159;;84761:32;:30;:32::i;:::-;84795:27;;84824:10;;84836:14;;84753:98;;;;;;;;;;;;;84704:159;61784:1;61710:11;84906:27;;;84905:46;:78;84901:146;;;85011:20;:18;:20::i;:::-;85004:27;;;;;;;;;;;;;84901:146;85080:24;:22;:24::i;:::-;85073:31;;;;;;;;;;;84188:924;;;;;:::o;23605:541::-;23725:9;23977:1;-1:-1:-1;;23960:19:0;23957:1;23954:26;23951:1;23947:34;23940:42;23927:11;23923:60;23913:118;;24014:1;24011;24004:12;23913:118;-1:-1:-1;24105:9:0;;24101:27;;23605:541::o;94397:506::-;94618:7;94660:18;94642:14;:36;94638:68;;-1:-1:-1;94687:19:0;94680:26;;94638:68;94859:35;94880:14;94859:18;:35;:::i;:::-;94823:18;94774:45;94796:23;94774:19;:45;:::i;:::-;94773:68;;;;:::i;:::-;94772:123;;;;:::i;:::-;94737:158;;:19;:158;:::i;:::-;94717:178;94397:506;-1:-1:-1;;;;;94397:506:0:o;93841:426::-;94061:7;94223:35;94244:14;94223:18;:35;:::i;20026:191::-;20119:6;;;-1:-1:-1;;;;;20136:17:0;;;;;;;;;;;20169:40;;20119:6;;;20136:17;20119:6;;20169:40;;20100:16;;20169:40;20089:128;20026:191;:::o;93046:300::-;93118:6;93152:7;93141:8;:18;:42;;;;93174:9;93163:8;:20;93141:42;93137:84;;;93192:29;;;;;;;;2106:25:1;;;2079:18;;93192:29:0;1960:177:1;93137:84:0;93333:4;93280:25;93297:8;93280:14;:25;:::i;:::-;93269:8;93249:17;93269:8;93249:6;:17;:::i;:::-;:28;;;;:::i;:::-;:56;;;;:::i;:::-;:80;;93308:21;93249:80;:::i;:::-;93248:89;;;;:::i;92715:108::-;92773:9;92806:1;92802;:5;:13;;92814:1;92802:13;;;-1:-1:-1;92810:1:0;;92715:108;-1:-1:-1;92715:108:0:o;18302:97::-;14837:13;;;;;;;14829:69;;;;;;;15687:2:1;14829:69:0;;;15669:21:1;15726:2;15706:18;;;15699:30;15765:34;15745:18;;;15738:62;15836:13;15816:18;;;15809:41;15867:19;;14829:69:0;15485:407:1;14829:69:0;18365:26:::1;:24;:26::i;91339:460::-:0;-1:-1:-1;;;;;91456:11:0;;91409:13;91456:11;;;:5;:11;;;;;:18;91409:13;;91513:279;91547:10;91538:6;:19;91513:279;;;-1:-1:-1;;;;;91591:11:0;;;;;;:5;:11;;;;;:19;;91603:6;;91591:19;;;;;;:::i;:::-;;;;;;;;91584:26;;91629:54;91654:28;91669:6;91677:4;93705:2;93688:19;93679:29;;;;93568:149;91629:54;91704:8;91625:103;91765:15;;91751:29;;91765:15;;;;91751:11;;;-1:-1:-1;;;;;91751:11:0;:29;:::i;:::-;91742:38;;-1:-1:-1;;;;;91742:38:0;;;:::i;:::-;;;91513:279;91559:8;;;:::i;:::-;;;91513:279;;;;91424:375;;91339:460;;;:::o;92330:167::-;92425:7;92452:37;:5;92469:19;92452:16;:37::i;90279:1010::-;90433:10;;90344:7;;90458:16;;;90454:71;;-1:-1:-1;;90498:15:0;;;90279:1010::o;90454:71::-;90565:16;;90611:7;:14;90537:25;;;90697:477;90735:6;90724:8;:17;90697:477;;;90769:7;90777:8;90769:17;;;;;;;;:::i;:::-;;;;;;;;;;90890:12;;90769:17;;-1:-1:-1;90832:10:0;;;;;90890:12;;;;;90931:10;;;;90962:15;:23;-1:-1:-1;90958:37:0;;;90987:8;;90697:477;;90958:37;91034:3;91014:17;:23;91010:37;;;91039:8;;90697:477;;91010:37;91140:22;;;;;-1:-1:-1;;;;;91140:22:0;91107:29;91111:5;91118:17;91107:3;:29::i;:::-;91079:25;91083:15;91100:3;91079;:25::i;:::-;:57;;;;:::i;:::-;91078:84;;;;:::i;:::-;91064:98;;;;:::i;:::-;;;90745:429;;90697:477;;;-1:-1:-1;91193:15:0;;:88;;91247:34;:10;91269:11;91247:21;:34::i;:::-;91229:15;;:52;;;;:::i;:::-;91193:88;;;91211:15;;91193:88;91186:95;;;;;;;90279:1010;:::o;85492:4745::-;85586:7;85608;85630;85652;85687:22;85712:10;;85687:35;;85737:14;85755:1;85737:19;85733:137;;85781:15;;85798:27;;85827:14;85843;;85773:85;;;;;;;;;;;85733:137;85882:28;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85882:28:0;85937:16;;85921:32;;85996:15;;86061:27;;86022:36;;;:66;86128:14;;86184:7;86155:36;;;;;;;;;;;;;;;;;;;85921:13;;86155:36;;86184:7;;85921:13;;86155:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;86155:36:0;;;;;;;;;;;;;;;;;;;;;;86203:30;86235:26;86265:116;86302:8;:13;;;86330:15;86360:10;86265:22;:116::i;:::-;86202:179;;;;86422:18;86398:13;:20;:42;86394:173;;86465:19;86486:8;:36;;;86524:14;86540;;86457:98;;;;;;;;;;;;;;;;;86394:173;86579:36;86601:13;86579:21;:36::i;:::-;86627:39;86668:19;86691:118;86727:13;86755:10;86780:18;86691:21;:118::i;:::-;86845:13;;86626:183;;-1:-1:-1;86626:183:0;-1:-1:-1;86836:40:0;;61710:11;;95036:26;;;95023:40;;86836;:::i;:::-;86822:11;;;:54;86889:2200;86911:15;86896:8;:11;;;:30;;:98;;;;;86983:11;86955:18;:25;:39;;;;:::i;:::-;86930:8;:22;;;:64;86896:98;86889:2200;;;87128:8;:13;;;87077:18;87096:8;:22;;;87077:42;;;;;;;;:::i;:::-;;;;;;;:48;;;:64;87073:189;;;87207:11;;;;61710;98985:19;;87193:26;87178:11;;;87162:57;;;87238:8;;87073:189;87397:8;:11;;;87348:18;87367:8;:22;;;87348:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:60;87344:204;;;87464:22;;;87462:24;;;;;;87524:8;;87344:204;87630:18;87649:8;:22;;;87630:42;;;;;;;;:::i;:::-;;;;;;;:54;;;87688:1;87630:59;87626:184;;87755:11;;;;61710;98985:19;;87741:26;98861:163;87626:184;87937:22;;;;:27;:75;;;;-1:-1:-1;87982:13:0;;87968:11;;;;61710;;87968:27;;;:::i;:::-;:44;87937:75;87933:494;;;88090:183;88196:8;:13;;;88182:8;:11;;;:27;61710:11;88090:18;88109:8;:22;;;88090:42;;;;;;;;:::i;:::-;;;;;;;:54;;;:65;;:183;;;;;:::i;:::-;88066:21;;;:207;87933:494;;;88357:18;88376:8;:22;;;88357:42;;;;;;;;:::i;:::-;;;;;;;:54;;;88333:8;:21;;:78;;;;;87933:494;88520:21;;;;:48;;88553:14;88520:32;:48::i;:::-;88639:36;;;;88497:71;;;88616:148;;88617:58;;61659:3;88710:35;;88616:71;:148::i;:::-;88587:26;;;:177;;;88783:36;;;:58;;;89065:11;;;;61659:3;88945:43;;88927:61;;;;;88860:48;;;61710:11;98985:19;;89051:26;98861:163;86889:2200;89186:13;;89202:15;-1:-1:-1;89186:85:0;;;;;89246:18;:25;89221:8;:22;;;:50;89186:85;89182:933;;;89459:15;89410:18;89429:8;:22;;;89410:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:64;:153;;;;;89562:1;89548:11;89520:18;:25;:39;;;;:::i;:::-;:43;;;;:::i;:::-;89495:8;:22;;;:68;89410:153;89388:302;;;89633:22;;;89631:24;;;;;;89388:302;89760:15;89710:18;89729:8;:22;;;89710:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:65;89706:398;;89829:18;61710:11;89952:8;:13;;;89934:15;:31;89851:18;89870:8;:22;;;89851:42;;;;;;;;:::i;:::-;;;;;;;:54;;;:115;89850:134;;;;;:::i;:::-;;;-1:-1:-1;90032:37:0;89850:134;90054:14;90032:21;:37::i;:::-;90009:60;;;;89796:293;89706:398;-1:-1:-1;;;;90156:36:0;;;;;;90135:19;;90156:36;;-1:-1:-1;90194:14:0;;-1:-1:-1;90194:14:0;;-1:-1:-1;85492:4745:0;;-1:-1:-1;;85492:4745:0:o;81735:1914::-;81833:7;81855;81877;81899;81934:22;81959:10;;81934:35;;81984:14;82002:1;81984:19;81980:137;;82028:15;;82045:27;;82074:14;82090;;82020:85;;;;;;;;;;;81980:137;82157:16;;82216:15;;82284:27;;82353:14;;82409:7;82380:36;;;;;;;;;;;;;;;;;;;82129:25;;82380:36;;82409:7;;82129:25;;82380:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;82380:36:0;;;;;;;;;;;;;;;;-1:-1:-1;82380:36:0;;-1:-1:-1;82549:17:0;;-1:-1:-1;82429:12:0;;-1:-1:-1;82429:12:0;;-1:-1:-1;82429:12:0;82582:44;61710:11;95036:26;;;95023:40;;82582:44;:::i;:::-;82577:49;;82637:683;82650:15;82644:2;:21;82637:683;;82697:38;82714:10;82726:4;82732:2;82697:16;:38::i;:::-;82682:53;-1:-1:-1;82802:39:0;82682:53;82826:14;82802:23;:39::i;:::-;82779:62;;;;82880:143;82881:53;;;61659:3;82969:35;;82880:66;:143::i;:::-;61659:3;83190:34;;83172:52;;;;;83134:19;;-1:-1:-1;83042:39:0;;;;83252:2;;-1:-1:-1;;61710:11:0;83273:20;;;82637:683;;;83343:15;83336:4;:22;83332:200;;;83390:51;83407:10;83419:4;83425:15;83390:16;:51::i;:::-;83375:66;-1:-1:-1;83481:39:0;83375:66;83505:14;83481:23;:39::i;:::-;83458:62;;;;:::i;:::-;;;83332:200;-1:-1:-1;83552:19:0;;83573:31;;-1:-1:-1;83606:14:0;;-1:-1:-1;83622:18:0;;-1:-1:-1;81735:1914:0;;-1:-1:-1;;;;;;81735:1914:0:o;18407:113::-;14837:13;;;;;;;14829:69;;;;;;;15687:2:1;14829:69:0;;;15669:21:1;15726:2;15706:18;;;15699:30;15765:34;15745:18;;;15738:62;15836:13;15816:18;;;15809:41;15867:19;;14829:69:0;15485:407:1;14829:69:0;18480:32:::1;17060:10:::0;18480:18:::1;:32::i;22725:166::-:0;22790:7;22817:21;22828:1;22831;22674:4;22817:10;:21::i;92553:108::-;92611:9;92644:1;92640;:5;:13;;92652:1;92640:13;;23067:166;23132:7;23159:21;23170:1;22674:4;23178:1;23159:10;:21::i;97784:1011::-;97927:16;97945:7;98063:30;98110:10;:17;98130:1;98110:21;;;;:::i;:::-;98096:36;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;98096:36:0;;98063:69;;98143:26;98180:13;98204:11;98226:24;98268:9;98263:470;98283:10;:17;98279:1;:21;98263:470;;;98327:30;98331:4;98337:10;98348:1;98337:13;;;;;;;;:::i;:::-;;;;;;;:19;;;98327:30;;:3;:30::i;:::-;98319:38;;98378:26;98382:2;98386:10;98397:1;98386:13;;;;;;;;:::i;:::-;;;;;;;:17;;;98378:26;;:3;:26::i;:::-;98372:32;;98460:3;98452:5;:11;98448:235;;;98524:5;98488:13;98502:18;;;;;;98488:33;;;;;;;;:::i;:::-;;;;;;:41;;;;;98588:3;98552:13;98566:18;;;;;;98552:33;;;;;;;;:::i;:::-;;;;;;:39;;;;;98448:235;;;98662:1;98640:23;;;;98448:235;98703:3;;98263:470;;;-1:-1:-1;98753:13:0;;98768:18;;-1:-1:-1;97784:1011:0;;-1:-1:-1;;;;;;;97784:1011:0:o;33046:1057::-;33197:1;33191:8;33241:1;33238;33231:12;33329:1;33326;33322:9;33319:1;33315:17;33369:4;33400:2;33396:7;33439:1;33436;33432:9;33417:612;33473:9;;33503:8;;;33514:5;33500:21;33554:1;33548:8;33598:1;33595;33591:9;33670:1;33664:8;33727:1;33724;33721:8;33711:32;;33733:8;;;33417:612;;33711:32;33761:215;33803:9;;;33796:20;33843:9;;33898:8;;33938;;;33761:215;33928:29;-1:-1:-1;34001:9:0;;33994:20;33417:612;;;-1:-1:-1;;;34043:12:0;;-1:-1:-1;33046:1057:0:o;96058:1639::-;96234:33;96269:19;96378:1;96357:18;96334:13;:20;:41;;;;:::i;:::-;:45;;;;:::i;:::-;96316:64;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;96316:64:0;;;;;;;;;;;;;;;;-1:-1:-1;96301:79:0;-1:-1:-1;96393:13:0;;;;;96535:18;96518:1125;96582:1;96559:13;:20;:24;;;;:::i;:::-;96555:1;:28;96518:1125;;;96610:13;96624:1;96610:16;;;;;;;;:::i;:::-;;;;;;;96602:24;;96647:13;96661:1;96665;96661:5;;;;:::i;:::-;96647:20;;;;;;;;:::i;:::-;;;;;;;96641:26;;96695:3;96686:5;:12;96682:173;;96752:13;;;;;96788:3;96518:1125;;96682:173;96883:1;96869:15;;96908:1;96904:5;;96899:585;96915:10;:17;96911:1;:21;96899:585;;;96981:5;96959:10;96970:1;96959:13;;;;;;;;:::i;:::-;;;;;;;:19;;;:27;;;96955:170;;;97048:3;;;;;96899:585;;96955:170;97167:3;97147:10;97158:1;97147:13;;;;;;;;:::i;:::-;;;;;;;:17;;;:23;;;97143:166;;;97232:3;;;;;96899:585;;97143:166;97394:10;97405:1;97394:13;;;;;;;;:::i;:::-;;;;;;;:29;;;-1:-1:-1;;;;;97377:46:0;61710:11;97377:46;97362:61;;;;97446:3;;;;;96899:585;;;97580:36;;;;;;;;;;;;;;;;;;;;;;;97551:26;;97529:3;97564:12;;;;97529:3;;;97551:12;;:26;;;;;;:::i;:::-;;;;;;:65;;;;96518:1125;;;;97655:34;;;;;96058:1639;;;;;;:::o;95159:790::-;95296:20;;95329:613;95353:10;:17;95349:1;:21;95329:613;;;95398:10;95409:1;95398:13;;;;;;;;:::i;:::-;;;;;;;:19;;;95393:24;;:2;:24;95389:147;;;95471:3;;95329:613;;95389:147;95561:10;95572:1;95561:13;;;;;;;;:::i;:::-;;;;;;;:17;;;95554:24;;:4;:24;95550:147;;;95632:3;;95329:613;;95550:147;95864:10;95875:1;95864:13;;;;;;;;:::i;:::-;;;;;;;:29;;;-1:-1:-1;;;;;95779:114:0;95809:30;95813:10;95824:1;95813:13;;;;;;;;:::i;:::-;;;;;;;:19;;;95809:30;;95834:4;95809:3;:30::i;:::-;95780:26;95784:2;95788:10;95799:1;95788:13;;;;;;;;:::i;95780:26::-;:59;95779:114;95742:151;;;;;95912:3;;95329:613;;;;95159:790;;;;;:::o;14:156:1:-;80:20;;140:4;129:16;;119:27;;109:55;;160:1;157;150:12;109:55;14:156;;;:::o;175:182::-;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;324:27;341:9;324:27;:::i;362:949::-;581:2;633:21;;;703:13;;606:18;;;725:22;;;552:4;;581:2;766;;784:18;;;;825:15;;;552:4;868:417;882:6;879:1;876:13;868:417;;;941:13;;1016:9;;977:10;1012:18;;;1000:31;;1075:11;;;1069:18;1065:27;1051:12;;;1044:49;1137:11;;1131:18;-1:-1:-1;;;;;1127:75:1;1113:12;;;1106:97;1232:4;1223:14;;;;1260:15;;;;904:1;897:9;868:417;;;-1:-1:-1;1302:3:1;;362:949;-1:-1:-1;;;;;;;362:949:1:o;1316:196::-;1384:20;;-1:-1:-1;;;;;1433:54:1;;1423:65;;1413:93;;1502:1;1499;1492:12;1517:118;1603:5;1596:13;1589:21;1582:5;1579:32;1569:60;;1625:1;1622;1615:12;1640:315;1705:6;1713;1766:2;1754:9;1745:7;1741:23;1737:32;1734:52;;;1782:1;1779;1772:12;1734:52;1805:29;1824:9;1805:29;:::i;:::-;1795:39;;1884:2;1873:9;1869:18;1856:32;1897:28;1919:5;1897:28;:::i;:::-;1944:5;1934:15;;;1640:315;;;;;:::o;2142:186::-;2201:6;2254:2;2242:9;2233:7;2229:23;2225:32;2222:52;;;2270:1;2267;2260:12;2222:52;2293:29;2312:9;2293:29;:::i;2333:928::-;2548:2;2600:21;;;2670:13;;2573:18;;;2692:22;;;2519:4;;2548:2;2733;;2751:18;;;;2792:15;;;2519:4;2835:400;2849:6;2846:1;2843:13;2835:400;;;2908:13;;2950:9;;2961:6;2946:22;2934:35;;3013:11;;;3007:18;3027:10;3003:35;2989:12;;;2982:57;3083:11;;3077:18;-1:-1:-1;;;;;3073:79:1;3059:12;;;3052:101;3182:4;3173:14;;;;3210:15;;;;2871:1;2864:9;2835:400;;3266:163;3333:20;;3393:10;3382:22;;3372:33;;3362:61;;3419:1;3416;3409:12;3434:461;3509:6;3517;3525;3578:2;3566:9;3557:7;3553:23;3549:32;3546:52;;;3594:1;3591;3584:12;3546:52;3617:28;3635:9;3617:28;:::i;:::-;3607:38;;3664:37;3697:2;3686:9;3682:18;3664:37;:::i;:::-;3654:47;;3751:2;3740:9;3736:18;3723:32;-1:-1:-1;;;;;3788:5:1;3784:62;3777:5;3774:73;3764:101;;3861:1;3858;3851:12;3764:101;3884:5;3874:15;;;3434:461;;;;;:::o;4092:180::-;4151:6;4204:2;4192:9;4183:7;4179:23;4175:32;4172:52;;;4220:1;4217;4210:12;4172:52;-1:-1:-1;4243:23:1;;4092:180;-1:-1:-1;4092:180:1:o;4277:208::-;4345:20;;-1:-1:-1;;;;;4394:66:1;;4384:77;;4374:105;;4475:1;4472;4465:12;4490:254;4558:6;4566;4619:2;4607:9;4598:7;4594:23;4590:32;4587:52;;;4635:1;4632;4625:12;4587:52;4671:9;4658:23;4648:33;;4700:38;4734:2;4723:9;4719:18;4700:38;:::i;:::-;4690:48;;4490:254;;;;;:::o;4980:::-;5048:6;5056;5109:2;5097:9;5088:7;5084:23;5080:32;5077:52;;;5125:1;5122;5115:12;5077:52;5148:29;5167:9;5148:29;:::i;:::-;5138:39;5224:2;5209:18;;;;5196:32;;-1:-1:-1;;;4980:254:1:o;5239:::-;5307:6;5315;5368:2;5356:9;5347:7;5343:23;5339:32;5336:52;;;5384:1;5381;5374:12;5336:52;5407:29;5426:9;5407:29;:::i;6153:385::-;6239:6;6247;6255;6263;6316:3;6304:9;6295:7;6291:23;6287:33;6284:53;;;6333:1;6330;6323:12;6284:53;-1:-1:-1;;6356:23:1;;;6426:2;6411:18;;6398:32;;-1:-1:-1;6477:2:1;6462:18;;6449:32;;6528:2;6513:18;6500:32;;-1:-1:-1;6153:385:1;-1:-1:-1;6153:385:1:o;6543:250::-;6609:6;6617;6670:2;6658:9;6649:7;6645:23;6641:32;6638:52;;;6686:1;6683;6676:12;6638:52;6709:27;6726:9;6709:27;:::i;7222:184::-;7274:77;7271:1;7264:88;7371:4;7368:1;7361:15;7395:4;7392:1;7385:15;7411:184;7463:77;7460:1;7453:88;7560:4;7557:1;7550:15;7584:4;7581:1;7574:15;7600:125;7665:9;;;7686:10;;;7683:36;;;7699:18;;:::i;7730:168::-;7803:9;;;7834;;7851:15;;;7845:22;;7831:37;7821:71;;7872:18;;:::i;8393:184::-;8445:77;8442:1;8435:88;8542:4;8539:1;8532:15;8566:4;8563:1;8556:15;8582:112;8614:1;8640;8630:35;;8645:18;;:::i;:::-;-1:-1:-1;8679:9:1;;8582:112::o;8699:175::-;8767:10;8810;;;8798;;;8794:27;;8833:12;;;8830:38;;;8848:18;;:::i;:::-;8830:38;8699:175;;;;:::o;8879:316::-;-1:-1:-1;;;;;9051:10:1;;;9021;;;9085:13;;;9081:22;;;8951:50;9125:11;;9146:17;;;9138:26;;9122:43;9112:77;;9169:18;;:::i;:::-;9112:77;;;8879:316;;;;:::o;9660:245::-;9727:6;9780:2;9768:9;9759:7;9755:23;9751:32;9748:52;;;9796:1;9793;9786:12;9748:52;9828:9;9822:16;9847:28;9869:5;9847:28;:::i;10638:128::-;10705:9;;;10726:11;;;10723:37;;;10740:18;;:::i;11024:184::-;11076:77;11073:1;11066:88;11173:4;11170:1;11163:15;11197:4;11194:1;11187:15;14091:171;14159:6;14198:10;;;14186;;;14182:27;;14221:12;;;14218:38;;;14236:18;;:::i;14267:320::-;-1:-1:-1;;;;;14443:10:1;;;14413;;;14477:13;;;14473:22;;;14339:54;14517:11;;14538:17;;;14530:26;;14514:43;14504:77;;14561:18;;:::i;15360:120::-;15400:1;15426;15416:35;;15431:18;;:::i;:::-;-1:-1:-1;15465:9:1;;15360:120::o;15897:195::-;15936:3;-1:-1:-1;;15960:5:1;15957:77;15954:103;;16037:18;;:::i;:::-;-1:-1:-1;16084:1:1;16073:13;;15897:195::o;16097:184::-;16149:77;16146:1;16139:88;16246:4;16243:1;16236:15;16270:4;16267:1;16260:15
Swarm Source
ipfs://9d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea243
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.