ERC-20
Overview
Max Total Supply
98,979.256628286697480865 WHO
Holders
362
Total Transfers
-
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
WHO333
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ERC333} from "./ERC333/ERC333.sol"; import {FullMath} from "./utils/FullMath.sol"; contract WHO333 is ERC333 { using Strings for uint256; string private constant __NAME = "WHO333"; string private constant __SYM = "WHO"; uint256 private constant __MINT_SUPPLY = 1000; uint24 private constant __TAX_PERCENT = 80000; uint8 private constant __DECIMALS = 18; uint8 private constant __RATIO = 100; address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; constructor( address initialOwner_, address initialMintRecipient_ ) ERC333( initialOwner_, initialMintRecipient_, __MINT_SUPPLY, __TAX_PERCENT, __NAME, __SYM, __DECIMALS, __RATIO ) { baseURI = "https://who333.wtf/assets/"; } function setERC721TransferExempt( address target_, bool state_ ) external onlyOwner { _setERC721TransferExempt(target_, state_); } function withdrawAll() external onlyOwner { // Call balanceOf // 0x70a08231: keccak256(balanceOf(address)) (bool success0, bytes memory data0) = WETH.staticcall( abi.encodeWithSelector(0x70a08231, address(this)) ); if (!success0) { return; } // Decode `uint256` from returned data uint256 totalWETHAmount = abi.decode(data0, (uint256)); // Call WETH transfer // 0xa9059cbb: keccak256(transfer(address,uint256)) (bool success, ) = WETH.call( abi.encodeWithSelector(0xa9059cbb, msg.sender, totalWETHAmount) ); } function setTickThreshold(int24 tickThreshold_) external onlyOwner { tickThreshold = tickThreshold_; } function initialize() external payable override onlyOwner { address positionManagerAddress = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88; address swapRouterAddress = 0xE592427A0AEce92De3Edee1F18E0157C05861564; if (msg.value > 0) { _depositETH(msg.value); } uint160 sqrtPriceX96 = (address(this) < WETH) ? 1372272028650297984479657984 // 0.0003 : 4574240095500993129133247561728; // 3333.333333333333 uint256 quoteTokenAmount = _getWETHAtSqrtPriceX96(sqrtPriceX96); // require(quoteTokenAmount > 14e17, "quoteTokenAmount"); uint256 wethAmount = _balanceOfWETH(); require(wethAmount >= quoteTokenAmount, "weth amount is too low"); // initialize liquidity _initialize( sqrtPriceX96, 3000, WETH, quoteTokenAmount, 60, positionManagerAddress, swapRouterAddress ); // initialize market limit for control _registerAll(); } function tokenURI(uint256 id) public view override returns (string memory) { uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id)))); string memory image; string memory color; if (seed <= 64) { image = "0.png"; color = "Red"; } else if (seed <= 128) { image = "1.png"; color = "Blue"; } else if (seed <= 192) { image = "2.png"; color = "Green"; } else { image = "3.png"; color = "Purple"; } return string( abi.encodePacked( '{"name": "WHO333 NFT#', Strings.toString(id), '","description":"A collection of ', Strings.toString(mintSupply), " pots of liquidity that tokenizes decentralized reserve currency idea for the IQ50, #ERC333.", '","external_url":"https://who333.wtf/","image":"', baseURI, image, '","attributes":[{"trait_type":"Color","value":"', color, '"}]}' ) ); } function _balanceOfWETH() internal returns (uint256 amount) { // Call balanceOf // 0x70a08231: keccak256(balanceOf(address)) (bool success, bytes memory data) = WETH.staticcall( abi.encodeWithSelector(0x70a08231, address(this)) ); if (success) { // Decode `uint256` from returned data amount = abi.decode(data, (uint256)); } } function _depositETH(uint256 amount) internal returns (bool) { // Deposit the eth // Call deposit // 0xd0e30db0: keccak256(deposit()) (bool success, ) = WETH.call{value: amount}( abi.encodeWithSelector(0xd0e30db0) ); return success; } function _getWETHAtSqrtPriceX96( uint160 sqrtPriceX96 ) private view returns (uint256 quoteAmount) { // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself uint256 thisAmount = balanceOf[address(this)]; if (sqrtPriceX96 <= type(uint128).max) { uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; quoteAmount = address(this) < WETH ? FullMath.mulDiv(ratioX192, thisAmount, 1 << 192) : FullMath.mulDiv(1 << 192, thisAmount, ratioX192); } else { uint256 ratioX128 = FullMath.mulDiv( sqrtPriceX96, sqrtPriceX96, 1 << 64 ); quoteAmount = address(this) < WETH ? FullMath.mulDiv(ratioX128, thisAmount, 1 << 128) : FullMath.mulDiv(1 << 128, thisAmount, ratioX128); } } receive() external payable { _depositETH(msg.value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @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. * * The initial owner is set to the address provided by the deployer. 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 Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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 { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ERC404} from "../ERC404/ERC404.sol"; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {PoolAddress} from "../utils/PoolAddress.sol"; import {TickMath} from "../utils/TickMath.sol"; import {PoolData} from "../structs/PoolData.sol"; import {MintParams, IncreaseLiquidityParams, DecreaseLiquidityParams, CollectParams} from "../structs/PositionParams.sol"; import {ExactInputSingleParams} from "../structs/RouterParams.sol"; abstract contract ERC333 is Ownable, ERC404 { event Initialize(PoolData poolData); event ReceiveTax(uint256 value); event ERC20Burn(uint256 value); event RefundETH(address sender, uint256 value); using Strings for uint256; mapping(address => bool) public operators; bool public marketLimit = false; string constant _JSON_FILE = ".json"; // default settings uint256 public mintSupply = 10000; // max NFT count uint24 public taxPercent = 80000; address public initialMintRecipient; // the first token owner PoolData public currentPoolData; /// @dev for the tick bar of ERC333 int24 public tickThreshold; int24 public currentTick; uint256 public mintTimestamp; /// @dev Total tax in ERC-20 token representation uint256 public totalTax; address public positionManagerAddress; address public swapRouterAddress; /// @dev for compute arithmetic mean tick by observation uint32 constant TWAP_INTERVAL = 30 minutes; event BaseUriUpdate(string uri); string public baseURI; constructor( address initialOwner_, address initialMintRecipient_, uint256 mintSupply_, uint24 taxPercent_, string memory name_, string memory sym_, uint8 decimals_, uint8 ratio_ ) ERC404(name_, sym_, decimals_, ratio_) Ownable(initialOwner_) { // init settings mintSupply = mintSupply_; taxPercent = taxPercent_; initialMintRecipient = initialMintRecipient_; // Do not mint the ERC721s to the initial owner, as it's a waste of gas. _setERC721TransferExempt(initialMintRecipient_, true); _mintERC20(initialMintRecipient_, mintSupply * units); } // ====================================================================================================== // // ERC333 overrides // // ====================================================================================================== function initialized() public view returns (bool) { return currentPoolData.poolAddress != address(0); } function initialize() external payable virtual; function _initialize( uint160 sqrtPriceX96, uint24 fee, address quoteToken, uint256 quoteTokenAmount, uint16 observationCardinalityNext, address positionManagerAddress_, address swapRouterAddress_ ) internal virtual onlyOwner { require(!initialized(), "already initialized"); positionManagerAddress = positionManagerAddress_; swapRouterAddress = swapRouterAddress_; currentPoolData.quoteToken = quoteToken; currentPoolData.fee = fee; currentPoolData.sqrtPriceX96 = sqrtPriceX96; (address token0, address token1) = (address(this), quoteToken); (uint256 amount0, uint256 amount1) = ( balanceOf[address(this)], quoteTokenAmount ); if (token0 > token1) { (token0, token1) = (token1, token0); (amount0, amount1) = (amount1, amount0); } _approveUniswap(token0, type(uint256).max); _approveUniswap(token1, type(uint256).max); // step1 create pool int24 tickSpacing; ( currentPoolData.poolAddress, currentTick, tickSpacing ) = _initializePool(token0, token1, fee, sqrtPriceX96); require( currentPoolData.poolAddress != address(0) && tickSpacing != 0, "initialize pool failed" ); tickThreshold = currentTick; if (_thisIsToken0()) { currentPoolData.tickLower = (tickThreshold / tickSpacing) * tickSpacing; if (tickThreshold < 0) { currentPoolData.tickLower -= tickSpacing; } // currentPoolData.tickLower = // (TickMath.MIN_TICK / tickSpacing) * // tickSpacing; currentPoolData.tickUpper = (TickMath.MAX_TICK / tickSpacing) * tickSpacing; } else { currentPoolData.tickUpper = (tickThreshold / tickSpacing) * tickSpacing; if (tickThreshold > 0) { currentPoolData.tickUpper += tickSpacing; } currentPoolData.tickLower = (TickMath.MIN_TICK / tickSpacing) * tickSpacing; } // step2 increase observation cardinality if (observationCardinalityNext > 0) { bool success = _initializeObservations( currentPoolData.poolAddress, observationCardinalityNext ); require(success, "initialize observations failed"); } // step3 create liquidity ( currentPoolData.positionId, currentPoolData.liquidity, , ) = _initializeLiquidity( token0, token1, fee, amount0, amount1, currentPoolData.tickLower, currentPoolData.tickUpper, address(this) ); require(currentPoolData.positionId != 0, "initialize liquidity failed"); mintTimestamp = block.timestamp; emit Initialize(currentPoolData); } function _registerAll() internal virtual { register(0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c, true); register(0x82C0fDFA607d9aFbe82Db5cBD103D1a4D5a43B77, true); register(0x5B93A825829f4B7B5177c259Edc22b63d6E4e380, true); register(positionManagerAddress, true); register(swapRouterAddress, true); register(currentPoolData.poolAddress, true); setMarketLimit(true); } /// @notice Explain to an end user what this does /// @dev Explain to a developer any extra details function _getCurrentTokenTick() internal virtual returns (int24) { if (!initialized()) { return tickThreshold; } // Call uniswapV3Pool.slot0 // 0x3850c7bd: keccak256(slot0()) (bool success0, bytes memory data0) = currentPoolData .poolAddress .staticcall(abi.encodeWithSelector(0x3850c7bd)); if (!success0) { return tickThreshold; } // Decode `Slot` from returned data (, int24 tick, uint16 index, uint16 cardinality, , , ) = abi.decode( data0, (uint160, int24, uint16, uint16, uint16, uint8, bool) ); uint32 delta = TWAP_INTERVAL; if (uint32(block.timestamp - mintTimestamp) < delta) { return tick; } uint32[] memory secondsTwapIntervals = new uint32[](2); secondsTwapIntervals[0] = delta; secondsTwapIntervals[1] = 0; // Call uniswapV3Pool.observe // 0x883bdbfd: keccak256(observe(uint32[])) // require(pools[poolFee] != address(0), "Pool must init"); (bool success, bytes memory data) = currentPoolData .poolAddress .staticcall( abi.encodeWithSelector(0x883bdbfd, secondsTwapIntervals) ); if (!success) { return tick; } // Decode `tickCumulatives` from returned data (int56[] memory tickCumulatives, ) = abi.decode( data, (int56[], uint160[]) ); int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0]; tick = int24(tickCumulativesDelta / int56(uint56(delta))); // Always round to negative infinity if ( tickCumulativesDelta < 0 && (tickCumulativesDelta % int56(uint56(delta)) != 0) ) tick--; return tick; } function _approveUniswap( address token, uint256 amount ) internal virtual returns (bool) { if (amount == 0) { return true; } if (token == address(this)) { allowance[address(this)][positionManagerAddress] = amount; allowance[address(this)][swapRouterAddress] = amount; return true; } // Approve the position manager // Call approve // 0x095ea7b3: keccak256(approve(address,uint256)) (bool success0, ) = token.call( abi.encodeWithSelector(0x095ea7b3, positionManagerAddress, amount) ); (bool success1, ) = token.call( abi.encodeWithSelector(0x095ea7b3, swapRouterAddress, amount) ); return success0 && success1; } function _initializePool( address token0, address token1, uint24 fee, uint160 sqrtPriceX96 ) internal virtual returns (address poolAddress, int24 tick, int24 tickSpacing) { // Call position manager createAndInitializePoolIfNecessary // 0x13ead562: keccak256(createAndInitializePoolIfNecessary(address,address,uint24,uint160)) (bool success0, bytes memory data0) = positionManagerAddress.call( abi.encodeWithSelector( 0x13ead562, token0, token1, fee, sqrtPriceX96 ) ); // If createAndInitializePoolIfNecessary hasn't reverted if (!success0) { return (address(0), 0, 0); } // Decode `address` from returned data poolAddress = abi.decode(data0, (address)); // Call uniswapV3Pool.slot0 // 0x3850c7bd: keccak256(slot0()) (bool success1, bytes memory data1) = poolAddress.staticcall( abi.encodeWithSelector(0x3850c7bd) ); if (!success1) { return (address(0), 0, 0); } // Decode `Slot` from returned data (, tick, , , , , ) = abi.decode( data1, (uint160, int24, uint16, uint16, uint16, uint8, bool) ); // Call uniswapV3Pool.tickSpacing // 0xd0c93a7c: keccak256(tickSpacing()) (bool success2, bytes memory data2) = poolAddress.staticcall( abi.encodeWithSelector(0xd0c93a7c) ); if (!success2) { return (address(0), 0, 0); } tickSpacing = abi.decode(data2, (int24)); } function _initializeObservations( address poolAddress, uint16 observationCardinalityNext ) internal virtual returns (bool) { // Call pool increaseObservationCardinalityNext // 0x32148f67: keccak256(increaseObservationCardinalityNext(uint16)) (bool success, ) = poolAddress.call( abi.encodeWithSelector(0x32148f67, observationCardinalityNext) ); return success; } function _initializeLiquidity( address token0, address token1, uint24 fee, uint256 amount0, uint256 amount1, int24 tickLower, int24 tickUpper, address recipient ) internal virtual returns ( uint256 positionId, uint128 liquidity, uint256 amount0Used, uint256 amount1Used ) { MintParams memory params = MintParams({ token0: token0, token1: token1, fee: fee, tickLower: tickLower, tickUpper: tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min: 0, amount1Min: 0, recipient: recipient, deadline: block.timestamp }); // Call position manager mint // 0x88316456: keccak256(mint((address,address,uint24,int24,int24,uint256, // uint256,uint256,uint256,address,uint256))) (bool success, bytes memory data) = positionManagerAddress.call( abi.encodeWithSelector(0x88316456, params) ); // If mint hasn't reverted if (success) { // Decode `(uint256, uint128, uint256, uint256)` from returned data (positionId, liquidity, amount0Used, amount1Used) = abi.decode( data, (uint256, uint128, uint256, uint256) ); } } function _exactInputSingle( address tokenIn, address tokenOut, address recipient, uint256 amountIn ) internal virtual returns (uint256 amountOut) { ExactInputSingleParams memory params = ExactInputSingleParams({ tokenIn: tokenIn, tokenOut: tokenOut, fee: currentPoolData.fee, recipient: recipient, amountIn: amountIn, amountOutMinimum: 0, sqrtPriceLimitX96: 0, deadline: block.timestamp }); // Call position manager increaseLiquidity // 0x414bf389: keccak256(exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))) (bool success, bytes memory data) = swapRouterAddress.call( abi.encodeWithSelector(0x414bf389, params) ); // If exactInputSingle hasn't reverted if (success) { // Decode `(uint128, uint256, uint256)` from returned data amountOut = abi.decode(data, (uint256)); } } function _increaseLiquidity( uint256 positionId, uint256 amount0, uint256 amount1 ) internal virtual returns (uint128 liquidity, uint256 amount0Used, uint256 amount1Used) { IncreaseLiquidityParams memory params = IncreaseLiquidityParams({ tokenId: positionId, amount0Desired: amount0, amount1Desired: amount1, amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); // Call position manager increaseLiquidity // 0x219f5d17: keccak256(increaseLiquidity((uint256,uint256,uint256,uint256,uint256,uint256))) (bool success, bytes memory data) = positionManagerAddress.call( abi.encodeWithSelector(0x219f5d17, params) ); // If increaseLiquidity hasn't reverted if (success) { // Decode `(uint128, uint256, uint256)` from returned data (liquidity, amount0Used, amount1Used) = abi.decode( data, (uint128, uint256, uint256) ); } } function _decreaseLiquidity( uint256 positionId, uint128 liquidity ) internal virtual returns (uint256 amount0, uint256 amount1) { DecreaseLiquidityParams memory params = DecreaseLiquidityParams({ tokenId: positionId, liquidity: liquidity, amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); // Call position manager increaseLiquidity // 0x0c49ccbe: keccak256(decreaseLiquidity((uint256,uint128,uint256,uint256,uint256))) (bool success, bytes memory data) = positionManagerAddress.call( abi.encodeWithSelector(0x0c49ccbe, params) ); // If decreaseLiquidity hasn't reverted if (success) { // Decode `(uint128, uint256, uint256)` from returned data (amount0, amount1) = abi.decode(data, (uint256, uint256)); } } function _collect( uint256 positionId, address recipient ) internal virtual returns (uint256 amount0, uint256 amount1) { CollectParams memory params = CollectParams({ tokenId: positionId, recipient: recipient, amount0Max: type(uint128).max, amount1Max: type(uint128).max }); // Call position manager increaseLiquidity // 0xfc6f7865: keccak256(collect((uint256,address,uint128,uint128))) (bool success, bytes memory data) = positionManagerAddress.call( abi.encodeWithSelector(0xfc6f7865, params) ); // If decreaseLiquidity hasn't reverted if (success) { // Decode `(uint128, uint256, uint256)` from returned data (amount0, amount1) = abi.decode(data, (uint256, uint256)); } } function _thisIsToken0() internal view returns (bool) { return (address(this) < currentPoolData.quoteToken); } function _getTaxOrBurned( address from_, address to_, uint256 value_ ) internal virtual returns (uint256 tax, bool burned) { if ( from_ == initialMintRecipient || msg.sender == initialMintRecipient || msg.sender == swapRouterAddress || from_ == address(this) || to_ == address(currentPoolData.poolAddress) ) { return (0, false); } // get token tick currentTick = _getCurrentTokenTick(); if (_thisIsToken0()) { if (currentTick > tickThreshold) { tax = (value_ * taxPercent) / 1000000; } else if (currentTick < tickThreshold) { burned = true; } else { // do someting if getCurrentTokenTick failed } } else { if (currentTick < tickThreshold) { tax = (value_ * taxPercent) / 1000000; } else if (currentTick > tickThreshold) { burned = true; } else { // do someting if getCurrentTokenTick failed } } } function _transferWithERC20Tax( address from_, address to_, uint256 value_ ) internal virtual returns (bool) { (uint256 tax, bool burned) = _getTaxOrBurned(from_, to_, value_); if (burned) { // burn from_ token, _transferERC20WithERC721(from_, address(0), value_); // refund the ETH value to the to_ address _refundETH(to_, value_); totalSupply -= value_; emit ERC20Burn(value_); } else if (tax > 0) { _transferERC20WithERC721(from_, to_, value_ - tax); _transferERC20WithERC721(from_, address(this), tax); totalTax += tax; emit ReceiveTax(tax); } else { // Transferring ERC-20s directly requires the _transfer function. _transferERC20WithERC721(from_, to_, value_); } return true; } function swapAndLiquify(uint256 amount) external virtual onlyOwner { require( amount <= ((balanceOf[address(this)] * 2) / 3), "amount is too large" ); // swap tokens for ETH uint256 quoteAmount = _swapTokensForQuote(amount); if (quoteAmount > 0) { // add liquidity to uniswap _addLiquidity(balanceOf[address(this)], quoteAmount / 2); } } function liquifyAndCollect(uint128 liquidity) external virtual onlyOwner { require( liquidity <= (currentPoolData.liquidity), "liquidity is too large" ); if (liquidity > 0) { _subLiquidity(liquidity); } _collect(currentPoolData.positionId, initialMintRecipient); } function setMarketLimit(bool value) public onlyOwner { marketLimit = value; } function register(address operator_, bool value) public onlyOwner { operators[operator_] = value; } function _swapTokensForQuote( uint256 tokenAmount ) private returns (uint256) { return _exactInputSingle( address(this), currentPoolData.quoteToken, address(this), tokenAmount ); } function _addLiquidity(uint256 thisAmount, uint256 quoteAmount) private { (address token0, address token1) = ( address(this), currentPoolData.quoteToken ); (uint256 amount0, uint256 amount1) = (thisAmount, quoteAmount); if (token0 > token1) { (token0, token1) = (token1, token0); (amount0, amount1) = (amount1, amount0); } uint128 liquidity; (liquidity, amount0, amount1) = _increaseLiquidity( currentPoolData.positionId, amount0, amount1 ); if (liquidity > 0) { currentPoolData.liquidity += liquidity; } } function _subLiquidity(uint128 liquidity) private { (uint256 amount0, uint256 amount1) = _decreaseLiquidity( currentPoolData.positionId, liquidity ); if (amount0 > 0 || amount1 > 0) { currentPoolData.liquidity -= liquidity; } } function _refundETH(address account, uint256 value) internal virtual { if (account == address(0)) { revert InvalidSender(); } // Call balanceOf // 0x70a08231: keccak256(balanceOf(address)) (bool success0, bytes memory data0) = currentPoolData .quoteToken .staticcall(abi.encodeWithSelector(0x70a08231, address(this))); if (!success0) { return; } // Decode `uint256` from returned data uint256 totalWETHAmount = abi.decode(data0, (uint256)); uint256 wethAmount = (value * totalWETHAmount) / totalSupply; // Call WETH transfer // 0xa9059cbb: keccak256(transfer(address,uint256)) (bool success, ) = currentPoolData.quoteToken.call( abi.encodeWithSelector(0xa9059cbb, account, wethAmount) ); // If transfer hasn't reverted if (success) { emit RefundETH(account, wethAmount); } } /// @notice Function for ERC-20 transfers. /// @dev This function assumes the operator is attempting to transfer as ERC-20 /// given this function is only supported on the ERC-20 interface function transfer( address to_, uint256 value_ ) public override returns (bool) { // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } return _transferWithERC20Tax(msg.sender, to_, value_); } // /// @notice Function for mixed transfers from an operator that may be different than 'from'. // /// @dev This function assumes the operator is attempting to transfer an ERC-721 // /// if valueOrId is less than or equal to current max id. // function transferFrom( // address from_, // address to_, // uint256 valueOrId_ // ) public override returns (bool) { // if (marketLimit) { // require( // msg.sender == owner() || // msg.sender == initialMintRecipient || // operators[msg.sender], // "not allowed" // ); // } // // Prevent transferring tokens from 0x0. // if (from_ == address(0)) { // revert InvalidSender(); // } // // Prevent burning tokens to 0x0. // if (to_ == address(0)) { // revert InvalidRecipient(); // } // if (valueOrId_ <= minted) { // // Intention is to transfer as ERC-721 token (id). // uint256 id = valueOrId_; // if (from_ != _getOwnerOf(id)) { // revert Unauthorized(); // } // // Check that the operator is either the sender or approved for the transfer. // if ( // msg.sender != from_ && // !isApprovedForAll[from_][msg.sender] && // msg.sender != getApproved[id] // ) { // revert Unauthorized(); // } // // Transfer 1 * units ERC-20 and 1 ERC-721 token. // _transferERC20(from_, to_, units); // _transferERC721(from_, to_, id); // } else { // // Intention is to transfer as ERC-20 token (value). // uint256 value = valueOrId_; // uint256 allowed = allowance[from_][msg.sender]; // // Check that the operator has sufficient allowance. // if (allowed != type(uint256).max) { // allowance[from_][msg.sender] = allowed - value; // } // return _transferWithERC20Tax(from_, to_, value); // } // return true; // } /// @notice Function for ERC-20 transfers from. /// @dev This function is recommended for ERC20 transfers function erc20TransferFrom( address from_, address to_, uint256 value_ ) public override returns (bool) { // Prevent minting tokens from 0x0. if (from_ == address(0)) { revert InvalidSender(); } // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } uint256 allowed = allowance[from_][msg.sender]; // Check that the operator has sufficient allowance. if (allowed != type(uint256).max) { allowance[from_][msg.sender] = allowed - value_; } // Transferring ERC-20s directly requires the _transferERC20WithERC721 function. // Handles ERC-721 exemptions internally. // return _transferERC20WithERC721(from_, to_, value_); return _transferWithERC20Tax(from_, to_, value_); } /// @notice Function for ERC-721 transfers from. /// @dev This function is recommended for ERC721 transfers. function erc721TransferFrom( address from_, address to_, uint256 id_ ) public override { // Prevent minting tokens from 0x0. if (from_ == address(0)) { revert InvalidSender(); } // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } if (from_ != _getOwnerOf(id_)) { revert Unauthorized(); } if (marketLimit) { require( msg.sender == owner() || msg.sender == initialMintRecipient || operators[msg.sender], "not allowed" ); } // Check that the operator is either the sender or approved for the transfer. if ( msg.sender != from_ && !isApprovedForAll[from_][msg.sender] && msg.sender != getApproved[id_] ) { revert Unauthorized(); } // We only need to check ERC-721 transfer exempt status for the recipient // since the sender being ERC-721 transfer exempt means they have already // had their ERC-721s stripped away during the rebalancing process. if (erc721TransferExempt(to_)) { revert RecipientIsERC721TransferExempt(); } // Transfer 1 * units ERC-20 and 1 ERC-721 token. // ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt. _transferERC20(from_, to_, units); _transferERC721(from_, to_, id_); } /// @notice Function for self-exemption function setSelfERC721TransferExempt(bool state_) public override { // _setERC721TransferExempt(msg.sender, state_); revert Unauthorized(); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC721Receiver} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol"; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; import {IERC404} from "./interfaces/IERC404.sol"; import {DoubleEndedQueue} from "./lib/DoubleEndedQueue.sol"; import {ERC721Events} from "./lib/ERC721Events.sol"; import {ERC20Events} from "./lib/ERC20Events.sol"; abstract contract ERC404 is IERC404 { using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque; /// @dev The queue of ERC-721 tokens stored in the contract. DoubleEndedQueue.Uint256Deque private _storedERC721Ids; /// @dev Token name string public name; /// @dev Token symbol string public symbol; /// @dev Decimals for ERC-20 representation uint8 public immutable decimals; /// @dev Units for ERC-20 representation uint256 public immutable units; /// @dev Total supply in ERC-20 representation uint256 public totalSupply; /// @dev Current mint counter which also represents the highest /// minted id, monotonically increasing to ensure accurate ownership uint256 public minted; /// @dev Initial chain id for EIP-2612 support uint256 internal immutable _INITIAL_CHAIN_ID; /// @dev Initial domain separator for EIP-2612 support bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR; /// @dev Balance of user in ERC-20 representation mapping(address => uint256) public balanceOf; /// @dev Allowance of user in ERC-20 representation mapping(address => mapping(address => uint256)) public allowance; /// @dev Approval in ERC-721 representaion mapping(uint256 => address) public getApproved; /// @dev Approval for all in ERC-721 representation mapping(address => mapping(address => bool)) public isApprovedForAll; /// @dev Packed representation of ownerOf and owned indices mapping(uint256 => uint256) internal _ownedData; /// @dev Array of owned ids in ERC-721 representation mapping(address => uint256[]) internal _owned; /// @dev Addresses that are exempt from ERC-721 transfer, typically for gas savings (pairs, routers, etc) mapping(address => bool) internal _erc721TransferExempt; /// @dev EIP-2612 nonces mapping(address => uint256) public nonces; /// @dev Address bitmask for packed ownership data uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; /// @dev Owned index bitmask for packed ownership data uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160; /// @dev Constant for token id encoding uint256 public constant ID_ENCODING_PREFIX = 1e36; constructor( string memory name_, string memory symbol_, uint8 decimals_, uint8 ratio_ ) { name = name_; symbol = symbol_; if (decimals_ < 18) { revert DecimalsTooLow(); } decimals = decimals_; units = 10 ** decimals * ratio_; // EIP-2612 initialization _INITIAL_CHAIN_ID = block.chainid; _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator(); } /// @notice Function to find owner of a given ERC-721 token function ownerOf( uint256 id_ ) public view virtual returns (address erc721Owner) { erc721Owner = _getOwnerOf(id_); if (!_isValidTokenId(id_)) { revert InvalidTokenId(); } if (erc721Owner == address(0)) { revert NotFound(); } } function owned( address owner_ ) public view virtual returns (uint256[] memory) { return _owned[owner_]; } function erc721BalanceOf( address owner_ ) public view virtual returns (uint256) { return _owned[owner_].length; } function erc20BalanceOf( address owner_ ) public view virtual returns (uint256) { return balanceOf[owner_]; } function erc20TotalSupply() public view virtual returns (uint256) { return totalSupply; } function erc721TotalSupply() public view virtual returns (uint256) { return minted; } function getERC721QueueLength() public view virtual returns (uint256) { return _storedERC721Ids.length(); } function getERC721TokensInQueue( uint256 start_, uint256 count_ ) public view virtual returns (uint256[] memory) { uint256[] memory tokensInQueue = new uint256[](count_); for (uint256 i = start_; i < start_ + count_; ) { tokensInQueue[i - start_] = _storedERC721Ids.at(i); unchecked { ++i; } } return tokensInQueue; } /// @notice tokenURI must be implemented by child contract function tokenURI(uint256 id_) public view virtual returns (string memory); /// @notice Function for token approvals /// @dev This function assumes the operator is attempting to approve /// an ERC-721 if valueOrId_ is a possibly valid ERC-721 token id. /// Unlike setApprovalForAll, spender_ must be allowed to be 0x0 so /// that approval can be revoked. function approve( address spender_, uint256 valueOrId_ ) public virtual returns (bool) { if (_isValidTokenId(valueOrId_)) { erc721Approve(spender_, valueOrId_); } else { return erc20Approve(spender_, valueOrId_); } return true; } function erc721Approve(address spender_, uint256 id_) public virtual { // Intention is to approve as ERC-721 token (id). address erc721Owner = _getOwnerOf(id_); if ( msg.sender != erc721Owner && !isApprovedForAll[erc721Owner][msg.sender] ) { revert Unauthorized(); } getApproved[id_] = spender_; emit ERC721Events.Approval(erc721Owner, spender_, id_); } /// @dev Providing type(uint256).max for approval value results in an /// unlimited approval that is not deducted from on transfers. function erc20Approve( address spender_, uint256 value_ ) public virtual returns (bool) { // Prevent granting 0x0 an ERC-20 allowance. if (spender_ == address(0)) { revert InvalidSpender(); } allowance[msg.sender][spender_] = value_; emit ERC20Events.Approval(msg.sender, spender_, value_); return true; } /// @notice Function for ERC-721 approvals function setApprovalForAll( address operator_, bool approved_ ) public virtual { // Prevent approvals to 0x0. if (operator_ == address(0)) { revert InvalidOperator(); } isApprovedForAll[msg.sender][operator_] = approved_; emit ERC721Events.ApprovalForAll(msg.sender, operator_, approved_); } /// @notice Function for mixed transfers from an operator that may be different than 'from'. /// @dev This function assumes the operator is attempting to transfer an ERC-721 /// if valueOrId is a possible valid token id. function transferFrom( address from_, address to_, uint256 valueOrId_ ) public virtual returns (bool) { if (_isValidTokenId(valueOrId_)) { erc721TransferFrom(from_, to_, valueOrId_); } else { // Intention is to transfer as ERC-20 token (value). return erc20TransferFrom(from_, to_, valueOrId_); } return true; } /// @notice Function for ERC-721 transfers from. /// @dev This function is recommended for ERC721 transfers. function erc721TransferFrom( address from_, address to_, uint256 id_ ) public virtual { // Prevent minting tokens from 0x0. if (from_ == address(0)) { revert InvalidSender(); } // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } if (from_ != _getOwnerOf(id_)) { revert Unauthorized(); } // Check that the operator is either the sender or approved for the transfer. if ( msg.sender != from_ && !isApprovedForAll[from_][msg.sender] && msg.sender != getApproved[id_] ) { revert Unauthorized(); } // We only need to check ERC-721 transfer exempt status for the recipient // since the sender being ERC-721 transfer exempt means they have already // had their ERC-721s stripped away during the rebalancing process. if (erc721TransferExempt(to_)) { revert RecipientIsERC721TransferExempt(); } // Transfer 1 * units ERC-20 and 1 ERC-721 token. // ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt. _transferERC20(from_, to_, units); _transferERC721(from_, to_, id_); } /// @notice Function for ERC-20 transfers from. /// @dev This function is recommended for ERC20 transfers function erc20TransferFrom( address from_, address to_, uint256 value_ ) public virtual returns (bool) { // Prevent minting tokens from 0x0. if (from_ == address(0)) { revert InvalidSender(); } // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } uint256 allowed = allowance[from_][msg.sender]; // Check that the operator has sufficient allowance. if (allowed != type(uint256).max) { allowance[from_][msg.sender] = allowed - value_; } // Transferring ERC-20s directly requires the _transferERC20WithERC721 function. // Handles ERC-721 exemptions internally. return _transferERC20WithERC721(from_, to_, value_); } /// @notice Function for ERC-20 transfers. /// @dev This function assumes the operator is attempting to transfer as ERC-20 /// given this function is only supported on the ERC-20 interface. /// Treats even large amounts that are valid ERC-721 ids as ERC-20s. function transfer( address to_, uint256 value_ ) public virtual returns (bool) { // Prevent burning tokens to 0x0. if (to_ == address(0)) { revert InvalidRecipient(); } // Transferring ERC-20s directly requires the _transferERC20WithERC721 function. // Handles ERC-721 exemptions internally. return _transferERC20WithERC721(msg.sender, to_, value_); } /// @notice Function for ERC-721 transfers with contract support. /// This function only supports moving valid ERC-721 ids, as it does not exist on the ERC-20 /// spec and will revert otherwise. function safeTransferFrom( address from_, address to_, uint256 id_ ) public virtual { safeTransferFrom(from_, to_, id_, ""); } /// @notice Function for ERC-721 transfers with contract support and callback data. /// This function only supports moving valid ERC-721 ids, as it does not exist on the /// ERC-20 spec and will revert otherwise. function safeTransferFrom( address from_, address to_, uint256 id_, bytes memory data_ ) public virtual { if (!_isValidTokenId(id_)) { revert InvalidTokenId(); } transferFrom(from_, to_, id_); if ( to_.code.length != 0 && IERC721Receiver(to_).onERC721Received( msg.sender, from_, id_, data_ ) != IERC721Receiver.onERC721Received.selector ) { revert UnsafeRecipient(); } } /// @notice Function for EIP-2612 permits (ERC-20 only). /// @dev Providing type(uint256).max for permit value results in an /// unlimited approval that is not deducted from on transfers. function permit( address owner_, address spender_, uint256 value_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_ ) public virtual { if (deadline_ < block.timestamp) { revert PermitDeadlineExpired(); } // permit cannot be used for ERC-721 token approvals, so ensure // the value does not fall within the valid range of ERC-721 token ids. if (_isValidTokenId(value_)) { revert InvalidApproval(); } if (spender_ == address(0)) { revert InvalidSpender(); } unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner_, spender_, value_, nonces[owner_]++, deadline_ ) ) ) ), v_, r_, s_ ); if (recoveredAddress == address(0) || recoveredAddress != owner_) { revert InvalidSigner(); } allowance[recoveredAddress][spender_] = value_; } emit ERC20Events.Approval(owner_, spender_, value_); } /// @notice Returns domain initial domain separator, or recomputes if chain id is not equal to initial chain id function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator(); } function supportsInterface( bytes4 interfaceId ) public view virtual returns (bool) { return interfaceId == type(IERC404).interfaceId || interfaceId == type(IERC165).interfaceId; } /// @notice Function for self-exemption function setSelfERC721TransferExempt(bool state_) public virtual { _setERC721TransferExempt(msg.sender, state_); } /// @notice Function to check if address is transfer exempt function erc721TransferExempt( address target_ ) public view virtual returns (bool) { return target_ == address(0) || _erc721TransferExempt[target_]; } /// @notice For a token token id to be considered valid, it just needs /// to fall within the range of possible token ids, it does not /// necessarily have to be minted yet. function _isValidTokenId(uint256 id_) internal pure returns (bool) { return id_ > ID_ENCODING_PREFIX && id_ != type(uint256).max; } /// @notice Internal function to compute domain separator for EIP-2612 permits function _computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /// @notice This is the lowest level ERC-20 transfer function, which /// should be used for both normal ERC-20 transfers as well as minting. /// Note that this function allows transfers to and from 0x0. function _transferERC20( address from_, address to_, uint256 value_ ) internal virtual { // Minting is a special case for which we should not check the balance of // the sender, and we should increase the total supply. if (from_ == address(0)) { totalSupply += value_; } else { // Deduct value from sender's balance. balanceOf[from_] -= value_; } // Update the recipient's balance. // Can be unchecked because on mint, adding to totalSupply is checked, and on transfer balance deduction is checked. unchecked { balanceOf[to_] += value_; } emit ERC20Events.Transfer(from_, to_, value_); } /// @notice Consolidated record keeping function for transferring ERC-721s. /// @dev Assign the token to the new owner, and remove from the old owner. /// Note that this function allows transfers to and from 0x0. /// Does not handle ERC-721 exemptions. function _transferERC721( address from_, address to_, uint256 id_ ) internal virtual { // If this is not a mint, handle record keeping for transfer from previous owner. if (from_ != address(0)) { // On transfer of an NFT, any previous approval is reset. delete getApproved[id_]; uint256 updatedId = _owned[from_][_owned[from_].length - 1]; if (updatedId != id_) { uint256 updatedIndex = _getOwnedIndex(id_); // update _owned for sender _owned[from_][updatedIndex] = updatedId; // update index for the moved id _setOwnedIndex(updatedId, updatedIndex); } // pop _owned[from_].pop(); } // Check if this is a burn. if (to_ != address(0)) { // If not a burn, update the owner of the token to the new owner. // Update owner of the token to the new owner. _setOwnerOf(id_, to_); // Push token onto the new owner's stack. _owned[to_].push(id_); // Update index for new owner's stack. _setOwnedIndex(id_, _owned[to_].length - 1); } else { // If this is a burn, reset the owner of the token to 0x0 by deleting the token from _ownedData. delete _ownedData[id_]; } emit ERC721Events.Transfer(from_, to_, id_); } /// @notice Internal function for ERC-20 transfers. Also handles any ERC-721 transfers that may be required. // Handles ERC-721 exemptions. function _transferERC20WithERC721( address from_, address to_, uint256 value_ ) internal virtual returns (bool) { uint256 erc20BalanceOfSenderBefore = erc20BalanceOf(from_); uint256 erc20BalanceOfReceiverBefore = erc20BalanceOf(to_); _transferERC20(from_, to_, value_); // Preload for gas savings on branches bool isFromERC721TransferExempt = erc721TransferExempt(from_); bool isToERC721TransferExempt = erc721TransferExempt(to_); // Skip _withdrawAndStoreERC721 and/or _retrieveOrMintERC721 for ERC-721 transfer exempt addresses // 1) to save gas // 2) because ERC-721 transfer exempt addresses won't always have/need ERC-721s corresponding to their ERC20s. if (isFromERC721TransferExempt && isToERC721TransferExempt) { // Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred. // NOOP. } else if (isFromERC721TransferExempt) { // Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. Contract should not attempt // to transfer ERC-721s from the sender, but the recipient should receive ERC-721s // from the bank/minted for any whole number increase in their balance. // Only cares about whole number increments. uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) - (erc20BalanceOfReceiverBefore / units); for (uint256 i = 0; i < tokensToRetrieveOrMint; ) { _retrieveOrMintERC721(to_); unchecked { ++i; } } } else if (isToERC721TransferExempt) { // Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. Contract should attempt // to withdraw and store ERC-721s from the sender, but the recipient should not // receive ERC-721s from the bank/minted. // Only cares about whole number increments. uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore / units) - (balanceOf[from_] / units); for (uint256 i = 0; i < tokensToWithdrawAndStore; ) { _withdrawAndStoreERC721(from_); unchecked { ++i; } } } else { // Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt. // Strategy: // 1. First deal with the whole tokens. These are easy and will just be transferred. // 2. Look at the fractional part of the value: // a) If it causes the sender to lose a whole token that was represented by an NFT due to a // fractional part being transferred, withdraw and store an additional NFT from the sender. // b) If it causes the receiver to gain a whole new token that should be represented by an NFT // due to receiving a fractional part that completes a whole token, retrieve or mint an NFT to the recevier. // Whole tokens worth of ERC-20s get transferred as ERC-721s without any burning/minting. uint256 nftsToTransfer = value_ / units; for (uint256 i = 0; i < nftsToTransfer; ) { // Pop from sender's ERC-721 stack and transfer them (LIFO) uint256 indexOfLastToken = _owned[from_].length - 1; uint256 tokenId = _owned[from_][indexOfLastToken]; _transferERC721(from_, to_, tokenId); unchecked { ++i; } } // If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional // amount (or vice versa), adjust ERC-721s. // First check if the send causes the sender to lose a whole token that was represented by an ERC-721 // due to a fractional part being transferred. // // Process: // Take the difference between the whole number of tokens before and after the transfer for the sender. // If that difference is greater than the number of ERC-721s transferred (whole units), then there was // an additional ERC-721 lost due to the fractional portion of the transfer. // If this is a self-send and the before and after balances are equal (not always the case but often), // then no ERC-721s will be lost here. if ( erc20BalanceOfSenderBefore / units - erc20BalanceOf(from_) / units > nftsToTransfer ) { _withdrawAndStoreERC721(from_); } // Then, check if the transfer causes the receiver to gain a whole new token which requires gaining // an additional ERC-721. // // Process: // Take the difference between the whole number of tokens before and after the transfer for the recipient. // If that difference is greater than the number of ERC-721s transferred (whole units), then there was // an additional ERC-721 gained due to the fractional portion of the transfer. // Again, for self-sends where the before and after balances are equal, no ERC-721s will be gained here. if ( erc20BalanceOf(to_) / units - erc20BalanceOfReceiverBefore / units > nftsToTransfer ) { _retrieveOrMintERC721(to_); } } return true; } /// @notice Internal function for ERC20 minting /// @dev This function will allow minting of new ERC20s. /// If mintCorrespondingERC721s_ is true, and the recipient is not ERC-721 exempt, it will /// also mint the corresponding ERC721s. /// Handles ERC-721 exemptions. function _mintERC20(address to_, uint256 value_) internal virtual { /// You cannot mint to the zero address (you can't mint and immediately burn in the same transfer). if (to_ == address(0)) { revert InvalidRecipient(); } if (totalSupply + value_ > ID_ENCODING_PREFIX) { revert MintLimitReached(); } _transferERC20WithERC721(address(0), to_, value_); } /// @notice Internal function for ERC-721 minting and retrieval from the bank. /// @dev This function will allow minting of new ERC-721s up to the total fractional supply. It will /// first try to pull from the bank, and if the bank is empty, it will mint a new token. /// Does not handle ERC-721 exemptions. function _retrieveOrMintERC721(address to_) internal virtual { if (to_ == address(0)) { revert InvalidRecipient(); } uint256 id; if (!_storedERC721Ids.empty()) { // If there are any tokens in the bank, use those first. // Pop off the end of the queue (FIFO). id = _storedERC721Ids.popBack(); } else { // Otherwise, mint a new token, should not be able to go over the total fractional supply. ++minted; // Reserve max uint256 for approvals if (minted == type(uint256).max) { revert MintLimitReached(); } id = ID_ENCODING_PREFIX + minted; } address erc721Owner = _getOwnerOf(id); // The token should not already belong to anyone besides 0x0 or this contract. // If it does, something is wrong, as this should never happen. if (erc721Owner != address(0)) { revert AlreadyExists(); } // Transfer the token to the recipient, either transferring from the contract's bank or minting. // Does not handle ERC-721 exemptions. _transferERC721(erc721Owner, to_, id); } /// @notice Internal function for ERC-721 deposits to bank (this contract). /// @dev This function will allow depositing of ERC-721s to the bank, which can be retrieved by future minters. // Does not handle ERC-721 exemptions. function _withdrawAndStoreERC721(address from_) internal virtual { if (from_ == address(0)) { revert InvalidSender(); } // Retrieve the latest token added to the owner's stack (LIFO). uint256 id = _owned[from_][_owned[from_].length - 1]; // Transfer to 0x0. // Does not handle ERC-721 exemptions. _transferERC721(from_, address(0), id); // Record the token in the contract's bank queue. _storedERC721Ids.pushFront(id); } /// @notice Initialization function to set pairs / etc, saving gas by avoiding mint / burn on unnecessary targets function _setERC721TransferExempt( address target_, bool state_ ) internal virtual { if (target_ == address(0)) { revert InvalidExemption(); } // Adjust the ERC721 balances of the target to respect exemption rules. // Despite this logic, it is still recommended practice to exempt prior to the target // having an active balance. if (state_) { _clearERC721Balance(target_); } else { _reinstateERC721Balance(target_); } _erc721TransferExempt[target_] = state_; } /// @notice Function to reinstate balance on exemption removal function _reinstateERC721Balance(address target_) private { uint256 expectedERC721Balance = erc20BalanceOf(target_) / units; uint256 actualERC721Balance = erc721BalanceOf(target_); for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) { // Transfer ERC721 balance in from pool _retrieveOrMintERC721(target_); unchecked { ++i; } } } /// @notice Function to clear balance on exemption inclusion function _clearERC721Balance(address target_) private { uint256 erc721Balance = erc721BalanceOf(target_); for (uint256 i = 0; i < erc721Balance; ) { // Transfer out ERC721 balance _withdrawAndStoreERC721(target_); unchecked { ++i; } } } function _getOwnerOf( uint256 id_ ) internal view virtual returns (address ownerOf_) { uint256 data = _ownedData[id_]; assembly { ownerOf_ := and(data, _BITMASK_ADDRESS) } } function _setOwnerOf(uint256 id_, address owner_) internal virtual { uint256 data = _ownedData[id_]; assembly { data := add( and(data, _BITMASK_OWNED_INDEX), and(owner_, _BITMASK_ADDRESS) ) } _ownedData[id_] = data; } function _getOwnedIndex( uint256 id_ ) internal view virtual returns (uint256 ownedIndex_) { uint256 data = _ownedData[id_]; assembly { ownedIndex_ := shr(160, data) } } function _setOwnedIndex(uint256 id_, uint256 index_) internal virtual { uint256 data = _ownedData[id_]; if (index_ > _BITMASK_OWNED_INDEX >> 160) { revert OwnedIndexOverflow(); } assembly { data := add( and(data, _BITMASK_ADDRESS), and(shl(160, index_), _BITMASK_OWNED_INDEX) ) } _ownedData[id_] = data; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; interface IERC404 is IERC165 { error NotFound(); error InvalidTokenId(); error AlreadyExists(); error InvalidRecipient(); error InvalidSender(); error InvalidSpender(); error InvalidOperator(); error UnsafeRecipient(); error RecipientIsERC721TransferExempt(); error Unauthorized(); error InsufficientAllowance(); error DecimalsTooLow(); error PermitDeadlineExpired(); error InvalidSigner(); error InvalidApproval(); error OwnedIndexOverflow(); error MintLimitReached(); error InvalidExemption(); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function erc20TotalSupply() external view returns (uint256); function erc721TotalSupply() external view returns (uint256); function balanceOf(address owner_) external view returns (uint256); function erc721BalanceOf(address owner_) external view returns (uint256); function erc20BalanceOf(address owner_) external view returns (uint256); function erc721TransferExempt(address account_) external view returns (bool); function isApprovedForAll( address owner_, address operator_ ) external view returns (bool); function allowance( address owner_, address spender_ ) external view returns (uint256); function owned(address owner_) external view returns (uint256[] memory); function ownerOf(uint256 id_) external view returns (address erc721Owner); function tokenURI(uint256 id_) external view returns (string memory); function approve( address spender_, uint256 valueOrId_ ) external returns (bool); function erc20Approve( address spender_, uint256 value_ ) external returns (bool); function erc721Approve(address spender_, uint256 id_) external; function setApprovalForAll(address operator_, bool approved_) external; function transferFrom( address from_, address to_, uint256 valueOrId_ ) external returns (bool); function erc20TransferFrom( address from_, address to_, uint256 value_ ) external returns (bool); function erc721TransferFrom(address from_, address to_, uint256 id_) external; function transfer(address to_, uint256 amount_) external returns (bool); function getERC721QueueLength() external view returns (uint256); function getERC721TokensInQueue( uint256 start_, uint256 count_ ) external view returns (uint256[] memory); function setSelfERC721TransferExempt(bool state_) external; function safeTransferFrom(address from_, address to_, uint256 id_) external; function safeTransferFrom( address from_, address to_, uint256 id_, bytes calldata data_ ) external; function DOMAIN_SEPARATOR() external view returns (bytes32); function permit( address owner_, address spender_, uint256 value_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_ ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) // Modified by Pandora Labs to support native uint256 operations pragma solidity ^0.8.20; /** * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that * the existing queue contents are left in storage. * * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory. * * ```solidity * DoubleEndedQueue.Uint256Deque queue; * ``` */ library DoubleEndedQueue { /** * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. */ error QueueEmpty(); /** * @dev A push operation couldn't be completed due to the queue being full. */ error QueueFull(); /** * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. */ error QueueOutOfBounds(); /** * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. * * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and * lead to unexpected behavior. * * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. */ struct Uint256Deque { uint128 _begin; uint128 _end; mapping(uint128 index => uint256) _data; } /** * @dev Inserts an item at the end of the queue. * * Reverts with {QueueFull} if the queue is full. */ function pushBack(Uint256Deque storage deque, uint256 value) internal { unchecked { uint128 backIndex = deque._end; if (backIndex + 1 == deque._begin) revert QueueFull(); deque._data[backIndex] = value; deque._end = backIndex + 1; } } /** * @dev Removes the item at the end of the queue and returns it. * * Reverts with {QueueEmpty} if the queue is empty. */ function popBack( Uint256Deque storage deque ) internal returns (uint256 value) { unchecked { uint128 backIndex = deque._end; if (backIndex == deque._begin) revert QueueEmpty(); --backIndex; value = deque._data[backIndex]; delete deque._data[backIndex]; deque._end = backIndex; } } /** * @dev Inserts an item at the beginning of the queue. * * Reverts with {QueueFull} if the queue is full. */ function pushFront(Uint256Deque storage deque, uint256 value) internal { unchecked { uint128 frontIndex = deque._begin - 1; if (frontIndex == deque._end) revert QueueFull(); deque._data[frontIndex] = value; deque._begin = frontIndex; } } /** * @dev Removes the item at the beginning of the queue and returns it. * * Reverts with `QueueEmpty` if the queue is empty. */ function popFront( Uint256Deque storage deque ) internal returns (uint256 value) { unchecked { uint128 frontIndex = deque._begin; if (frontIndex == deque._end) revert QueueEmpty(); value = deque._data[frontIndex]; delete deque._data[frontIndex]; deque._begin = frontIndex + 1; } } /** * @dev Returns the item at the beginning of the queue. * * Reverts with `QueueEmpty` if the queue is empty. */ function front( Uint256Deque storage deque ) internal view returns (uint256 value) { if (empty(deque)) revert QueueEmpty(); return deque._data[deque._begin]; } /** * @dev Returns the item at the end of the queue. * * Reverts with `QueueEmpty` if the queue is empty. */ function back( Uint256Deque storage deque ) internal view returns (uint256 value) { if (empty(deque)) revert QueueEmpty(); unchecked { return deque._data[deque._end - 1]; } } /** * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at * `length(deque) - 1`. * * Reverts with `QueueOutOfBounds` if the index is out of bounds. */ function at( Uint256Deque storage deque, uint256 index ) internal view returns (uint256 value) { if (index >= length(deque)) revert QueueOutOfBounds(); // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 unchecked { return deque._data[deque._begin + uint128(index)]; } } /** * @dev Resets the queue back to being empty. * * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses * out on potential gas refunds. */ function clear(Uint256Deque storage deque) internal { deque._begin = 0; deque._end = 0; } /** * @dev Returns the number of items in the queue. */ function length(Uint256Deque storage deque) internal view returns (uint256) { unchecked { return uint256(deque._end - deque._begin); } } /** * @dev Returns true if the queue is empty. */ function empty(Uint256Deque storage deque) internal view returns (bool) { return deque._end == deque._begin; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library ERC20Events { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 amount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library ERC721Events { event ApprovalForAll( address indexed owner, address indexed operator, bool approved ); event Approval( address indexed owner, address indexed spender, uint256 indexed id ); event Transfer(address indexed from, address indexed to, uint256 indexed id); }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.9; struct PoolData { address poolAddress; address quoteToken; uint24 fee; uint256 positionId; uint160 sqrtPriceX96; int24 tickLower; int24 tickUpper; uint128 liquidity; }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.9; struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.9; struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. // EDIT for 0.8 compatibility: // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256 uint256 twos = denominator & (~denominator + 1); // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title PoolAddress modified to have <0.8 POOL_INIT_CODE_HASH library PoolAddress { bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; /// @notice The identifying key of the pool struct PoolKey { address token0; address token1; uint24 fee; } /// @notice Returns PoolKey: the ordered tokens with the matched fee levels /// @param tokenA The first token of a pool, unsorted /// @param tokenB The second token of a pool, unsorted /// @param fee The fee level of the pool /// @return Poolkey The pool details with ordered token0 and token1 assignments function getPoolKey( address tokenA, address tokenB, uint24 fee ) internal pure returns (PoolKey memory) { if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); return PoolKey({token0: tokenA, token1: tokenB, fee: fee}); } /// @notice Deterministically computes the pool address given the factory and PoolKey /// @param factory The Uniswap V3 factory contract address /// @param key The PoolKey /// @return pool The contract address of the V3 pool function computeAddress( address factory, PoolKey memory key ) internal pure returns (address pool) { require(key.token0 < key.token1); pool = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256( abi.encode(key.token0, key.token1, key.fee) ), POOL_INIT_CODE_HASH ) ) ) ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick( int24 tick ) internal pure returns (uint160 sqrtPriceX96) { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); // EDIT: 0.8 compatibility require(absTick <= uint256(int256(MAX_TICK)), "T"); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160( (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) ); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio( uint160 sqrtPriceX96 ) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require( sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, "R" ); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24( (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 ); int24 tickHi = int24( (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 ); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"address","name":"initialMintRecipient_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DecimalsTooLow","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidApproval","type":"error"},{"inputs":[],"name":"InvalidExemption","type":"error"},{"inputs":[],"name":"InvalidOperator","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"MintLimitReached","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnedIndexOverflow","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","type":"error"},{"inputs":[],"name":"RecipientIsERC721TransferExempt","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"uri","type":"string"}],"name":"BaseUriUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC20Burn","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"indexed":false,"internalType":"struct PoolData","name":"poolData","type":"tuple"}],"name":"Initialize","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":"value","type":"uint256"}],"name":"ReceiveTax","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"RefundETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ID_ENCODING_PREFIX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPoolData","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTick","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc20BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20TransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc721BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"erc721TransferExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC721QueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start_","type":"uint256"},{"internalType":"uint256","name":"count_","type":"uint256"}],"name":"getERC721TokensInQueue","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialMintRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"liquifyAndCollect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"erc721Owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"positionManagerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"},{"internalType":"bool","name":"state_","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setMarketLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setSelfERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"tickThreshold_","type":"int24"}],"name":"setTickThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"swapAndLiquify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxPercent","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tickThreshold","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"units","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101006040526010805460ff191690556127106011556012805462ffffff1916620138801790553480156200003357600080fd5b506040516200677b3803806200677b833981016040819052620000569162000d26565b81816103e8620138806040518060400160405280600681526020016557484f33333360d01b8152506040518060400160405280600381526020016257484f60e81b81525060126064838383838b60006001600160a01b0316816001600160a01b031603620000de57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000e9816200021d565b506003620000f8858262000e02565b50600462000107848262000e02565b5060128260ff1610156200012e576040516398790fd560e01b815260040160405180910390fd5b60ff8083166080819052908216906200014990600a62000fe1565b62000155919062000ff9565b60a0524660c052620001666200026d565b60e052505050601187905550601280546001600160a01b0389166301000000026001600160b81b031990911662ffffff881617179055620001a987600162000309565b620001c68760a051601154620001c0919062000ff9565b6200037f565b50505050505050506040518060400160405280601a81526020017f68747470733a2f2f77686f3333332e7774662f6173736574732f000000000000815250601d908162000214919062000e02565b50505062001128565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6003604051620002a1919062001013565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b038216620003315760405163a41e3d3f60e01b815260040160405180910390fd5b801562000349576200034382620003fa565b62000354565b620003548262000432565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6001600160a01b038216620003a757604051634e46966960e11b815260040160405180910390fd5b6ec097ce7bc90715b34b9f100000000081600554620003c7919062001091565b1115620003e75760405163303b682f60e01b815260040160405180910390fd5b620003f560008383620004bb565b505050565b6001600160a01b0381166000908152600c6020526040812054905b81811015620003f55762000429836200076a565b60010162000415565b60a05160009062000458836001600160a01b031660009081526007602052604090205490565b620004649190620010a7565b9050600062000488836001600160a01b03166000908152600c602052604090205490565b905060005b620004998284620010ca565b811015620004b557620004ac84620007ff565b6001016200048d565b50505050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190620004ee86868662000900565b6000620004fb87620009b2565b905060006200050a87620009b2565b9050818015620005175750805b6200075c5781156200059357600060a05184620005359190620010a7565b60a0516001600160a01b038a166000908152600760205260409020546200055d9190620010a7565b620005699190620010ca565b905060005b818110156200058b576200058289620007ff565b6001016200056e565b50506200075c565b8015620006005760a0516001600160a01b0389166000908152600760205260408120549091620005c391620010a7565b60a051620005d29087620010a7565b620005de9190620010ca565b905060005b818110156200058b57620005f78a6200076a565b600101620005e3565b600060a05187620006129190620010a7565b905060005b81811015620006a4576001600160a01b038a166000908152600c60205260408120546200064790600190620010ca565b6001600160a01b038c166000908152600c602052604081208054929350909183908110620006795762000679620010e0565b90600052602060002001549050620006998c8c83620009e960201b60201c565b505060010162000617565b5060a0518190620006ca8b6001600160a01b031660009081526007602052604090205490565b620006d69190620010a7565b60a051620006e59088620010a7565b620006f19190620010ca565b1115620007035762000703896200076a565b8060a05185620007149190620010a7565b60a0516001600160a01b038b166000908152600760205260409020546200073c9190620010a7565b620007489190620010ca565b11156200075a576200075a88620007ff565b505b506001979650505050505050565b6001600160a01b0381166200079257604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604081208054620007ba90600190620010ca565b81548110620007cd57620007cd620010e0565b90600052602060002001549050620007ee82600083620009e960201b60201c565b620007fb60018262000bc5565b5050565b6001600160a01b0381166200082757604051634e46966960e11b815260040160405180910390fd5b600062000848600154600160801b81046001600160801b0390811691161490565b620008615762000859600162000c30565b9050620008bb565b6006600081546200087290620010f6565b909155506006546001016200089a5760405163303b682f60e01b815260040160405180910390fd5b600654620008b8906ec097ce7bc90715b34b9f100000000062001091565b90505b6000818152600b60205260409020546001600160a01b03168015620008f35760405163119b4fd360e11b815260040160405180910390fd5b620003f5818484620009e9565b6001600160a01b0383166200092f57806005600082825462000923919062001091565b909155506200095f9050565b6001600160a01b0383166000908152600760205260408120805483929062000959908490620010ca565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516906000805160206200675b83398151915290620009a59085815260200190565b60405180910390a3505050565b60006001600160a01b0382161580620009e357506001600160a01b0382166000908152600d602052604090205460ff165b92915050565b6001600160a01b0383161562000b0357600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c9091528120805462000a3b90600190620010ca565b8154811062000a4e5762000a4e620010e0565b9060005260206000200154905081811462000ac1576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c60205260409020805491925083918390811062000aa75762000aa7620010e0565b60009182526020909120015562000abf828262000ca1565b505b6001600160a01b0384166000908152600c6020526040902080548062000aeb5762000aeb62001112565b60019003818190600052602060002001600090559055505b6001600160a01b0382161562000b80576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c8352908320805460018181018355828652938520018590559252905462000b7a91839162000b749190620010ca565b62000ca1565b62000b90565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03166000805160206200675b83398151915260405160405180910390a4505050565b81546001600160801b038082166000190191600160801b900481169082160362000c0257604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b80546000906001600160801b03600160801b820481169116810362000c68576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b6000828152600b60205260409020546001600160601b0382111562000cd957604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b80516001600160a01b038116811462000d2157600080fd5b919050565b6000806040838503121562000d3a57600080fd5b62000d458362000d09565b915062000d556020840162000d09565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168062000d8957607f821691505b60208210810362000daa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003f557600081815260208120601f850160051c8101602086101562000dd95750805b601f850160051c820191505b8181101562000dfa5782815560010162000de5565b505050505050565b81516001600160401b0381111562000e1e5762000e1e62000d5e565b62000e368162000e2f845462000d74565b8462000db0565b602080601f83116001811462000e6e576000841562000e555750858301515b600019600386901b1c1916600185901b17855562000dfa565b600085815260208120601f198616915b8281101562000e9f5788860151825594840194600190910190840162000e7e565b508582101562000ebe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111562000f2557816000190482111562000f095762000f0962000ece565b8085161562000f1757918102915b93841c939080029062000ee9565b509250929050565b60008262000f3e57506001620009e3565b8162000f4d57506000620009e3565b816001811462000f66576002811462000f715762000f91565b6001915050620009e3565b60ff84111562000f855762000f8562000ece565b50506001821b620009e3565b5060208310610133831016604e8410600b841016171562000fb6575081810a620009e3565b62000fc2838362000ee4565b806000190482111562000fd95762000fd962000ece565b029392505050565b600062000ff260ff84168362000f2d565b9392505050565b8082028115828204841417620009e357620009e362000ece565b6000808354620010238162000d74565b600182811680156200103e5760018114620010545762001085565b60ff198416875282151583028701945062001085565b8760005260208060002060005b858110156200107c5781548a82015290840190820162001061565b50505082870194505b50929695505050505050565b80820180821115620009e357620009e362000ece565b600082620010c557634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620009e357620009e362000ece565b634e487b7160e01b600052603260045260246000fd5b6000600182016200110b576200110b62000ece565b5060010190565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e0516155ac620011af6000396000610fd901526000610fa901526000818161099d01528181611d6001528181613ae401528181613b2801528181613ba101528181613bcb01528181613c1f01528181613ccb01528181613d1801528181613d5c01528181613d8301526140410152600061063001526155ac6000f3fe6080604052600436106103a55760003560e01c80637a8a1113116101e7578063b88d4fde1161010d578063dd62ed3e116100a0578063e995016c1161006f578063e995016c14610c2b578063f2fde38b14610c4b578063f780bc1a14610c6b578063fe85b42b14610c8b57600080fd5b8063dd62ed3e14610b78578063dd63769914610bb0578063dfabc03314610bd0578063e985e9c514610bf057600080fd5b8063c87b56dd116100dc578063c87b56dd14610afe578063cd4bb50a14610b1e578063d505accf14610b38578063d96ca0b914610b5857600080fd5b8063b88d4fde14610a82578063c5ab3ba614610aa2578063c6e672b914610ab7578063c77cd5ac14610ad757600080fd5b806390fcdb3611610185578063a9059cbb11610154578063a9059cbb146109df578063ab01b469146109ff578063b1ab931714610a1f578063b3f9ea3414610a4c57600080fd5b806390fcdb361461095657806395d89b4114610976578063976a84351461098b578063a22cb465146109bf57600080fd5b8063853828b6116101c1578063853828b6146108ee57806389fb4c66146109035780638a696e50146109185780638da5cb5b1461093857600080fd5b80637a8a1113146108995780637ecebe00146108b95780638129fc1c146108e657600080fd5b806323b872dd116102cc5780634f02c4201161026a5780636e8f624b116102395780636e8f624b1461080457806370a0823114610827578063715018a6146108545780637541f41c1461086957600080fd5b80634f02c420146106f35780635eed923e146107095780636352211e146107cf5780636c0360eb146107ef57600080fd5b806342842e0e116102a657806342842e0e146106795780634524c4ab1461069957806349fa7fd8146106b35780634d966072146106d357600080fd5b806323b872dd146105fe578063313ce5671461061e5780633644e5151461066457600080fd5b8063095ea7b311610344578063158ef93e11610313578063158ef93e14610592578063173865ad146105b257806318160ddd146105d25780631bc392ae146105e857600080fd5b8063095ea7b31461050d57806309674eb01461052d57806309f0ef651461054257806313e7c9d81461056257600080fd5b8063045b7dca11610380578063045b7dca14610453578063065e53601461046957806306fdde031461049d578063081812fc146104bf57600080fd5b8062a5a777146103ba57806301ffc9a7146103da57806302519da31461040f57600080fd5b366103b5576103b334610ca1565b005b600080fd5b3480156103c657600080fd5b506103b36103d536600461474d565b610d3e565b3480156103e657600080fd5b506103fa6103f5366004614780565b610d59565b60405190151581526020015b60405180910390f35b34801561041b57600080fd5b5061044561042a3660046147b2565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610406565b34801561045f57600080fd5b5061044560115481565b34801561047557600080fd5b5060185461048a906301000000900460020b81565b60405160029190910b8152602001610406565b3480156104a957600080fd5b506104b2610d90565b604051610406919061481f565b3480156104cb57600080fd5b506104f56104da366004614832565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610406565b34801561051957600080fd5b506103fa61052836600461484b565b610e1e565b34801561053957600080fd5b50610445610e57565b34801561054e57600080fd5b506103fa61055d3660046147b2565b610e81565b34801561056e57600080fd5b506103fa61057d3660046147b2565b600f6020526000908152604090205460ff1681565b34801561059e57600080fd5b506013546001600160a01b031615156103fa565b3480156105be57600080fd5b506103b36105cd366004614832565b610eb3565b3480156105de57600080fd5b5061044560055481565b3480156105f457600080fd5b5061044560195481565b34801561060a57600080fd5b506103fa610619366004614877565b610f68565b34801561062a57600080fd5b506106527f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610406565b34801561067057600080fd5b50610445610fa5565b34801561068557600080fd5b506103b3610694366004614877565b610ffb565b3480156106a557600080fd5b5060185461048a9060020b81565b3480156106bf57600080fd5b506103b36106ce3660046148cd565b61101b565b3480156106df57600080fd5b506103fa6106ee36600461484b565b6110b3565b3480156106ff57600080fd5b5061044560065481565b34801561071557600080fd5b5060135460145460155460165460175461076e946001600160a01b03908116948082169462ffffff600160a01b928390041694909392811692918104600290810b92600160b81b909204900b906001600160801b031688565b604080516001600160a01b03998a168152978916602089015262ffffff90961695870195909552606086019390935294166080840152600293840b60a084015290920b60c08201526001600160801b0390911660e082015261010001610406565b3480156107db57600080fd5b506104f56107ea366004614832565b611140565b3480156107fb57600080fd5b506104b26111aa565b34801561081057600080fd5b506104456ec097ce7bc90715b34b9f100000000081565b34801561083357600080fd5b506104456108423660046147b2565b60076020526000908152604090205481565b34801561086057600080fd5b506103b36111b7565b34801561087557600080fd5b506012546108859062ffffff1681565b60405162ffffff9091168152602001610406565b3480156108a557600080fd5b50601b546104f5906001600160a01b031681565b3480156108c557600080fd5b506104456108d43660046147b2565b600e6020526000908152604090205481565b6103b36111cb565b3480156108fa57600080fd5b506103b36112f4565b34801561090f57600080fd5b50600554610445565b34801561092457600080fd5b506103b361093336600461474d565b61146e565b34801561094457600080fd5b506000546001600160a01b03166104f5565b34801561096257600080fd5b50601c546104f5906001600160a01b031681565b34801561098257600080fd5b506104b2611486565b34801561099757600080fd5b506104457f000000000000000000000000000000000000000000000000000000000000000081565b3480156109cb57600080fd5b506103b36109da3660046148ea565b611493565b3480156109eb57600080fd5b506103fa6109fa36600461484b565b611526565b348015610a0b57600080fd5b506103b3610a1a3660046148ea565b61155a565b348015610a2b57600080fd5b50610a3f610a3a3660046147b2565b61158d565b6040516104069190614923565b348015610a5857600080fd5b50610445610a673660046147b2565b6001600160a01b03166000908152600c602052604090205490565b348015610a8e57600080fd5b506103b3610a9d3660046149ae565b6115f9565b348015610aae57600080fd5b50600654610445565b348015610ac357600080fd5b506103b3610ad23660046148ea565b6116e7565b348015610ae357600080fd5b506012546104f590630100000090046001600160a01b031681565b348015610b0a57600080fd5b506104b2610b19366004614832565b6116f9565b348015610b2a57600080fd5b506010546103fa9060ff1681565b348015610b4457600080fd5b506103b3610b53366004614a81565b6118a2565b348015610b6457600080fd5b506103fa610b73366004614877565b611ae5565b348015610b8457600080fd5b50610445610b93366004614af2565b600860209081526000928352604080842090915290825290205481565b348015610bbc57600080fd5b506103b3610bcb366004614877565b611ba5565b348015610bdc57600080fd5b506103b3610beb36600461484b565b611d8f565b348015610bfc57600080fd5b506103fa610c0b366004614af2565b600a60209081526000928352604080842090915290825290205460ff1681565b348015610c3757600080fd5b506103b3610c46366004614b2f565b611e54565b348015610c5757600080fd5b506103b3610c663660046147b2565b611e76565b348015610c7757600080fd5b50610a3f610c86366004614b4c565b611eb4565b348015610c9757600080fd5b50610445601a5481565b60408051600481526024810182526020810180516001600160e01b0316630d0e30db60e41b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2918591610cf29190614b8a565b60006040518083038185875af1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b5090949350505050565b610d46611f51565b6010805460ff1916911515919091179055565b60006001600160e01b0319821663caf91ff560e01b1480610d8a57506001600160e01b031982166301ffc9a760e01b145b92915050565b60038054610d9d90614ba6565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc990614ba6565b8015610e165780601f10610deb57610100808354040283529160200191610e16565b820191906000526020600020905b815481529060010190602001808311610df957829003601f168201915b505050505081565b6000610e2982611f7e565b15610e3d57610e388383611d8f565b610e4e565b610e4783836110b3565b9050610d8a565b50600192915050565b6000610e7c6001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b0382161580610d8a5750506001600160a01b03166000908152600d602052604090205460ff1690565b610ebb611f51565b30600090815260076020526040902054600390610ed9906002614bf0565b610ee39190614c1d565b811115610f2d5760405162461bcd60e51b8152602060048201526013602482015272616d6f756e7420697320746f6f206c6172676560681b60448201526064015b60405180910390fd5b6000610f3882611fa2565b90508015610f645730600090815260076020526040902054610f6490610f5f600284614c1d565b611fbe565b5050565b6000610f7382611f7e565b15610f8857610f83848484611ba5565b610f9a565b610f93848484611ae5565b9050610f9e565b5060015b9392505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610fd657610e7c61204e565b507f000000000000000000000000000000000000000000000000000000000000000090565b611016838383604051806020016040528060008152506115f9565b505050565b611023611f51565b6017546001600160801b03908116908216111561107b5760405162461bcd60e51b81526020600482015260166024820152756c697175696469747920697320746f6f206c6172676560501b6044820152606401610f24565b6001600160801b0381161561109357611093816120e8565b6015546012546110169190630100000090046001600160a01b0316612159565b60006001600160a01b0383166110dc57604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661116182611f7e565b61117e576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b0381166111a55760405163c5723b5160e01b815260040160405180910390fd5b919050565b601d8054610d9d90614ba6565b6111bf611f51565b6111c96000612274565b565b6111d3611f51565b73c36442b4a4522e871399cd717abdd847ab11fe8873e592427a0aece92de3edee1f18e0157c05861564341561120e5761120c34610ca1565b505b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061123e576c39bc2ab9629fb800000000000061124c565b6b046f1de7bc353a00000000005b6cffffffffffffffffffffffffff1690506000611268826122c4565b905060006112746123b1565b9050818110156112bf5760405162461bcd60e51b81526020600482015260166024820152757765746820616d6f756e7420697320746f6f206c6f7760501b6044820152606401610f24565b6112e583610bb873c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285603c8a8a61247a565b6112ed612952565b5050505050565b6112fc611f51565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161135b91614b8a565b600060405180830381855afa9150503d8060008114611396576040519150601f19603f3d011682016040523d82523d6000602084013e61139b565b606091505b5091509150816113a9575050565b6000818060200190518101906113bf9190614c31565b60408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b179052905191925060009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161142391614b8a565b6000604051808303816000865af19150503d8060008114611460576040519150601f19603f3d011682016040523d82523d6000602084013e611465565b606091505b50505050505050565b6040516282b42960e81b815260040160405180910390fd5b60048054610d9d90614ba6565b6001600160a01b0382166114ba5760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b03831661154f57604051634e46966960e11b815260040160405180910390fd5b610f9e3384846129fe565b611562611f51565b6001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6001600160a01b0381166000908152600c60209081526040918290208054835181840281018401909452808452606093928301828280156115ed57602002820191906000526020600020905b8154815260200190600101908083116115d9575b50505050509050919050565b61160282611f7e565b61161f576040516307ed98ed60e31b815260040160405180910390fd5b61162a848484610f68565b506001600160a01b0383163b158015906116c35750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611673903390899088908890600401614c4a565b6020604051808303816000875af1158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190614c87565b6001600160e01b03191614155b156116e157604051633da6393160e01b815260040160405180910390fd5b50505050565b6116ef611f51565b610f648282612b06565b606060008260405160200161171091815260200190565b6040516020818303038152906040528051906020012060f81c905060608060408360ff161161177c5760405180604001604052806005815260200164302e706e6760d81b81525091506040518060400160405280600381526020016214995960ea1b815250905061185d565b60808360ff16116117cb5760405180604001604052806005815260200164312e706e6760d81b815250915060405180604001604052806004815260200163426c756560e01b815250905061185d565b60c08360ff161161181b5760405180604001604052806005815260200164322e706e6760d81b81525091506040518060400160405280600581526020016423b932b2b760d91b815250905061185d565b60405180604001604052806005815260200164332e706e6760d81b815250915060405180604001604052806006815260200165507572706c6560d01b81525090505b61186685612b75565b611871601154612b75565b601d8484604051602001611889959493929190614d40565b6040516020818303038152906040529350505050919050565b428410156118c3576040516305787bdf60e01b815260040160405180910390fd5b6118cc85611f7e565b156118ea576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b03861661191157604051635461585f60e01b815260040160405180910390fd5b6000600161191d610fa5565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611a29573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580611a5e5750876001600160a01b0316816001600160a01b031614155b15611a7c57604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416611b0e57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316611b3557604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114611b9157611b6c8382614ef0565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b611b9c8585856129fe565b95945050505050565b6001600160a01b038316611bcc57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216611bf357604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614611c2c576040516282b42960e81b815260040160405180910390fd5b60105460ff1615611cb5576000546001600160a01b0316331480611c615750601254630100000090046001600160a01b031633145b80611c7b5750336000908152600f602052604090205460ff165b611cb55760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08185b1b1bddd95960aa1b6044820152606401610f24565b336001600160a01b03841614801590611cf257506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015611d1557506000818152600960205260409020546001600160a01b03163314155b15611d32576040516282b42960e81b815260040160405180910390fd5b611d3b82610e81565b15611d5957604051635ce7539760e01b815260040160405180910390fd5b611d8483837f0000000000000000000000000000000000000000000000000000000000000000612c08565b611016838383612cc4565b6000818152600b60205260409020546001600160a01b0316338114801590611ddb57506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b15611df8576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b611e5c611f51565b6018805462ffffff191662ffffff92909216919091179055565b611e7e611f51565b6001600160a01b038116611ea857604051631e4fbdf760e01b815260006004820152602401610f24565b611eb181612274565b50565b606060008267ffffffffffffffff811115611ed157611ed1614967565b604051908082528060200260200182016040528015611efa578160200160208202803683370190505b509050835b611f098486614f03565b811015611f4957611f1b600182612e9c565b82611f268784614ef0565b81518110611f3657611f36614f16565b6020908102919091010152600101611eff565b509392505050565b6000546001600160a01b031633146111c95760405163118cdaa760e01b8152336004820152602401610f24565b60006ec097ce7bc90715b34b9f100000000082118015610d8a575050600019141590565b601454600090610d8a9030906001600160a01b03168185612f07565b60145430906001600160a01b0316838382841115611fdb57919291905b6000611fed6013600201548484613061565b909450925090506001600160801b0381161561146557601780548291906000906120219084906001600160801b0316614f2c565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516120809190614f53565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000806120fa60136002015484613187565b91509150600082118061210d5750600081115b1561101657601780548491906000906121309084906001600160801b0316614f5f565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b604080516080810182528381526001600160a01b03838116602083019081526001600160801b0383850181815260608501828152601b549651602481018a905293518516604485015290518216606484015251166084820152600093849392849283929091169063fc6f78659060a4015b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516122039190614b8a565b6000604051808303816000865af19150503d8060008114612240576040519150601f19603f3d011682016040523d82523d6000602084013e612245565b606091505b5091509150811561226a57808060200190518101906122649190614f7f565b90955093505b5050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b306000908152600760205260408120546001600160801b036001600160a01b038416116123485760006123006001600160a01b03851680614bf0565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc230106123315761232c600160c01b838361320a565b612340565b6123408183600160c01b61320a565b9250506123ab565b60006123676001600160a01b038516806801000000000000000061320a565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061239857612393600160801b838361320a565b6123a7565b6123a78183600160801b61320a565b9250505b50919050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17905290516000918291829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916124139190614b8a565b600060405180830381855afa9150503d806000811461244e576040519150601f19603f3d011682016040523d82523d6000602084013e612453565b606091505b5091509150811561247557808060200190518101906124729190614c31565b92505b505090565b612482611f51565b6013546001600160a01b0316156124d15760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610f24565b601b80546001600160a01b03199081166001600160a01b0385811691909117909255601c80548216848416179055601480548884166001600160b81b03199091168117600160a01b62ffffff8c16021790915560168054909216928a16929092179055306000818152600760205260409020549091879190879084111561255757919291905b612563846000196132b8565b50612570836000196132b8565b50600061257f85858d8f61346e565b6018805462ffffff90931663010000000265ffffff0000001990931692909217909155601380546001600160a01b039093166001600160a01b0319909316831790559150158015906125d557508060020b600014155b61261a5760405162461bcd60e51b81526020600482015260166024820152751a5b9a5d1a585b1a5e99481c1bdbdb0819985a5b195960521b6044820152606401610f24565b6018805462ffffff198116630100000090910462ffffff161790556014546001600160a01b031630101561272357601854819061265b90829060020b614fa3565b6126659190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b19909216919091179055601854600060029190910b12156126d857601680548291906014906126b8908490600160a01b900460020b614ffd565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b80806126e7620d89e719615022565b6126f19190614fa3565b6126fb9190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b199092169190911790556127f0565b601854819061273690829060020b614fa3565b6127409190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b19909216919091179055601854600060029190910b13156127b35760168054829190601790612793908490600160b81b900460020b615044565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b806127c281620d89e719614fa3565b6127cc9190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b199092169190911790555b61ffff88161561286457601354600090612813906001600160a01b03168a6136eb565b9050806128625760405162461bcd60e51b815260206004820152601e60248201527f696e697469616c697a65206f62736572766174696f6e73206661696c656400006044820152606401610f24565b505b60165461289190869086908e9087908790600160a01b8104600290810b91600160b81b9004900b30613790565b5050601780546001600160801b0319166001600160801b039290921691909117905560158190556000036129075760405162461bcd60e51b815260206004820152601b60248201527f696e697469616c697a65206c6971756964697479206661696c656400000000006044820152606401610f24565b426019556040517fc6cb858e754b4efdad8980cee030a8e8725c4e6e690d9b77733a89b5dd5601a19061293c90601390615069565b60405180910390a1505050505050505050505050565b61297173a7fd99748ce527eadc0bdac60cba8a4ef4090f7c600161155a565b6129907382c0fdfa607d9afbe82db5cbd103d1a4d5a43b77600161155a565b6129af735b93a825829f4b7b5177c259edc22b63d6e4e380600161155a565b601b546129c6906001600160a01b0316600161155a565b601c546129dd906001600160a01b0316600161155a565b6013546129f4906001600160a01b0316600161155a565b6111c96001610d3e565b6000806000612a0e8686866138fd565b915091508015612a7f57612a2486600086613a7e565b50612a2f8585613df4565b8360056000828254612a419190614ef0565b90915550506040518481527f77dd5e627769f9468b3e9ef3f0d14fdf2cca856af36dd6aa591989bdf3957685906020015b60405180910390a1612afa565b8115612aed57612a998686612a948588614ef0565b613a7e565b50612aa5863084613a7e565b5081601a6000828254612ab89190614f03565b90915550506040518281527fed9d4923888165f7fbf184c0010cb4a535efc8f5ac2b5ec687473e903997155290602001612a72565b612af8868686613a7e565b505b50600195945050505050565b6001600160a01b038216612b2d5760405163a41e3d3f60e01b815260040160405180910390fd5b8015612b4157612b3c82613fee565b612b4a565b612b4a82614022565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b60606000612b82836140b0565b600101905060008167ffffffffffffffff811115612ba257612ba2614967565b6040519080825280601f01601f191660200182016040528015612bcc576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612bd657509392505050565b6001600160a01b038316612c33578060056000828254612c289190614f03565b90915550612c619050565b6001600160a01b03831660009081526007602052604081208054839290612c5b908490614ef0565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612cb79085815260200190565b60405180910390a3505050565b6001600160a01b03831615612dcf57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c90915281208054612d1390600190614ef0565b81548110612d2357612d23614f16565b90600052602060002001549050818114612d90576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c602052604090208054919250839183908110612d7857612d78614f16565b600091825260209091200155612d8e8282614188565b505b6001600160a01b0384166000908152600c60205260409020805480612db757612db76150e7565b60019003818190600052602060002001600090559055505b6001600160a01b03821615612e46576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c83529083208054600181810183558286529385200185905592529054612e41918391612e3c9190614ef0565b614188565b612e56565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612ec083546001600160801b03808216600160801b9092048116919091031690565b8210612edf5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b60408051610100810182526001600160a01b03868116808352868216602080850191825260145462ffffff600160a01b909104811686880190815289861660608801908152426080890190815260a089018b8152600060c08b0181815260e08c01828152601c548e51602481019c909c5299518c1660448c0152955190961660648a0152925189166084890152905160a48801525160c4870152915160e48601525185166101048086019190915287518086039091018152610124909401875290830180516001600160e01b031663414bf38960e01b179052945185938493921691612ff291614b8a565b6000604051808303816000865af19150503d806000811461302f576040519150601f19603f3d011682016040523d82523d6000602084013e613034565b606091505b5091509150811561305657808060200190518101906130539190614c31565b93505b505050949350505050565b6040805160c0810182528481526020808201858152828401858152600060608501818152608086018281524260a08801908152601b548951602481018e90529651604488015294516064870152915160848601525160a48501525160c4808501919091528651808503909101815260e4909301865292820180516001600160e01b031663219f5d1760e01b17905293519193849384939092849283926001600160a01b039091169161311291614b8a565b6000604051808303816000865af19150503d806000811461314f576040519150601f19603f3d011682016040523d82523d6000602084013e613154565b606091505b5091509150811561317b578080602001905181019061317391906150fd565b919750955093505b50505093509350939050565b6040805160a0810182528381526001600160801b03838116602083019081526000838501818152606085018281524260808701908152601b549751602481018b90529451909516604485015290516064840152516084830152915160a48201529092839291839182916001600160a01b0390911690630c49ccbe9060c4016121ca565b6000808060001985870985870292508281108382030391505080600003613243576000841161323857600080fd5b508290049050610f9e565b80841161324f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000816000036132ca57506001610d8a565b306001600160a01b038416036133195750306000908152600860209081526040808320601b546001600160a01b0390811685529252808320849055601c54909116825290208190556001610d8a565b601b54604080516001600160a01b039283166024820152604480820186905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b179052905160009286169161337491614b8a565b6000604051808303816000865af19150503d80600081146133b1576040519150601f19603f3d011682016040523d82523d6000602084013e6133b6565b606091505b5050601c54604080516001600160a01b039283166024820152604480820188905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b1790529051929350600092918716916134189190614b8a565b6000604051808303816000865af19150503d8060008114613455576040519150601f19603f3d011682016040523d82523d6000602084013e61345a565b606091505b50509050818015611b9c5750949350505050565b601b54604080516001600160a01b038781166024830152868116604483015262ffffff861660648301528481166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166309f56ab160e11b1790529151600093849384938493849392909216916134eb9190614b8a565b6000604051808303816000865af19150503d8060008114613528576040519150601f19603f3d011682016040523d82523d6000602084013e61352d565b606091505b50915091508161354957600080600094509450945050506136e1565b8080602001905181019061355d9190615134565b60408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905191965060009182916001600160a01b038916916135a49190614b8a565b600060405180830381855afa9150503d80600081146135df576040519150601f19603f3d011682016040523d82523d6000602084013e6135e4565b606091505b509150915081613602576000806000965096509650505050506136e1565b808060200190518101906136169190615163565b505060408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b1790529051949b506000955085946001600160a01b038e1694506136649350909150614b8a565b600060405180830381855afa9150503d806000811461369f576040519150601f19603f3d011682016040523d82523d6000602084013e6136a4565b606091505b5091509150816136c45760008060009850985098505050505050506136e1565b808060200190518101906136d891906151f5565b96505050505050505b9450945094915050565b6040805161ffff831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166332148f6760e01b179052905160009182916001600160a01b0386169161374391614b8a565b6000604051808303816000865af19150503d8060008114613780576040519150601f19603f3d011682016040523d82523d6000602084013e613785565b606091505b509095945050505050565b60008060008060006040518061016001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c62ffffff1681526020018960020b81526020018860020b81526020018b81526020018a81526020016000815260200160008152602001876001600160a01b03168152602001428152509050600080601b60009054906101000a90046001600160a01b03166001600160a01b03166388316456846040516024016138469190615212565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161387f9190614b8a565b6000604051808303816000865af19150503d80600081146138bc576040519150601f19603f3d011682016040523d82523d6000602084013e6138c1565b606091505b509150915081156138eb57808060200190518101906138e091906152d6565b929950909750955093505b50505098509850985098945050505050565b60125460009081906001600160a01b0386811663010000009092041614806139365750601254630100000090046001600160a01b031633145b8061394b5750601c546001600160a01b031633145b8061395e57506001600160a01b03851630145b8061397657506013546001600160a01b038581169116145b1561398657506000905080613a76565b61398e6141f4565b6018805462ffffff9290921663010000000265ffffff000000199092169190911790556139c56014546001600160a01b0316301090565b15613a2b57601854600281810b6301000000909204900b1315613a0a57601254620f4240906139f99062ffffff1685614bf0565b613a039190614c1d565b9150613a76565b601854600281810b6301000000909204900b1215613a26575060015b613a76565b601854600281810b6301000000909204900b1215613a5a57601254620f4240906139f99062ffffff1685614bf0565b601854600281810b6301000000909204900b1315613a76575060015b935093915050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190613aaf868686612c08565b6000613aba87610e81565b90506000613ac787610e81565b9050818015613ad35750805b613de6578115613b7c576000613b097f000000000000000000000000000000000000000000000000000000000000000085614c1d565b6001600160a01b038916600090815260076020526040902054613b4d907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b613b579190614ef0565b905060005b81811015613b7557613b6d896144f1565b600101613b5c565b5050613de6565b8015613c18576001600160a01b038816600090815260076020526040812054613bc6907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b613bf07f000000000000000000000000000000000000000000000000000000000000000087614c1d565b613bfa9190614ef0565b905060005b81811015613b7557613c108a6145e4565b600101613bff565b6000613c447f000000000000000000000000000000000000000000000000000000000000000088614c1d565b905060005b81811015613cc7576001600160a01b038a166000908152600c6020526040812054613c7690600190614ef0565b6001600160a01b038c166000908152600c602052604081208054929350909183908110613ca557613ca5614f16565b90600052602060002001549050613cbd8c8c83612cc4565b5050600101613c49565b50807f0000000000000000000000000000000000000000000000000000000000000000613d098b6001600160a01b031660009081526007602052604090205490565b613d139190614c1d565b613d3d7f000000000000000000000000000000000000000000000000000000000000000088614c1d565b613d479190614ef0565b1115613d5657613d56896145e4565b80613d817f000000000000000000000000000000000000000000000000000000000000000086614c1d565b7f0000000000000000000000000000000000000000000000000000000000000000613dc18b6001600160a01b031660009081526007602052604090205490565b613dcb9190614c1d565b613dd59190614ef0565b1115613de457613de4886144f1565b505b506001979650505050505050565b6001600160a01b038216613e1b57604051636edaef2f60e11b815260040160405180910390fd5b601454604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009283926001600160a01b0390911691613e749190614b8a565b600060405180830381855afa9150503d8060008114613eaf576040519150601f19603f3d011682016040523d82523d6000602084013e613eb4565b606091505b509150915081613ec45750505050565b600081806020019051810190613eda9190614c31565b905060006005548286613eed9190614bf0565b613ef79190614c1d565b601454604080516001600160a01b038a81166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291519394506000939190921691613f5791614b8a565b6000604051808303816000865af19150503d8060008114613f94576040519150601f19603f3d011682016040523d82523d6000602084013e613f99565b606091505b50509050801561146557604080516001600160a01b0389168152602081018490527f289360176646a5f99cb4b6300628426dca46b723f40db3c04449d6ed1745a0e7910160405180910390a150505050505050565b6001600160a01b0381166000908152600c6020526040812054905b818110156110165761401a836145e4565b600101614009565b6001600160a01b038116600090815260076020526040812054614066907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b90506000614089836001600160a01b03166000908152600c602052604090205490565b905060005b6140988284614ef0565b8110156116e1576140a8846144f1565b60010161408e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106140ef5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061411b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061413957662386f26fc10000830492506010015b6305f5e1008310614151576305f5e100830492506008015b612710831061416557612710830492506004015b60648310614177576064830492506002015b600a8310610d8a5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff8211156141c457604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b600061420a6013546001600160a01b0316151590565b614218575060185460020b90565b60135460408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905160009283926001600160a01b03909116916142609190614b8a565b600060405180830381855afa9150503d806000811461429b576040519150601f19603f3d011682016040523d82523d6000602084013e6142a0565b606091505b5091509150816142b757505060185460020b919050565b6000806000838060200190518101906142d09190615163565b50506019549397509195509350610708925082916142ef915042614ef0565b63ffffffff16101561430657509195945050505050565b604080516002808252606082018352600092602083019080368337019050509050818160008151811061433b5761433b614f16565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061436a5761436a614f16565b63ffffffff9092166020928302919091019091015260135460405160009182916001600160a01b039091169063883bdbfd906143aa908690602401615314565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516143e39190614b8a565b600060405180830381855afa9150503d806000811461441e576040519150601f19603f3d011682016040523d82523d6000602084013e614423565b606091505b50915091508161443b57509498975050505050505050565b60008180602001905181019061445191906153ea565b50905060008160008151811061446957614469614f16565b60200260200101518260018151811061448457614484614f16565b602002602001015161449691906154b6565b90506144a863ffffffff8716826154e3565b985060008160060b1280156144ce57506144c863ffffffff871682615518565b60060b15155b156144e157886144dd8161553a565b9950505b50969a9950505050505050505050565b6001600160a01b03811661451857604051634e46966960e11b815260040160405180910390fd5b6000614538600154600160801b81046001600160801b0390811691161490565b61454d576145466001614665565b90506145a2565b60066000815461455c9061555d565b909155506006546001016145835760405163303b682f60e01b815260040160405180910390fd5b60065461459f906ec097ce7bc90715b34b9f1000000000614f03565b90505b6000818152600b60205260409020546001600160a01b031680156145d95760405163119b4fd360e11b815260040160405180910390fd5b611016818484612cc4565b6001600160a01b03811661460b57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c60205260408120805461463190600190614ef0565b8154811061464157614641614f16565b9060005260206000200154905061465a82600083612cc4565b610f646001826146d5565b80546000906001600160801b03600160801b820481169116810361469c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b900481169082160361471157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b8015158114611eb157600080fd5b60006020828403121561475f57600080fd5b8135610f9e8161473f565b6001600160e01b031981168114611eb157600080fd5b60006020828403121561479257600080fd5b8135610f9e8161476a565b6001600160a01b0381168114611eb157600080fd5b6000602082840312156147c457600080fd5b8135610f9e8161479d565b60005b838110156147ea5781810151838201526020016147d2565b50506000910152565b6000815180845261480b8160208601602086016147cf565b601f01601f19169290920160200192915050565b602081526000610f9e60208301846147f3565b60006020828403121561484457600080fd5b5035919050565b6000806040838503121561485e57600080fd5b82356148698161479d565b946020939093013593505050565b60008060006060848603121561488c57600080fd5b83356148978161479d565b925060208401356148a78161479d565b929592945050506040919091013590565b6001600160801b0381168114611eb157600080fd5b6000602082840312156148df57600080fd5b8135610f9e816148b8565b600080604083850312156148fd57600080fd5b82356149088161479d565b915060208301356149188161473f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561495b5783518352928401929184019160010161493f565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149a6576149a6614967565b604052919050565b600080600080608085870312156149c457600080fd5b84356149cf8161479d565b93506020858101356149e08161479d565b935060408601359250606086013567ffffffffffffffff80821115614a0457600080fd5b818801915088601f830112614a1857600080fd5b813581811115614a2a57614a2a614967565b614a3c601f8201601f1916850161497d565b91508082528984828501011115614a5257600080fd5b808484018584013760008482840101525080935050505092959194509250565b60ff81168114611eb157600080fd5b600080600080600080600060e0888a031215614a9c57600080fd5b8735614aa78161479d565b96506020880135614ab78161479d565b955060408801359450606088013593506080880135614ad581614a72565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215614b0557600080fd5b8235614b108161479d565b915060208301356149188161479d565b8060020b8114611eb157600080fd5b600060208284031215614b4157600080fd5b8135610f9e81614b20565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b60008151614b808185602086016147cf565b9290920192915050565b60008251614b9c8184602087016147cf565b9190910192915050565b600181811c90821680614bba57607f821691505b6020821081036123ab57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d8a57610d8a614bda565b634e487b7160e01b600052601260045260246000fd5b600082614c2c57614c2c614c07565b500490565b600060208284031215614c4357600080fd5b5051919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614c7d908301846147f3565b9695505050505050565b600060208284031215614c9957600080fd5b8151610f9e8161476a565b8054600090600181811c9080831680614cbe57607f831692505b60208084108203614cdf57634e487b7160e01b600052602260045260246000fd5b818015614cf35760018114614d0857614d34565b60ff1986168952841515850289019650614d34565b876000528160002060005b86811015614d2c5781548b820152908501908301614d13565b505084890196505b50505050505092915050565b747b226e616d65223a202257484f333333204e46542360581b81528551600090614d71816015850160208b016147cf565b7f222c226465736372697074696f6e223a224120636f6c6c656374696f6e206f66601591840191820152600160fd1b60358201528651614db8816036840160208b016147cf565b7f20706f7473206f66206c6971756964697479207468617420746f6b656e697a65603692909101918201527f7320646563656e7472616c697a656420726573657276652063757272656e637960568201527f206964656120666f722074686520495135302c20234552433333332e0000000060768201527f222c2265787465726e616c5f75726c223a2268747470733a2f2f77686f33333360928201526f173bba331791161134b6b0b3b2911d1160811b60b2820152614ee4614ed4614ece614e8d614e8760c286018b614ca4565b89614b6e565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a224381526e37b637b91116113b30b63ab2911d1160891b6020820152602f0190565b86614b6e565b63227d5d7d60e01b815260040190565b98975050505050505050565b81810381811115610d8a57610d8a614bda565b80820180821115610d8a57610d8a614bda565b634e487b7160e01b600052603260045260246000fd5b6001600160801b03818116838216019080821115614f4c57614f4c614bda565b5092915050565b6000610f9e8284614ca4565b6001600160801b03828116828216039080821115614f4c57614f4c614bda565b60008060408385031215614f9257600080fd5b505080516020909101519092909150565b60008160020b8360020b80614fba57614fba614c07565b627fffff19821460001982141615614fd457614fd4614bda565b90059392505050565b60008260020b8260020b028060020b9150808214614f4c57614f4c614bda565b600282810b9082900b03627fffff198112627fffff82131715610d8a57610d8a614bda565b60008160020b627fffff19810361503b5761503b614bda565b60000392915050565b600281810b9083900b01627fffff8113627fffff1982121715610d8a57610d8a614bda565b81546001600160a01b03168152610100810160018301546001600160a01b03808216602085015262ffffff60a092831c16604085015260028086015460608601526003860154918216608086015281831c810b9285019290925260b81c900b60c083015260048301546001600160801b031660e08301819052614f4c565b634e487b7160e01b600052603160045260246000fd5b60008060006060848603121561511257600080fd5b835161511d816148b8565b602085015160409095015190969495509392505050565b60006020828403121561514657600080fd5b8151610f9e8161479d565b805161ffff811681146111a557600080fd5b600080600080600080600060e0888a03121561517e57600080fd5b87516151898161479d565b602089015190975061519a81614b20565b95506151a860408901615151565b94506151b660608901615151565b93506151c460808901615151565b925060a08801516151d481614a72565b60c08901519092506151e58161473f565b8091505092959891949750929550565b60006020828403121561520757600080fd5b8151610f9e81614b20565b81516001600160a01b031681526101608101602083015161523e60208401826001600160a01b03169052565b506040830151615255604084018262ffffff169052565b50606083015161526a606084018260020b9052565b50608083015161527f608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516152c5828501826001600160a01b03169052565b505061014092830151919092015290565b600080600080608085870312156152ec57600080fd5b8451935060208501516152fe816148b8565b6040860151606090960151949790965092505050565b6020808252825182820181905260009190848201906040850190845b8181101561495b57835163ffffffff1683529284019291840191600101615330565b600067ffffffffffffffff82111561536c5761536c614967565b5060051b60200190565b600082601f83011261538757600080fd5b8151602061539c61539783615352565b61497d565b82815260059290921b840181019181810190868411156153bb57600080fd5b8286015b848110156153df5780516153d28161479d565b83529183019183016153bf565b509695505050505050565b600080604083850312156153fd57600080fd5b825167ffffffffffffffff8082111561541557600080fd5b818501915085601f83011261542957600080fd5b8151602061543961539783615352565b82815260059290921b8401810191818101908984111561545857600080fd5b948201945b838610156154865785518060060b81146154775760008081fd5b8252948201949082019061545d565b9188015191965090935050508082111561549f57600080fd5b506154ac85828601615376565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff82131715610d8a57610d8a614bda565b60008160060b8360060b806154fa576154fa614c07565b667fffffffffffff19821460001982141615614fd457614fd4614bda565b60008260060b8061552b5761552b614c07565b808360060b0791505092915050565b60008160020b627fffff19810361555357615553614bda565b6000190192915050565b60006001820161556f5761556f614bda565b506001019056fea264697066735822122069487e0347bf5b69b5a87dbc77908d5664fad9d13b7ee437e4a2e8ac0a61c17864736f6c63430008140033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159
Deployed Bytecode
0x6080604052600436106103a55760003560e01c80637a8a1113116101e7578063b88d4fde1161010d578063dd62ed3e116100a0578063e995016c1161006f578063e995016c14610c2b578063f2fde38b14610c4b578063f780bc1a14610c6b578063fe85b42b14610c8b57600080fd5b8063dd62ed3e14610b78578063dd63769914610bb0578063dfabc03314610bd0578063e985e9c514610bf057600080fd5b8063c87b56dd116100dc578063c87b56dd14610afe578063cd4bb50a14610b1e578063d505accf14610b38578063d96ca0b914610b5857600080fd5b8063b88d4fde14610a82578063c5ab3ba614610aa2578063c6e672b914610ab7578063c77cd5ac14610ad757600080fd5b806390fcdb3611610185578063a9059cbb11610154578063a9059cbb146109df578063ab01b469146109ff578063b1ab931714610a1f578063b3f9ea3414610a4c57600080fd5b806390fcdb361461095657806395d89b4114610976578063976a84351461098b578063a22cb465146109bf57600080fd5b8063853828b6116101c1578063853828b6146108ee57806389fb4c66146109035780638a696e50146109185780638da5cb5b1461093857600080fd5b80637a8a1113146108995780637ecebe00146108b95780638129fc1c146108e657600080fd5b806323b872dd116102cc5780634f02c4201161026a5780636e8f624b116102395780636e8f624b1461080457806370a0823114610827578063715018a6146108545780637541f41c1461086957600080fd5b80634f02c420146106f35780635eed923e146107095780636352211e146107cf5780636c0360eb146107ef57600080fd5b806342842e0e116102a657806342842e0e146106795780634524c4ab1461069957806349fa7fd8146106b35780634d966072146106d357600080fd5b806323b872dd146105fe578063313ce5671461061e5780633644e5151461066457600080fd5b8063095ea7b311610344578063158ef93e11610313578063158ef93e14610592578063173865ad146105b257806318160ddd146105d25780631bc392ae146105e857600080fd5b8063095ea7b31461050d57806309674eb01461052d57806309f0ef651461054257806313e7c9d81461056257600080fd5b8063045b7dca11610380578063045b7dca14610453578063065e53601461046957806306fdde031461049d578063081812fc146104bf57600080fd5b8062a5a777146103ba57806301ffc9a7146103da57806302519da31461040f57600080fd5b366103b5576103b334610ca1565b005b600080fd5b3480156103c657600080fd5b506103b36103d536600461474d565b610d3e565b3480156103e657600080fd5b506103fa6103f5366004614780565b610d59565b60405190151581526020015b60405180910390f35b34801561041b57600080fd5b5061044561042a3660046147b2565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610406565b34801561045f57600080fd5b5061044560115481565b34801561047557600080fd5b5060185461048a906301000000900460020b81565b60405160029190910b8152602001610406565b3480156104a957600080fd5b506104b2610d90565b604051610406919061481f565b3480156104cb57600080fd5b506104f56104da366004614832565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610406565b34801561051957600080fd5b506103fa61052836600461484b565b610e1e565b34801561053957600080fd5b50610445610e57565b34801561054e57600080fd5b506103fa61055d3660046147b2565b610e81565b34801561056e57600080fd5b506103fa61057d3660046147b2565b600f6020526000908152604090205460ff1681565b34801561059e57600080fd5b506013546001600160a01b031615156103fa565b3480156105be57600080fd5b506103b36105cd366004614832565b610eb3565b3480156105de57600080fd5b5061044560055481565b3480156105f457600080fd5b5061044560195481565b34801561060a57600080fd5b506103fa610619366004614877565b610f68565b34801561062a57600080fd5b506106527f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610406565b34801561067057600080fd5b50610445610fa5565b34801561068557600080fd5b506103b3610694366004614877565b610ffb565b3480156106a557600080fd5b5060185461048a9060020b81565b3480156106bf57600080fd5b506103b36106ce3660046148cd565b61101b565b3480156106df57600080fd5b506103fa6106ee36600461484b565b6110b3565b3480156106ff57600080fd5b5061044560065481565b34801561071557600080fd5b5060135460145460155460165460175461076e946001600160a01b03908116948082169462ffffff600160a01b928390041694909392811692918104600290810b92600160b81b909204900b906001600160801b031688565b604080516001600160a01b03998a168152978916602089015262ffffff90961695870195909552606086019390935294166080840152600293840b60a084015290920b60c08201526001600160801b0390911660e082015261010001610406565b3480156107db57600080fd5b506104f56107ea366004614832565b611140565b3480156107fb57600080fd5b506104b26111aa565b34801561081057600080fd5b506104456ec097ce7bc90715b34b9f100000000081565b34801561083357600080fd5b506104456108423660046147b2565b60076020526000908152604090205481565b34801561086057600080fd5b506103b36111b7565b34801561087557600080fd5b506012546108859062ffffff1681565b60405162ffffff9091168152602001610406565b3480156108a557600080fd5b50601b546104f5906001600160a01b031681565b3480156108c557600080fd5b506104456108d43660046147b2565b600e6020526000908152604090205481565b6103b36111cb565b3480156108fa57600080fd5b506103b36112f4565b34801561090f57600080fd5b50600554610445565b34801561092457600080fd5b506103b361093336600461474d565b61146e565b34801561094457600080fd5b506000546001600160a01b03166104f5565b34801561096257600080fd5b50601c546104f5906001600160a01b031681565b34801561098257600080fd5b506104b2611486565b34801561099757600080fd5b506104457f0000000000000000000000000000000000000000000000056bc75e2d6310000081565b3480156109cb57600080fd5b506103b36109da3660046148ea565b611493565b3480156109eb57600080fd5b506103fa6109fa36600461484b565b611526565b348015610a0b57600080fd5b506103b3610a1a3660046148ea565b61155a565b348015610a2b57600080fd5b50610a3f610a3a3660046147b2565b61158d565b6040516104069190614923565b348015610a5857600080fd5b50610445610a673660046147b2565b6001600160a01b03166000908152600c602052604090205490565b348015610a8e57600080fd5b506103b3610a9d3660046149ae565b6115f9565b348015610aae57600080fd5b50600654610445565b348015610ac357600080fd5b506103b3610ad23660046148ea565b6116e7565b348015610ae357600080fd5b506012546104f590630100000090046001600160a01b031681565b348015610b0a57600080fd5b506104b2610b19366004614832565b6116f9565b348015610b2a57600080fd5b506010546103fa9060ff1681565b348015610b4457600080fd5b506103b3610b53366004614a81565b6118a2565b348015610b6457600080fd5b506103fa610b73366004614877565b611ae5565b348015610b8457600080fd5b50610445610b93366004614af2565b600860209081526000928352604080842090915290825290205481565b348015610bbc57600080fd5b506103b3610bcb366004614877565b611ba5565b348015610bdc57600080fd5b506103b3610beb36600461484b565b611d8f565b348015610bfc57600080fd5b506103fa610c0b366004614af2565b600a60209081526000928352604080842090915290825290205460ff1681565b348015610c3757600080fd5b506103b3610c46366004614b2f565b611e54565b348015610c5757600080fd5b506103b3610c663660046147b2565b611e76565b348015610c7757600080fd5b50610a3f610c86366004614b4c565b611eb4565b348015610c9757600080fd5b50610445601a5481565b60408051600481526024810182526020810180516001600160e01b0316630d0e30db60e41b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2918591610cf29190614b8a565b60006040518083038185875af1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b5090949350505050565b610d46611f51565b6010805460ff1916911515919091179055565b60006001600160e01b0319821663caf91ff560e01b1480610d8a57506001600160e01b031982166301ffc9a760e01b145b92915050565b60038054610d9d90614ba6565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc990614ba6565b8015610e165780601f10610deb57610100808354040283529160200191610e16565b820191906000526020600020905b815481529060010190602001808311610df957829003601f168201915b505050505081565b6000610e2982611f7e565b15610e3d57610e388383611d8f565b610e4e565b610e4783836110b3565b9050610d8a565b50600192915050565b6000610e7c6001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b0382161580610d8a5750506001600160a01b03166000908152600d602052604090205460ff1690565b610ebb611f51565b30600090815260076020526040902054600390610ed9906002614bf0565b610ee39190614c1d565b811115610f2d5760405162461bcd60e51b8152602060048201526013602482015272616d6f756e7420697320746f6f206c6172676560681b60448201526064015b60405180910390fd5b6000610f3882611fa2565b90508015610f645730600090815260076020526040902054610f6490610f5f600284614c1d565b611fbe565b5050565b6000610f7382611f7e565b15610f8857610f83848484611ba5565b610f9a565b610f93848484611ae5565b9050610f9e565b5060015b9392505050565b60007f00000000000000000000000000000000000000000000000000000000000000014614610fd657610e7c61204e565b507f97aa1e46215350a0a115551c891f3a0dd44d08039b451b77646325a7a674278990565b611016838383604051806020016040528060008152506115f9565b505050565b611023611f51565b6017546001600160801b03908116908216111561107b5760405162461bcd60e51b81526020600482015260166024820152756c697175696469747920697320746f6f206c6172676560501b6044820152606401610f24565b6001600160801b0381161561109357611093816120e8565b6015546012546110169190630100000090046001600160a01b0316612159565b60006001600160a01b0383166110dc57604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661116182611f7e565b61117e576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b0381166111a55760405163c5723b5160e01b815260040160405180910390fd5b919050565b601d8054610d9d90614ba6565b6111bf611f51565b6111c96000612274565b565b6111d3611f51565b73c36442b4a4522e871399cd717abdd847ab11fe8873e592427a0aece92de3edee1f18e0157c05861564341561120e5761120c34610ca1565b505b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061123e576c39bc2ab9629fb800000000000061124c565b6b046f1de7bc353a00000000005b6cffffffffffffffffffffffffff1690506000611268826122c4565b905060006112746123b1565b9050818110156112bf5760405162461bcd60e51b81526020600482015260166024820152757765746820616d6f756e7420697320746f6f206c6f7760501b6044820152606401610f24565b6112e583610bb873c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285603c8a8a61247a565b6112ed612952565b5050505050565b6112fc611f51565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161135b91614b8a565b600060405180830381855afa9150503d8060008114611396576040519150601f19603f3d011682016040523d82523d6000602084013e61139b565b606091505b5091509150816113a9575050565b6000818060200190518101906113bf9190614c31565b60408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b179052905191925060009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161142391614b8a565b6000604051808303816000865af19150503d8060008114611460576040519150601f19603f3d011682016040523d82523d6000602084013e611465565b606091505b50505050505050565b6040516282b42960e81b815260040160405180910390fd5b60048054610d9d90614ba6565b6001600160a01b0382166114ba5760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b03831661154f57604051634e46966960e11b815260040160405180910390fd5b610f9e3384846129fe565b611562611f51565b6001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6001600160a01b0381166000908152600c60209081526040918290208054835181840281018401909452808452606093928301828280156115ed57602002820191906000526020600020905b8154815260200190600101908083116115d9575b50505050509050919050565b61160282611f7e565b61161f576040516307ed98ed60e31b815260040160405180910390fd5b61162a848484610f68565b506001600160a01b0383163b158015906116c35750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611673903390899088908890600401614c4a565b6020604051808303816000875af1158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190614c87565b6001600160e01b03191614155b156116e157604051633da6393160e01b815260040160405180910390fd5b50505050565b6116ef611f51565b610f648282612b06565b606060008260405160200161171091815260200190565b6040516020818303038152906040528051906020012060f81c905060608060408360ff161161177c5760405180604001604052806005815260200164302e706e6760d81b81525091506040518060400160405280600381526020016214995960ea1b815250905061185d565b60808360ff16116117cb5760405180604001604052806005815260200164312e706e6760d81b815250915060405180604001604052806004815260200163426c756560e01b815250905061185d565b60c08360ff161161181b5760405180604001604052806005815260200164322e706e6760d81b81525091506040518060400160405280600581526020016423b932b2b760d91b815250905061185d565b60405180604001604052806005815260200164332e706e6760d81b815250915060405180604001604052806006815260200165507572706c6560d01b81525090505b61186685612b75565b611871601154612b75565b601d8484604051602001611889959493929190614d40565b6040516020818303038152906040529350505050919050565b428410156118c3576040516305787bdf60e01b815260040160405180910390fd5b6118cc85611f7e565b156118ea576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b03861661191157604051635461585f60e01b815260040160405180910390fd5b6000600161191d610fa5565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611a29573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580611a5e5750876001600160a01b0316816001600160a01b031614155b15611a7c57604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416611b0e57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316611b3557604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114611b9157611b6c8382614ef0565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b611b9c8585856129fe565b95945050505050565b6001600160a01b038316611bcc57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216611bf357604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614611c2c576040516282b42960e81b815260040160405180910390fd5b60105460ff1615611cb5576000546001600160a01b0316331480611c615750601254630100000090046001600160a01b031633145b80611c7b5750336000908152600f602052604090205460ff165b611cb55760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08185b1b1bddd95960aa1b6044820152606401610f24565b336001600160a01b03841614801590611cf257506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015611d1557506000818152600960205260409020546001600160a01b03163314155b15611d32576040516282b42960e81b815260040160405180910390fd5b611d3b82610e81565b15611d5957604051635ce7539760e01b815260040160405180910390fd5b611d8483837f0000000000000000000000000000000000000000000000056bc75e2d63100000612c08565b611016838383612cc4565b6000818152600b60205260409020546001600160a01b0316338114801590611ddb57506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b15611df8576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b611e5c611f51565b6018805462ffffff191662ffffff92909216919091179055565b611e7e611f51565b6001600160a01b038116611ea857604051631e4fbdf760e01b815260006004820152602401610f24565b611eb181612274565b50565b606060008267ffffffffffffffff811115611ed157611ed1614967565b604051908082528060200260200182016040528015611efa578160200160208202803683370190505b509050835b611f098486614f03565b811015611f4957611f1b600182612e9c565b82611f268784614ef0565b81518110611f3657611f36614f16565b6020908102919091010152600101611eff565b509392505050565b6000546001600160a01b031633146111c95760405163118cdaa760e01b8152336004820152602401610f24565b60006ec097ce7bc90715b34b9f100000000082118015610d8a575050600019141590565b601454600090610d8a9030906001600160a01b03168185612f07565b60145430906001600160a01b0316838382841115611fdb57919291905b6000611fed6013600201548484613061565b909450925090506001600160801b0381161561146557601780548291906000906120219084906001600160801b0316614f2c565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516120809190614f53565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000806120fa60136002015484613187565b91509150600082118061210d5750600081115b1561101657601780548491906000906121309084906001600160801b0316614f5f565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b604080516080810182528381526001600160a01b03838116602083019081526001600160801b0383850181815260608501828152601b549651602481018a905293518516604485015290518216606484015251166084820152600093849392849283929091169063fc6f78659060a4015b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516122039190614b8a565b6000604051808303816000865af19150503d8060008114612240576040519150601f19603f3d011682016040523d82523d6000602084013e612245565b606091505b5091509150811561226a57808060200190518101906122649190614f7f565b90955093505b5050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b306000908152600760205260408120546001600160801b036001600160a01b038416116123485760006123006001600160a01b03851680614bf0565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc230106123315761232c600160c01b838361320a565b612340565b6123408183600160c01b61320a565b9250506123ab565b60006123676001600160a01b038516806801000000000000000061320a565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061239857612393600160801b838361320a565b6123a7565b6123a78183600160801b61320a565b9250505b50919050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17905290516000918291829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916124139190614b8a565b600060405180830381855afa9150503d806000811461244e576040519150601f19603f3d011682016040523d82523d6000602084013e612453565b606091505b5091509150811561247557808060200190518101906124729190614c31565b92505b505090565b612482611f51565b6013546001600160a01b0316156124d15760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610f24565b601b80546001600160a01b03199081166001600160a01b0385811691909117909255601c80548216848416179055601480548884166001600160b81b03199091168117600160a01b62ffffff8c16021790915560168054909216928a16929092179055306000818152600760205260409020549091879190879084111561255757919291905b612563846000196132b8565b50612570836000196132b8565b50600061257f85858d8f61346e565b6018805462ffffff90931663010000000265ffffff0000001990931692909217909155601380546001600160a01b039093166001600160a01b0319909316831790559150158015906125d557508060020b600014155b61261a5760405162461bcd60e51b81526020600482015260166024820152751a5b9a5d1a585b1a5e99481c1bdbdb0819985a5b195960521b6044820152606401610f24565b6018805462ffffff198116630100000090910462ffffff161790556014546001600160a01b031630101561272357601854819061265b90829060020b614fa3565b6126659190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b19909216919091179055601854600060029190910b12156126d857601680548291906014906126b8908490600160a01b900460020b614ffd565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b80806126e7620d89e719615022565b6126f19190614fa3565b6126fb9190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b199092169190911790556127f0565b601854819061273690829060020b614fa3565b6127409190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b19909216919091179055601854600060029190910b13156127b35760168054829190601790612793908490600160b81b900460020b615044565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b806127c281620d89e719614fa3565b6127cc9190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b199092169190911790555b61ffff88161561286457601354600090612813906001600160a01b03168a6136eb565b9050806128625760405162461bcd60e51b815260206004820152601e60248201527f696e697469616c697a65206f62736572766174696f6e73206661696c656400006044820152606401610f24565b505b60165461289190869086908e9087908790600160a01b8104600290810b91600160b81b9004900b30613790565b5050601780546001600160801b0319166001600160801b039290921691909117905560158190556000036129075760405162461bcd60e51b815260206004820152601b60248201527f696e697469616c697a65206c6971756964697479206661696c656400000000006044820152606401610f24565b426019556040517fc6cb858e754b4efdad8980cee030a8e8725c4e6e690d9b77733a89b5dd5601a19061293c90601390615069565b60405180910390a1505050505050505050505050565b61297173a7fd99748ce527eadc0bdac60cba8a4ef4090f7c600161155a565b6129907382c0fdfa607d9afbe82db5cbd103d1a4d5a43b77600161155a565b6129af735b93a825829f4b7b5177c259edc22b63d6e4e380600161155a565b601b546129c6906001600160a01b0316600161155a565b601c546129dd906001600160a01b0316600161155a565b6013546129f4906001600160a01b0316600161155a565b6111c96001610d3e565b6000806000612a0e8686866138fd565b915091508015612a7f57612a2486600086613a7e565b50612a2f8585613df4565b8360056000828254612a419190614ef0565b90915550506040518481527f77dd5e627769f9468b3e9ef3f0d14fdf2cca856af36dd6aa591989bdf3957685906020015b60405180910390a1612afa565b8115612aed57612a998686612a948588614ef0565b613a7e565b50612aa5863084613a7e565b5081601a6000828254612ab89190614f03565b90915550506040518281527fed9d4923888165f7fbf184c0010cb4a535efc8f5ac2b5ec687473e903997155290602001612a72565b612af8868686613a7e565b505b50600195945050505050565b6001600160a01b038216612b2d5760405163a41e3d3f60e01b815260040160405180910390fd5b8015612b4157612b3c82613fee565b612b4a565b612b4a82614022565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b60606000612b82836140b0565b600101905060008167ffffffffffffffff811115612ba257612ba2614967565b6040519080825280601f01601f191660200182016040528015612bcc576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612bd657509392505050565b6001600160a01b038316612c33578060056000828254612c289190614f03565b90915550612c619050565b6001600160a01b03831660009081526007602052604081208054839290612c5b908490614ef0565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612cb79085815260200190565b60405180910390a3505050565b6001600160a01b03831615612dcf57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c90915281208054612d1390600190614ef0565b81548110612d2357612d23614f16565b90600052602060002001549050818114612d90576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c602052604090208054919250839183908110612d7857612d78614f16565b600091825260209091200155612d8e8282614188565b505b6001600160a01b0384166000908152600c60205260409020805480612db757612db76150e7565b60019003818190600052602060002001600090559055505b6001600160a01b03821615612e46576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c83529083208054600181810183558286529385200185905592529054612e41918391612e3c9190614ef0565b614188565b612e56565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612ec083546001600160801b03808216600160801b9092048116919091031690565b8210612edf5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b60408051610100810182526001600160a01b03868116808352868216602080850191825260145462ffffff600160a01b909104811686880190815289861660608801908152426080890190815260a089018b8152600060c08b0181815260e08c01828152601c548e51602481019c909c5299518c1660448c0152955190961660648a0152925189166084890152905160a48801525160c4870152915160e48601525185166101048086019190915287518086039091018152610124909401875290830180516001600160e01b031663414bf38960e01b179052945185938493921691612ff291614b8a565b6000604051808303816000865af19150503d806000811461302f576040519150601f19603f3d011682016040523d82523d6000602084013e613034565b606091505b5091509150811561305657808060200190518101906130539190614c31565b93505b505050949350505050565b6040805160c0810182528481526020808201858152828401858152600060608501818152608086018281524260a08801908152601b548951602481018e90529651604488015294516064870152915160848601525160a48501525160c4808501919091528651808503909101815260e4909301865292820180516001600160e01b031663219f5d1760e01b17905293519193849384939092849283926001600160a01b039091169161311291614b8a565b6000604051808303816000865af19150503d806000811461314f576040519150601f19603f3d011682016040523d82523d6000602084013e613154565b606091505b5091509150811561317b578080602001905181019061317391906150fd565b919750955093505b50505093509350939050565b6040805160a0810182528381526001600160801b03838116602083019081526000838501818152606085018281524260808701908152601b549751602481018b90529451909516604485015290516064840152516084830152915160a48201529092839291839182916001600160a01b0390911690630c49ccbe9060c4016121ca565b6000808060001985870985870292508281108382030391505080600003613243576000841161323857600080fd5b508290049050610f9e565b80841161324f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000816000036132ca57506001610d8a565b306001600160a01b038416036133195750306000908152600860209081526040808320601b546001600160a01b0390811685529252808320849055601c54909116825290208190556001610d8a565b601b54604080516001600160a01b039283166024820152604480820186905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b179052905160009286169161337491614b8a565b6000604051808303816000865af19150503d80600081146133b1576040519150601f19603f3d011682016040523d82523d6000602084013e6133b6565b606091505b5050601c54604080516001600160a01b039283166024820152604480820188905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b1790529051929350600092918716916134189190614b8a565b6000604051808303816000865af19150503d8060008114613455576040519150601f19603f3d011682016040523d82523d6000602084013e61345a565b606091505b50509050818015611b9c5750949350505050565b601b54604080516001600160a01b038781166024830152868116604483015262ffffff861660648301528481166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166309f56ab160e11b1790529151600093849384938493849392909216916134eb9190614b8a565b6000604051808303816000865af19150503d8060008114613528576040519150601f19603f3d011682016040523d82523d6000602084013e61352d565b606091505b50915091508161354957600080600094509450945050506136e1565b8080602001905181019061355d9190615134565b60408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905191965060009182916001600160a01b038916916135a49190614b8a565b600060405180830381855afa9150503d80600081146135df576040519150601f19603f3d011682016040523d82523d6000602084013e6135e4565b606091505b509150915081613602576000806000965096509650505050506136e1565b808060200190518101906136169190615163565b505060408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b1790529051949b506000955085946001600160a01b038e1694506136649350909150614b8a565b600060405180830381855afa9150503d806000811461369f576040519150601f19603f3d011682016040523d82523d6000602084013e6136a4565b606091505b5091509150816136c45760008060009850985098505050505050506136e1565b808060200190518101906136d891906151f5565b96505050505050505b9450945094915050565b6040805161ffff831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166332148f6760e01b179052905160009182916001600160a01b0386169161374391614b8a565b6000604051808303816000865af19150503d8060008114613780576040519150601f19603f3d011682016040523d82523d6000602084013e613785565b606091505b509095945050505050565b60008060008060006040518061016001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c62ffffff1681526020018960020b81526020018860020b81526020018b81526020018a81526020016000815260200160008152602001876001600160a01b03168152602001428152509050600080601b60009054906101000a90046001600160a01b03166001600160a01b03166388316456846040516024016138469190615212565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161387f9190614b8a565b6000604051808303816000865af19150503d80600081146138bc576040519150601f19603f3d011682016040523d82523d6000602084013e6138c1565b606091505b509150915081156138eb57808060200190518101906138e091906152d6565b929950909750955093505b50505098509850985098945050505050565b60125460009081906001600160a01b0386811663010000009092041614806139365750601254630100000090046001600160a01b031633145b8061394b5750601c546001600160a01b031633145b8061395e57506001600160a01b03851630145b8061397657506013546001600160a01b038581169116145b1561398657506000905080613a76565b61398e6141f4565b6018805462ffffff9290921663010000000265ffffff000000199092169190911790556139c56014546001600160a01b0316301090565b15613a2b57601854600281810b6301000000909204900b1315613a0a57601254620f4240906139f99062ffffff1685614bf0565b613a039190614c1d565b9150613a76565b601854600281810b6301000000909204900b1215613a26575060015b613a76565b601854600281810b6301000000909204900b1215613a5a57601254620f4240906139f99062ffffff1685614bf0565b601854600281810b6301000000909204900b1315613a76575060015b935093915050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190613aaf868686612c08565b6000613aba87610e81565b90506000613ac787610e81565b9050818015613ad35750805b613de6578115613b7c576000613b097f0000000000000000000000000000000000000000000000056bc75e2d6310000085614c1d565b6001600160a01b038916600090815260076020526040902054613b4d907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b613b579190614ef0565b905060005b81811015613b7557613b6d896144f1565b600101613b5c565b5050613de6565b8015613c18576001600160a01b038816600090815260076020526040812054613bc6907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b613bf07f0000000000000000000000000000000000000000000000056bc75e2d6310000087614c1d565b613bfa9190614ef0565b905060005b81811015613b7557613c108a6145e4565b600101613bff565b6000613c447f0000000000000000000000000000000000000000000000056bc75e2d6310000088614c1d565b905060005b81811015613cc7576001600160a01b038a166000908152600c6020526040812054613c7690600190614ef0565b6001600160a01b038c166000908152600c602052604081208054929350909183908110613ca557613ca5614f16565b90600052602060002001549050613cbd8c8c83612cc4565b5050600101613c49565b50807f0000000000000000000000000000000000000000000000056bc75e2d63100000613d098b6001600160a01b031660009081526007602052604090205490565b613d139190614c1d565b613d3d7f0000000000000000000000000000000000000000000000056bc75e2d6310000088614c1d565b613d479190614ef0565b1115613d5657613d56896145e4565b80613d817f0000000000000000000000000000000000000000000000056bc75e2d6310000086614c1d565b7f0000000000000000000000000000000000000000000000056bc75e2d63100000613dc18b6001600160a01b031660009081526007602052604090205490565b613dcb9190614c1d565b613dd59190614ef0565b1115613de457613de4886144f1565b505b506001979650505050505050565b6001600160a01b038216613e1b57604051636edaef2f60e11b815260040160405180910390fd5b601454604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009283926001600160a01b0390911691613e749190614b8a565b600060405180830381855afa9150503d8060008114613eaf576040519150601f19603f3d011682016040523d82523d6000602084013e613eb4565b606091505b509150915081613ec45750505050565b600081806020019051810190613eda9190614c31565b905060006005548286613eed9190614bf0565b613ef79190614c1d565b601454604080516001600160a01b038a81166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291519394506000939190921691613f5791614b8a565b6000604051808303816000865af19150503d8060008114613f94576040519150601f19603f3d011682016040523d82523d6000602084013e613f99565b606091505b50509050801561146557604080516001600160a01b0389168152602081018490527f289360176646a5f99cb4b6300628426dca46b723f40db3c04449d6ed1745a0e7910160405180910390a150505050505050565b6001600160a01b0381166000908152600c6020526040812054905b818110156110165761401a836145e4565b600101614009565b6001600160a01b038116600090815260076020526040812054614066907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b90506000614089836001600160a01b03166000908152600c602052604090205490565b905060005b6140988284614ef0565b8110156116e1576140a8846144f1565b60010161408e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106140ef5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061411b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061413957662386f26fc10000830492506010015b6305f5e1008310614151576305f5e100830492506008015b612710831061416557612710830492506004015b60648310614177576064830492506002015b600a8310610d8a5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff8211156141c457604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b600061420a6013546001600160a01b0316151590565b614218575060185460020b90565b60135460408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905160009283926001600160a01b03909116916142609190614b8a565b600060405180830381855afa9150503d806000811461429b576040519150601f19603f3d011682016040523d82523d6000602084013e6142a0565b606091505b5091509150816142b757505060185460020b919050565b6000806000838060200190518101906142d09190615163565b50506019549397509195509350610708925082916142ef915042614ef0565b63ffffffff16101561430657509195945050505050565b604080516002808252606082018352600092602083019080368337019050509050818160008151811061433b5761433b614f16565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061436a5761436a614f16565b63ffffffff9092166020928302919091019091015260135460405160009182916001600160a01b039091169063883bdbfd906143aa908690602401615314565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516143e39190614b8a565b600060405180830381855afa9150503d806000811461441e576040519150601f19603f3d011682016040523d82523d6000602084013e614423565b606091505b50915091508161443b57509498975050505050505050565b60008180602001905181019061445191906153ea565b50905060008160008151811061446957614469614f16565b60200260200101518260018151811061448457614484614f16565b602002602001015161449691906154b6565b90506144a863ffffffff8716826154e3565b985060008160060b1280156144ce57506144c863ffffffff871682615518565b60060b15155b156144e157886144dd8161553a565b9950505b50969a9950505050505050505050565b6001600160a01b03811661451857604051634e46966960e11b815260040160405180910390fd5b6000614538600154600160801b81046001600160801b0390811691161490565b61454d576145466001614665565b90506145a2565b60066000815461455c9061555d565b909155506006546001016145835760405163303b682f60e01b815260040160405180910390fd5b60065461459f906ec097ce7bc90715b34b9f1000000000614f03565b90505b6000818152600b60205260409020546001600160a01b031680156145d95760405163119b4fd360e11b815260040160405180910390fd5b611016818484612cc4565b6001600160a01b03811661460b57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c60205260408120805461463190600190614ef0565b8154811061464157614641614f16565b9060005260206000200154905061465a82600083612cc4565b610f646001826146d5565b80546000906001600160801b03600160801b820481169116810361469c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b900481169082160361471157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b8015158114611eb157600080fd5b60006020828403121561475f57600080fd5b8135610f9e8161473f565b6001600160e01b031981168114611eb157600080fd5b60006020828403121561479257600080fd5b8135610f9e8161476a565b6001600160a01b0381168114611eb157600080fd5b6000602082840312156147c457600080fd5b8135610f9e8161479d565b60005b838110156147ea5781810151838201526020016147d2565b50506000910152565b6000815180845261480b8160208601602086016147cf565b601f01601f19169290920160200192915050565b602081526000610f9e60208301846147f3565b60006020828403121561484457600080fd5b5035919050565b6000806040838503121561485e57600080fd5b82356148698161479d565b946020939093013593505050565b60008060006060848603121561488c57600080fd5b83356148978161479d565b925060208401356148a78161479d565b929592945050506040919091013590565b6001600160801b0381168114611eb157600080fd5b6000602082840312156148df57600080fd5b8135610f9e816148b8565b600080604083850312156148fd57600080fd5b82356149088161479d565b915060208301356149188161473f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561495b5783518352928401929184019160010161493f565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149a6576149a6614967565b604052919050565b600080600080608085870312156149c457600080fd5b84356149cf8161479d565b93506020858101356149e08161479d565b935060408601359250606086013567ffffffffffffffff80821115614a0457600080fd5b818801915088601f830112614a1857600080fd5b813581811115614a2a57614a2a614967565b614a3c601f8201601f1916850161497d565b91508082528984828501011115614a5257600080fd5b808484018584013760008482840101525080935050505092959194509250565b60ff81168114611eb157600080fd5b600080600080600080600060e0888a031215614a9c57600080fd5b8735614aa78161479d565b96506020880135614ab78161479d565b955060408801359450606088013593506080880135614ad581614a72565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215614b0557600080fd5b8235614b108161479d565b915060208301356149188161479d565b8060020b8114611eb157600080fd5b600060208284031215614b4157600080fd5b8135610f9e81614b20565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b60008151614b808185602086016147cf565b9290920192915050565b60008251614b9c8184602087016147cf565b9190910192915050565b600181811c90821680614bba57607f821691505b6020821081036123ab57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d8a57610d8a614bda565b634e487b7160e01b600052601260045260246000fd5b600082614c2c57614c2c614c07565b500490565b600060208284031215614c4357600080fd5b5051919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614c7d908301846147f3565b9695505050505050565b600060208284031215614c9957600080fd5b8151610f9e8161476a565b8054600090600181811c9080831680614cbe57607f831692505b60208084108203614cdf57634e487b7160e01b600052602260045260246000fd5b818015614cf35760018114614d0857614d34565b60ff1986168952841515850289019650614d34565b876000528160002060005b86811015614d2c5781548b820152908501908301614d13565b505084890196505b50505050505092915050565b747b226e616d65223a202257484f333333204e46542360581b81528551600090614d71816015850160208b016147cf565b7f222c226465736372697074696f6e223a224120636f6c6c656374696f6e206f66601591840191820152600160fd1b60358201528651614db8816036840160208b016147cf565b7f20706f7473206f66206c6971756964697479207468617420746f6b656e697a65603692909101918201527f7320646563656e7472616c697a656420726573657276652063757272656e637960568201527f206964656120666f722074686520495135302c20234552433333332e0000000060768201527f222c2265787465726e616c5f75726c223a2268747470733a2f2f77686f33333360928201526f173bba331791161134b6b0b3b2911d1160811b60b2820152614ee4614ed4614ece614e8d614e8760c286018b614ca4565b89614b6e565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a224381526e37b637b91116113b30b63ab2911d1160891b6020820152602f0190565b86614b6e565b63227d5d7d60e01b815260040190565b98975050505050505050565b81810381811115610d8a57610d8a614bda565b80820180821115610d8a57610d8a614bda565b634e487b7160e01b600052603260045260246000fd5b6001600160801b03818116838216019080821115614f4c57614f4c614bda565b5092915050565b6000610f9e8284614ca4565b6001600160801b03828116828216039080821115614f4c57614f4c614bda565b60008060408385031215614f9257600080fd5b505080516020909101519092909150565b60008160020b8360020b80614fba57614fba614c07565b627fffff19821460001982141615614fd457614fd4614bda565b90059392505050565b60008260020b8260020b028060020b9150808214614f4c57614f4c614bda565b600282810b9082900b03627fffff198112627fffff82131715610d8a57610d8a614bda565b60008160020b627fffff19810361503b5761503b614bda565b60000392915050565b600281810b9083900b01627fffff8113627fffff1982121715610d8a57610d8a614bda565b81546001600160a01b03168152610100810160018301546001600160a01b03808216602085015262ffffff60a092831c16604085015260028086015460608601526003860154918216608086015281831c810b9285019290925260b81c900b60c083015260048301546001600160801b031660e08301819052614f4c565b634e487b7160e01b600052603160045260246000fd5b60008060006060848603121561511257600080fd5b835161511d816148b8565b602085015160409095015190969495509392505050565b60006020828403121561514657600080fd5b8151610f9e8161479d565b805161ffff811681146111a557600080fd5b600080600080600080600060e0888a03121561517e57600080fd5b87516151898161479d565b602089015190975061519a81614b20565b95506151a860408901615151565b94506151b660608901615151565b93506151c460808901615151565b925060a08801516151d481614a72565b60c08901519092506151e58161473f565b8091505092959891949750929550565b60006020828403121561520757600080fd5b8151610f9e81614b20565b81516001600160a01b031681526101608101602083015161523e60208401826001600160a01b03169052565b506040830151615255604084018262ffffff169052565b50606083015161526a606084018260020b9052565b50608083015161527f608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516152c5828501826001600160a01b03169052565b505061014092830151919092015290565b600080600080608085870312156152ec57600080fd5b8451935060208501516152fe816148b8565b6040860151606090960151949790965092505050565b6020808252825182820181905260009190848201906040850190845b8181101561495b57835163ffffffff1683529284019291840191600101615330565b600067ffffffffffffffff82111561536c5761536c614967565b5060051b60200190565b600082601f83011261538757600080fd5b8151602061539c61539783615352565b61497d565b82815260059290921b840181019181810190868411156153bb57600080fd5b8286015b848110156153df5780516153d28161479d565b83529183019183016153bf565b509695505050505050565b600080604083850312156153fd57600080fd5b825167ffffffffffffffff8082111561541557600080fd5b818501915085601f83011261542957600080fd5b8151602061543961539783615352565b82815260059290921b8401810191818101908984111561545857600080fd5b948201945b838610156154865785518060060b81146154775760008081fd5b8252948201949082019061545d565b9188015191965090935050508082111561549f57600080fd5b506154ac85828601615376565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff82131715610d8a57610d8a614bda565b60008160060b8360060b806154fa576154fa614c07565b667fffffffffffff19821460001982141615614fd457614fd4614bda565b60008260060b8061552b5761552b614c07565b808360060b0791505092915050565b60008160020b627fffff19810361555357615553614bda565b6000190192915050565b60006001820161556f5761556f614bda565b506001019056fea264697066735822122069487e0347bf5b69b5a87dbc77908d5664fad9d13b7ee437e4a2e8ac0a61c17864736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159
-----Decoded View---------------
Arg [0] : initialOwner_ (address): 0xCdF74BFF7C62c72775A2cdb83dBc0A1d4866703A
Arg [1] : initialMintRecipient_ (address): 0xA6AFd4D1226169db19432cf6F26f66a219b9b159
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a
Arg [1] : 000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.