ERC-20
Overview
Max Total Supply
10,000 Bunny
Holders
9
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
14.356265377115135719 BunnyValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
LuckyBunny404
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2024-03-05 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); } // File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } } // File: @openzeppelin/contracts/utils/introspection/IERC165.sol // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @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); } // File: @openzeppelin/contracts/token/ERC721/IERC721.sol // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; /** * @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 caller. * * 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); } // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); } // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; /** * @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); } // File: Bot/Bot404.sol pragma solidity ^0.8.4; pragma abicoder v2; /// @notice Library for converting numbers into strings and other string operations. /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } } /// @notice Library for burning gas without reverting. library GasBurnerLib { /// @dev Burns approximately `x` amount of gas. /// Intended for Contract Secured Revenue (CSR). /// /// Recommendation: pass in an admin-controlled dynamic value instead of a hardcoded one. /// This is so that you can adjust your contract as needed depending on market conditions, /// and to give you and your users a leeway in case the L2 chain change the rules. function burn(uint256 x) internal pure { /// @solidity memory-safe-assembly assembly { mstore(0x10, or(1, x)) let n := mul(gt(x, 120), div(x, 91)) // We use keccak256 instead of blake2f precompile for better widespread compatibility. for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { mstore(0x10, keccak256(0x10, 0x10)) // Yes. } if iszero(mload(0x10)) { invalid() } } } } /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes. uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } } library DailyOutflowCounterLib { uint256 internal constant WAD_TRUNCATED = 10 ** 18 >> 40; uint256 internal constant OUTFLOW_TRUNCATED_MASK = 0xffffffffffffff; uint256 internal constant DAY_BITPOS = 56; uint256 internal constant DAY_MASK = 0x7fffffff; uint256 internal constant OUTFLOW_TRUNCATE_SHR = 40; uint256 internal constant WHITELISTED_BITPOS = 87; function update(uint88 packed, uint256 outflow) internal view returns (uint88 updated, uint256 multiple) { unchecked { if (isWhitelisted(packed)) { return (packed, 0); } uint256 currentDay = (block.timestamp / 86400) & DAY_MASK; uint256 packedDay = (uint256(packed) >> DAY_BITPOS) & DAY_MASK; uint256 totalOutflowTruncated = uint256(packed) & OUTFLOW_TRUNCATED_MASK; if (packedDay != currentDay) { totalOutflowTruncated = 0; packedDay = currentDay; } uint256 result = packedDay << DAY_BITPOS; uint256 todaysOutflowTruncated = totalOutflowTruncated + ((outflow >> OUTFLOW_TRUNCATE_SHR) & OUTFLOW_TRUNCATED_MASK); result |= todaysOutflowTruncated & OUTFLOW_TRUNCATED_MASK; updated = uint88(result); multiple = todaysOutflowTruncated / WAD_TRUNCATED; } } function isWhitelisted(uint88 packed) internal pure returns (bool) { return packed >> WHITELISTED_BITPOS != 0; } function setWhitelisted(uint88 packed, bool status) internal pure returns (uint88) { if (isWhitelisted(packed) != status) { packed ^= uint88(1 << WHITELISTED_BITPOS); } return packed; } } /// @notice Simple single owner authorization mixin. /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } } /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Overwrite the roles directly without authorization guard. function _setRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Store the new value. sstore(keccak256(0x0c, 0x20), roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Updates the roles directly without authorization guard. /// If `on` is true, each set bit of `roles` will be turned on, /// otherwise, each set bit of `roles` will be turned off. function _updateRoles(address user, uint256 roles, bool on) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let current := sload(roleSlot) // Compute the updated roles if `on` is true. let updated := or(current, roles) // Compute the updated roles if `on` is false. // Use `and` to compute the intersection of `current` and `roles`, // `xor` it with `current` to flip the bits in the intersection. if iszero(on) { updated := xor(current, and(current, roles)) } // Then, store the new value. sstore(roleSlot, updated) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) } } /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, true); } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, false); } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles != 0; } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles == roles; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; } /// @title DN404 /// @notice DN404 is a hybrid ERC20 and ERC721 implementation that mints /// and burns NFTs based on an account's ERC20 token balance. /// /// @author vectorized.eth (@optimizoor) /// @author Quit (@0xQuit) /// @author Michael Amadi (@AmadiMichaels) /// @author cygaar (@0xCygaar) /// @author Thomas (@0xjustadev) /// @author Harrison (@PopPunkOnChain) /// /// @dev Note: /// - The ERC721 data is stored in this base DN404 contract, however a /// DN404Mirror contract ***MUST*** be deployed and linked during /// initialization. abstract contract DN404 { /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* EVENTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Emitted when `amount` tokens is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 amount); /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`. event Approval(address indexed owner, address indexed spender, uint256 amount); /// @dev Emitted when `target` sets their skipNFT flag to `status`. event SkipNFTSet(address indexed target, bool status); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CUSTOM ERRORS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Thrown when attempting to double-initialize the contract. error DNAlreadyInitialized(); /// @dev Thrown when attempting to transfer or burn more tokens than sender's balance. error InsufficientBalance(); /// @dev Thrown when a spender attempts to transfer tokens with an insufficient allowance. error InsufficientAllowance(); /// @dev Thrown when minting an amount of tokens that would overflow the max tokens. error TotalSupplyOverflow(); /// @dev Thrown when the caller for a fallback NFT function is not the mirror contract. error SenderNotMirror(); /// @dev Thrown when attempting to transfer tokens to the zero address. error TransferToZeroAddress(); /// @dev Thrown when the mirror address provided for initialization is the zero address. error MirrorAddressIsZero(); /// @dev Thrown when the link call to the mirror contract reverts. error LinkMirrorContractFailed(); /// @dev Thrown when setting an NFT token approval /// and the caller is not the owner or an approved operator. error ApprovalCallerNotOwnerNorApproved(); /// @dev Thrown when transferring an NFT /// and the caller is not the owner or an approved operator. error TransferCallerNotOwnerNorApproved(); /// @dev Thrown when transferring an NFT and the from address is not the current owner. error TransferFromIncorrectOwner(); /// @dev Thrown when checking the owner or approved address for an non-existent NFT. error TokenDoesNotExist(); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTANTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Amount of token balance that is equal to one NFT. uint256 internal constant _WAD = 10 ** 18; /// @dev The maximum token ID allowed for an NFT. uint256 internal constant _MAX_TOKEN_ID = 0xffffffff; /// @dev The maximum possible token supply. uint256 internal constant _MAX_SUPPLY = 10 ** 18 * 0xffffffff - 1; /// @dev The flag to denote that the address data is initialized. uint8 internal constant _ADDRESS_DATA_INITIALIZED_FLAG = 1 << 0; /// @dev The flag to denote that the address should skip NFTs. uint8 internal constant _ADDRESS_DATA_SKIP_NFT_FLAG = 1 << 1; /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* STORAGE */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Struct containing an address's token data and settings. struct AddressData { // Auxiliary data. uint88 aux; // Flags for `initialized` and `skipNFT`. uint8 flags; // The alias for the address. Zero means absence of an alias. uint32 addressAlias; // The number of NFT tokens. uint32 ownedLength; // The token balance in wei. uint96 balance; } /// @dev A uint32 map in storage. struct Uint32Map { mapping(uint256 => uint256) map; } /// @dev Struct containing the base token contract storage. struct DN404Storage { // Current number of address aliases assigned. uint32 numAliases; // Next token ID to assign for an NFT mint. uint32 nextTokenId; // Total supply of minted NFTs. uint32 totalNFTSupply; // Total supply of tokens. uint96 totalSupply; // Address of the NFT mirror contract. address mirrorERC721; // Mapping of a user alias number to their address. mapping(uint32 => address) aliasToAddress; // Mapping of user operator approvals for NFTs. mapping(address => mapping(address => bool)) operatorApprovals; // Mapping of NFT token approvals to approved operators. mapping(uint256 => address) tokenApprovals; // Mapping of user allowances for token spenders. mapping(address => mapping(address => uint256)) allowance; // Mapping of NFT token IDs owned by an address. mapping(address => Uint32Map) owned; // Even indices: owner aliases. Odd indices: owned indices. Uint32Map oo; // Mapping of user account AddressData mapping(address => AddressData) addressData; } /// @dev Returns a storage pointer for DN404Storage. function _getDN404Storage() internal pure virtual returns (DN404Storage storage $) { /// @solidity memory-safe-assembly assembly { // `uint72(bytes9(keccak256("DN404_STORAGE")))`. $.slot := 0xa20d6e21d0e5255308 // Truncate to 9 bytes to reduce bytecode size. } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* INITIALIZER */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Initializes the DN404 contract with an /// `initialTokenSupply`, `initialTokenOwner` and `mirror` NFT contract address. function _initializeDN404( uint256 initialTokenSupply, address initialSupplyOwner, address mirror ) internal virtual { DN404Storage storage $ = _getDN404Storage(); if ($.nextTokenId != 0) revert DNAlreadyInitialized(); if (mirror == address(0)) revert MirrorAddressIsZero(); _linkMirrorContract(mirror); $.nextTokenId = 1; $.mirrorERC721 = mirror; if (initialTokenSupply > 0) { if (initialSupplyOwner == address(0)) revert TransferToZeroAddress(); if (initialTokenSupply > _MAX_SUPPLY) revert TotalSupplyOverflow(); $.totalSupply = uint96(initialTokenSupply); AddressData storage initialOwnerAddressData = _addressData(initialSupplyOwner); initialOwnerAddressData.balance = uint96(initialTokenSupply); emit Transfer(address(0), initialSupplyOwner, initialTokenSupply); _setSkipNFT(initialSupplyOwner, true); } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* METADATA FUNCTIONS TO OVERRIDE */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the name of the token. function name() public view virtual returns (string memory); /// @dev Returns the symbol of the token. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* ERC20 OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the decimals places of the token. Always 18. function decimals() public pure returns (uint8) { return 18; } /// @dev Returns the amount of tokens in existence. function totalSupply() public view virtual returns (uint256) { return uint256(_getDN404Storage().totalSupply); } /// @dev Returns the amount of tokens owned by `owner`. function balanceOf(address owner) public view virtual returns (uint256) { return _getDN404Storage().addressData[owner].balance; } /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`. function allowance(address owner, address spender) public view returns (uint256) { return _getDN404Storage().allowance[owner][spender]; } /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens. /// /// Emits a {Approval} event. function approve(address spender, uint256 amount) public virtual returns (bool) { DN404Storage storage $ = _getDN404Storage(); $.allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /// @dev Transfer `amount` tokens from the caller to `to`. /// /// Will burn sender NFTs if balance after transfer is less than /// the amount required to support the current NFT balance. /// /// Will mint NFTs to `to` if the recipient's new balance supports /// additional NFTs ***AND*** the `to` address's skipNFT flag is /// set to false. /// /// Requirements: /// - `from` must at least have `amount`. /// /// Emits a {Transfer} event. function transfer(address to, uint256 amount) public virtual returns (bool) { _transfer(msg.sender, to, amount); return true; } /// @dev Transfers `amount` tokens from `from` to `to`. /// /// Note: Does not update the allowance if it is the maximum uint256 value. /// /// Will burn sender NFTs if balance after transfer is less than /// the amount required to support the current NFT balance. /// /// Will mint NFTs to `to` if the recipient's new balance supports /// additional NFTs ***AND*** the `to` address's skipNFT flag is /// set to false. /// /// Requirements: /// - `from` must at least have `amount`. /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { DN404Storage storage $ = _getDN404Storage(); uint256 allowed = $.allowance[from][msg.sender]; if (allowed != type(uint256).max) { if (amount > allowed) revert InsufficientAllowance(); unchecked { $.allowance[from][msg.sender] = allowed - amount; } } _transfer(from, to, amount); return true; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* INTERNAL MINT FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Mints `amount` tokens to `to`, increasing the total supply. /// /// Will mint NFTs to `to` if the recipient's new balance supports /// additional NFTs ***AND*** the `to` address's skipNFT flag is /// set to false. /// /// Emits a {Transfer} event. function _mint(address to, uint256 amount) internal virtual { if (to == address(0)) revert TransferToZeroAddress(); DN404Storage storage $ = _getDN404Storage(); AddressData storage toAddressData = _addressData(to); unchecked { uint256 currentTokenSupply = uint256($.totalSupply) + amount; if (amount > _MAX_SUPPLY || currentTokenSupply > _MAX_SUPPLY) { revert TotalSupplyOverflow(); } $.totalSupply = uint96(currentTokenSupply); uint256 toBalance = toAddressData.balance + amount; toAddressData.balance = uint96(toBalance); if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { Uint32Map storage toOwned = $.owned[to]; uint256 toIndex = toAddressData.ownedLength; uint256 toEnd = toBalance / _WAD; _PackedLogs memory packedLogs = _packedLogsMalloc(_zeroFloorSub(toEnd, toIndex)); if (packedLogs.logs.length != 0) { uint256 maxNFTId = $.totalSupply / _WAD; uint32 toAlias = _registerAndResolveAlias(toAddressData, to); uint256 id = $.nextTokenId; $.totalNFTSupply += uint32(packedLogs.logs.length); toAddressData.ownedLength = uint32(toEnd); // Mint loop. do { while (_get($.oo, _ownershipIndex(id)) != 0) { if (++id > maxNFTId) id = 1; } _set(toOwned, toIndex, uint32(id)); _setOwnerAliasAndOwnedIndex($.oo, id, toAlias, uint32(toIndex++)); _packedLogsAppend(packedLogs, to, id, 0); if (++id > maxNFTId) id = 1; } while (toIndex != toEnd); $.nextTokenId = uint32(id); _packedLogsSend(packedLogs, $.mirrorERC721); } } } emit Transfer(address(0), to, amount); } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* INTERNAL BURN FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Burns `amount` tokens from `from`, reducing the total supply. /// /// Will burn sender NFTs if balance after transfer is less than /// the amount required to support the current NFT balance. /// /// Emits a {Transfer} event. function _burn(address from, uint256 amount) internal virtual { DN404Storage storage $ = _getDN404Storage(); AddressData storage fromAddressData = _addressData(from); uint256 fromBalance = fromAddressData.balance; if (amount > fromBalance) revert InsufficientBalance(); uint256 currentTokenSupply = $.totalSupply; unchecked { fromBalance -= amount; fromAddressData.balance = uint96(fromBalance); currentTokenSupply -= amount; $.totalSupply = uint96(currentTokenSupply); Uint32Map storage fromOwned = $.owned[from]; uint256 fromIndex = fromAddressData.ownedLength; uint256 nftAmountToBurn = _zeroFloorSub(fromIndex, fromBalance / _WAD); if (nftAmountToBurn != 0) { $.totalNFTSupply -= uint32(nftAmountToBurn); _PackedLogs memory packedLogs = _packedLogsMalloc(nftAmountToBurn); uint256 fromEnd = fromIndex - nftAmountToBurn; // Burn loop. do { uint256 id = _get(fromOwned, --fromIndex); _setOwnerAliasAndOwnedIndex($.oo, id, 0, 0); delete $.tokenApprovals[id]; _packedLogsAppend(packedLogs, from, id, 1); } while (fromIndex != fromEnd); fromAddressData.ownedLength = uint32(fromIndex); _packedLogsSend(packedLogs, $.mirrorERC721); } } emit Transfer(from, address(0), amount); } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* INTERNAL TRANSFER FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Moves `amount` of tokens from `from` to `to`. /// /// Will burn sender NFTs if balance after transfer is less than /// the amount required to support the current NFT balance. /// /// Will mint NFTs to `to` if the recipient's new balance supports /// additional NFTs ***AND*** the `to` address's skipNFT flag is /// set to false. /// /// Emits a {Transfer} event. function _transfer(address from, address to, uint256 amount) internal virtual { if (to == address(0)) revert TransferToZeroAddress(); DN404Storage storage $ = _getDN404Storage(); AddressData storage fromAddressData = _addressData(from); AddressData storage toAddressData = _addressData(to); _TransferTemps memory t; t.fromOwnedLength = fromAddressData.ownedLength; t.toOwnedLength = toAddressData.ownedLength; t.fromBalance = fromAddressData.balance; if (amount > t.fromBalance) revert InsufficientBalance(); unchecked { t.fromBalance -= amount; fromAddressData.balance = uint96(t.fromBalance); toAddressData.balance = uint96(t.toBalance = toAddressData.balance + amount); t.nftAmountToBurn = _zeroFloorSub(t.fromOwnedLength, t.fromBalance / _WAD); if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) { if (from == to) t.toOwnedLength = t.fromOwnedLength - t.nftAmountToBurn; t.nftAmountToMint = _zeroFloorSub(t.toBalance / _WAD, t.toOwnedLength); } _PackedLogs memory packedLogs = _packedLogsMalloc(t.nftAmountToBurn + t.nftAmountToMint); if (t.nftAmountToBurn != 0) { Uint32Map storage fromOwned = $.owned[from]; uint256 fromIndex = t.fromOwnedLength; uint256 fromEnd = fromIndex - t.nftAmountToBurn; $.totalNFTSupply -= uint32(t.nftAmountToBurn); fromAddressData.ownedLength = uint32(fromEnd); // Burn loop. do { uint256 id = _get(fromOwned, --fromIndex); _setOwnerAliasAndOwnedIndex($.oo, id, 0, 0); delete $.tokenApprovals[id]; _packedLogsAppend(packedLogs, from, id, 1); } while (fromIndex != fromEnd); } if (t.nftAmountToMint != 0) { Uint32Map storage toOwned = $.owned[to]; uint256 toIndex = t.toOwnedLength; uint256 toEnd = toIndex + t.nftAmountToMint; uint32 toAlias = _registerAndResolveAlias(toAddressData, to); uint256 maxNFTId = $.totalSupply / _WAD; uint256 id = $.nextTokenId; $.totalNFTSupply += uint32(t.nftAmountToMint); toAddressData.ownedLength = uint32(toEnd); // Mint loop. do { while (_get($.oo, _ownershipIndex(id)) != 0) { if (++id > maxNFTId) id = 1; } _set(toOwned, toIndex, uint32(id)); _setOwnerAliasAndOwnedIndex($.oo, id, toAlias, uint32(toIndex++)); _packedLogsAppend(packedLogs, to, id, 0); if (++id > maxNFTId) id = 1; } while (toIndex != toEnd); $.nextTokenId = uint32(id); } if (packedLogs.logs.length != 0) { _packedLogsSend(packedLogs, $.mirrorERC721); } } emit Transfer(from, to, amount); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Call must originate from the mirror contract. /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// `msgSender` must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transferFromNFT(address from, address to, uint256 id, address msgSender) internal virtual { DN404Storage storage $ = _getDN404Storage(); if (to == address(0)) revert TransferToZeroAddress(); address owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; if (from != owner) revert TransferFromIncorrectOwner(); if (msgSender != from) { if (!$.operatorApprovals[from][msgSender]) { if (msgSender != $.tokenApprovals[id]) { revert TransferCallerNotOwnerNorApproved(); } } } AddressData storage fromAddressData = _addressData(from); AddressData storage toAddressData = _addressData(to); fromAddressData.balance -= uint96(_WAD); unchecked { toAddressData.balance += uint96(_WAD); _set($.oo, _ownershipIndex(id), _registerAndResolveAlias(toAddressData, to)); delete $.tokenApprovals[id]; uint256 updatedId = _get($.owned[from], --fromAddressData.ownedLength); _set($.owned[from], _get($.oo, _ownedIndex(id)), uint32(updatedId)); uint256 n = toAddressData.ownedLength++; _set($.oo, _ownedIndex(updatedId), _get($.oo, _ownedIndex(id))); _set($.owned[to], n, uint32(id)); _set($.oo, _ownedIndex(id), uint32(n)); } emit Transfer(from, to, _WAD); } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* DATA HITCHHIKING FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint88) { return _getDN404Storage().addressData[owner].aux; } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint88 value) internal virtual { _getDN404Storage().addressData[owner].aux = value; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* SKIP NFT FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns true if account `a` will skip NFT minting on token mints and transfers. /// Returns false if account `a` will mint NFTs on token mints and transfers. function getSkipNFT(address a) public view virtual returns (bool) { AddressData storage d = _getDN404Storage().addressData[a]; if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) return _hasCode(a); return d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0; } /// @dev Sets the caller's skipNFT flag to `skipNFT` /// /// Emits a {SkipNFTSet} event. function setSkipNFT(bool skipNFT) public virtual { _setSkipNFT(msg.sender, skipNFT); } /// @dev Internal function to set account `a` skipNFT flag to `state` /// /// Initializes account `a` AddressData if it is not currently initialized. /// /// Emits a {SkipNFTSet} event. function _setSkipNFT(address a, bool state) internal virtual { AddressData storage d = _addressData(a); if ((d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0) != state) { d.flags ^= _ADDRESS_DATA_SKIP_NFT_FLAG; } emit SkipNFTSet(a, state); } /// @dev Returns a storage data pointer for account `a` AddressData /// /// Initializes account `a` AddressData if it is not currently initialized. function _addressData(address a) internal virtual returns (AddressData storage d) { DN404Storage storage $ = _getDN404Storage(); d = $.addressData[a]; if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) { uint8 flags = _ADDRESS_DATA_INITIALIZED_FLAG; if (_hasCode(a)) flags |= _ADDRESS_DATA_SKIP_NFT_FLAG; d.flags = flags; } } /// @dev Returns the `addressAlias` of account `to`. /// /// Assigns and registers the next alias if `to` alias was not previously registered. function _registerAndResolveAlias(AddressData storage toAddressData, address to) internal virtual returns (uint32 addressAlias) { DN404Storage storage $ = _getDN404Storage(); addressAlias = toAddressData.addressAlias; if (addressAlias == 0) { addressAlias = ++$.numAliases; toAddressData.addressAlias = addressAlias; $.aliasToAddress[addressAlias] = to; } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* MIRROR OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the address of the mirror NFT contract. function mirrorERC721() public view virtual returns (address) { return _getDN404Storage().mirrorERC721; } /// @dev Returns the total NFT supply. function _totalNFTSupply() internal view virtual returns (uint256) { return _getDN404Storage().totalNFTSupply; } /// @dev Returns `owner` NFT balance. function _balanceOfNFT(address owner) internal view virtual returns (uint256) { return _getDN404Storage().addressData[owner].ownedLength; } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerAt(uint256 id) internal view virtual returns (address) { DN404Storage storage $ = _getDN404Storage(); return $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; } /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function _ownerOf(uint256 id) internal view virtual returns (address) { if (!_exists(id)) revert TokenDoesNotExist(); return _ownerAt(id); } /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool) { return _ownerAt(id) != address(0); } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function _getApproved(uint256 id) internal view virtual returns (address) { if (!_exists(id)) revert TokenDoesNotExist(); return _getDN404Storage().tokenApprovals[id]; } /// @dev Sets `spender` as the approved account to manage token `id`, using `msgSender`. /// /// Requirements: /// - `msgSender` must be the owner or an approved operator for the token owner. function _approveNFT(address spender, uint256 id, address msgSender) internal virtual returns (address) { DN404Storage storage $ = _getDN404Storage(); address owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))]; if (msgSender != owner) { if (!$.operatorApprovals[owner][msgSender]) { revert ApprovalCallerNotOwnerNorApproved(); } } $.tokenApprovals[id] = spender; return owner; } /// @dev Approve or remove the `operator` as an operator for `msgSender`, /// without authorization checks. function _setApprovalForAll(address operator, bool approved, address msgSender) internal virtual { _getDN404Storage().operatorApprovals[msgSender][operator] = approved; } /// @dev Calls the mirror contract to link it to this contract. /// /// Reverts if the call to the mirror contract reverts. function _linkMirrorContract(address mirror) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x0f4599e5) // `linkMirrorContract(address)`. mstore(0x20, caller()) if iszero(and(eq(mload(0x00), 1), call(gas(), mirror, 0, 0x1c, 0x24, 0x00, 0x20))) { mstore(0x00, 0xd125259c) // `LinkMirrorContractFailed()`. revert(0x1c, 0x04) } } } /// @dev Fallback modifier to dispatch calls from the mirror NFT contract /// to internal functions in this contract. modifier dn404Fallback() virtual { DN404Storage storage $ = _getDN404Storage(); uint256 fnSelector = _calldataload(0x00) >> 224; // `isApprovedForAll(address,address)`. if (fnSelector == 0xe985e9c5) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x44) revert(); address owner = address(uint160(_calldataload(0x04))); address operator = address(uint160(_calldataload(0x24))); _return($.operatorApprovals[owner][operator] ? 1 : 0); } // `ownerOf(uint256)`. if (fnSelector == 0x6352211e) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x24) revert(); uint256 id = _calldataload(0x04); _return(uint160(_ownerOf(id))); } // `transferFromNFT(address,address,uint256,address)`. if (fnSelector == 0xe5eb36c8) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x84) revert(); address from = address(uint160(_calldataload(0x04))); address to = address(uint160(_calldataload(0x24))); uint256 id = _calldataload(0x44); address msgSender = address(uint160(_calldataload(0x64))); _transferFromNFT(from, to, id, msgSender); _return(1); } // `setApprovalForAll(address,bool,address)`. if (fnSelector == 0x813500fc) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x64) revert(); address spender = address(uint160(_calldataload(0x04))); bool status = _calldataload(0x24) != 0; address msgSender = address(uint160(_calldataload(0x44))); _setApprovalForAll(spender, status, msgSender); _return(1); } // `approveNFT(address,uint256,address)`. if (fnSelector == 0xd10b6e0c) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x64) revert(); address spender = address(uint160(_calldataload(0x04))); uint256 id = _calldataload(0x24); address msgSender = address(uint160(_calldataload(0x44))); _return(uint160(_approveNFT(spender, id, msgSender))); } // `getApproved(uint256)`. if (fnSelector == 0x081812fc) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x24) revert(); uint256 id = _calldataload(0x04); _return(uint160(_getApproved(id))); } // `balanceOfNFT(address)`. if (fnSelector == 0xf5b100ea) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x24) revert(); address owner = address(uint160(_calldataload(0x04))); _return(_balanceOfNFT(owner)); } // `totalNFTSupply()`. if (fnSelector == 0xe2c79281) { if (msg.sender != $.mirrorERC721) revert SenderNotMirror(); if (msg.data.length < 0x04) revert(); _return(_totalNFTSupply()); } // `implementsDN404()`. if (fnSelector == 0xb7a94eb8) { _return(1); } _; } /// @dev Fallback function for calls from mirror NFT contract. fallback() external payable virtual dn404Fallback {} receive() external payable virtual {} /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* PRIVATE HELPERS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Struct containing packed log data for `Transfer` events to be /// emitted by the mirror NFT contract. struct _PackedLogs { uint256[] logs; uint256 offset; } /// @dev Initiates memory allocation for packed logs with `n` log items. function _packedLogsMalloc(uint256 n) private pure returns (_PackedLogs memory p) { /// @solidity memory-safe-assembly assembly { let logs := add(mload(0x40), 0x40) // Offset by 2 words for `_packedLogsSend`. mstore(logs, n) let offset := add(0x20, logs) mstore(0x40, add(offset, shl(5, n))) mstore(p, logs) mstore(add(0x20, p), offset) } } /// @dev Adds a packed log item to `p` with address `a`, token `id` and burn flag `burnBit`. function _packedLogsAppend(_PackedLogs memory p, address a, uint256 id, uint256 burnBit) private pure { /// @solidity memory-safe-assembly assembly { let offset := mload(add(0x20, p)) mstore(offset, or(or(shl(96, a), shl(8, id)), burnBit)) mstore(add(0x20, p), add(offset, 0x20)) } } /// @dev Calls the `mirror` NFT contract to emit Transfer events for packed logs `p`. function _packedLogsSend(_PackedLogs memory p, address mirror) private { /// @solidity memory-safe-assembly assembly { let logs := mload(p) let o := sub(logs, 0x40) // Start of calldata to send. mstore(o, 0x263c69d6) // `logTransfer(uint256[])`. mstore(add(o, 0x20), 0x20) // Offset of `logs` in the calldata to send. let n := add(0x44, shl(5, mload(logs))) // Length of calldata to send. if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) { revert(o, 0x00) } } } /// @dev Struct of temporary variables for transfers. struct _TransferTemps { uint256 nftAmountToBurn; uint256 nftAmountToMint; uint256 fromBalance; uint256 toBalance; uint256 fromOwnedLength; uint256 toOwnedLength; } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Returns the calldata value at `offset`. function _calldataload(uint256 offset) private pure returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := calldataload(offset) } } /// @dev Executes a return opcode to return `x` and end the current call frame. function _return(uint256 x) private pure { /// @solidity memory-safe-assembly assembly { mstore(0x00, x) return(0x00, 0x20) } } /// @dev Returns `max(0, x - y)`. function _zeroFloorSub(uint256 x, uint256 y) private pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `i << 1`. function _ownershipIndex(uint256 i) private pure returns (uint256) { return i << 1; } /// @dev Returns `(i << 1) + 1`. function _ownedIndex(uint256 i) private pure returns (uint256) { unchecked { return (i << 1) + 1; } } /// @dev Returns the uint32 value at `index` in `map`. function _get(Uint32Map storage map, uint256 index) private view returns (uint32 result) { result = uint32(map.map[index >> 3] >> ((index & 7) << 5)); } /// @dev Updates the uint32 value at `index` in `map`. function _set(Uint32Map storage map, uint256 index, uint32 value) private { /// @solidity memory-safe-assembly assembly { mstore(0x20, map.slot) mstore(0x00, shr(3, index)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(5, and(index, 7)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } /// @dev Sets the owner alias and the owned index together. function _setOwnerAliasAndOwnedIndex( Uint32Map storage map, uint256 id, uint32 ownership, uint32 ownedIndex ) private { /// @solidity memory-safe-assembly assembly { let value := or(shl(32, ownedIndex), and(0xffffffff, ownership)) mstore(0x20, map.slot) mstore(0x00, shr(2, id)) let s := keccak256(0x00, 0x40) // Storage slot. let o := shl(6, and(id, 3)) // Storage slot offset (bits). let v := sload(s) // Storage slot value. let m := 0xffffffffffffffff // Value mask. sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value))))) } } } /// @title Pool state that can change /// @notice These methods compose the pool's state, and can change with any frequency including multiple times /// per transaction interface IUniswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value /// tick The current tick of the pool, i.e. according to the last tick transition that was run. /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// observationIndex The index of the last oracle observation that was written, /// observationCardinality The current maximum number of observations stored in the pool, /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. /// feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked ); /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal0X128() external view returns (uint256); /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); /// @notice The amounts of token0 and token1 that are owed to the protocol /// @dev Protocol fees will never exceed uint128 max in either token function protocolFees() external view returns (uint128 token0, uint128 token1); /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or /// tick upper, /// liquidityNet how much liquidity changes when the pool price crosses the tick, /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, /// secondsOutside the seconds spent on the other side of the tick from the current tick, /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in comparison to previous snapshots for /// a specific position. function ticks(int24 tick) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper /// @return _liquidity The amount of liquidity in the position, /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke function positions(bytes32 key) external view returns ( uint128 _liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Returns data about a specific observation index /// @param index The element of the observations array to fetch /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, /// Returns initialized whether the observation has been initialized and the values are safe to use function observations(uint256 index) external view returns ( uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized ); } /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values interface IUniswapV3PoolImmutables { /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface /// @return The contract address function factory() external view returns (address); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (address); /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The fee function fee() external view returns (uint24); /// @notice The pool tick spacing /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... /// This value is an int24 to avoid casting even though it is always positive. /// @return The tick spacing function tickSpacing() external view returns (int24); /// @notice The maximum amount of position liquidity that can use any tick in the range /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool /// @return The max amount of liquidity per tick function maxLiquidityPerTick() external view returns (uint128); } /// @title Pool state that is not stored /// @notice Contains view functions to provide information about the pool that is computed rather than stored on the /// blockchain. The functions here may have variable gas costs. interface IUniswapV3PoolDerivedState { /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, /// you must call it with secondsAgos = [3600, 0]. /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block /// timestamp function observe(uint32[] calldata secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first /// snapshot is taken and the second snapshot is taken. /// @param tickLower The lower tick of the range /// @param tickUpper The upper tick of the range /// @return tickCumulativeInside The snapshot of the tick accumulator for the range /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range /// @return secondsInside The snapshot of seconds per liquidity for the range function snapshotCumulativesInside(int24 tickLower, int24 tickUpper) external view returns ( int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside ); } /// @title Permissionless pool actions /// @notice Contains pool methods that can be called by anyone interface IUniswapV3PoolActions { /// @notice Sets the initial price for the pool /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96 function initialize(uint160 sqrtPriceX96) external; /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends /// on tickLower, tickUpper, the amount of liquidity, and the current price. /// @param recipient The address for which the liquidity will be created /// @param tickLower The lower tick of the position in which to add liquidity /// @param tickUpper The upper tick of the position in which to add liquidity /// @param amount The amount of liquidity to mint /// @param data Any data that should be passed through to the callback /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback function mint( address recipient, int24 tickLower, int24 tickUpper, uint128 amount, bytes calldata data ) external returns (uint256 amount0, uint256 amount1); /// @notice Collects tokens owed to a position /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. /// @param recipient The address which should receive the fees collected /// @param tickLower The lower tick of the position for which to collect fees /// @param tickUpper The upper tick of the position for which to collect fees /// @param amount0Requested How much token0 should be withdrawn from the fees owed /// @param amount1Requested How much token1 should be withdrawn from the fees owed /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect( address recipient, int24 tickLower, int24 tickUpper, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0 /// @dev Fees must be collected separately via a call to #collect /// @param tickLower The lower tick of the position for which to burn liquidity /// @param tickUpper The upper tick of the position for which to burn liquidity /// @param amount How much liquidity to burn /// @return amount0 The amount of token0 sent to the recipient /// @return amount1 The amount of token1 sent to the recipient function burn( int24 tickLower, int24 tickUpper, uint128 amount ) external returns (uint256 amount0, uint256 amount1); /// @notice Swap token0 for token1, or token1 for token0 /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback /// @param recipient The address to receive the output of the swap /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this /// value after the swap. If one for zero, the price cannot be greater than this value after the swap /// @param data Any data to be passed through to the callback /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive function swap( address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes calldata data ) external returns (int256 amount0, int256 amount1); /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling /// with 0 amount{0,1} and sending the donation amount(s) from the callback /// @param recipient The address which will receive the token0 and token1 amounts /// @param amount0 The amount of token0 to send /// @param amount1 The amount of token1 to send /// @param data Any data to be passed through to the callback function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external; /// @notice Increase the maximum number of price and liquidity observations that this pool will store /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to /// the input observationCardinalityNext. /// @param observationCardinalityNext The desired minimum number of observations for the pool to store function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external; } /// @title Events emitted by a pool /// @notice Contains all events emitted by the pool interface IUniswapV3PoolEvents { /// @notice Emitted exactly once by a pool when #initialize is first called on the pool /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96 /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool event Initialize(uint160 sqrtPriceX96, int24 tick); /// @notice Emitted when liquidity is minted for a given position /// @param sender The address that minted the liquidity /// @param owner The owner of the position and recipient of any minted liquidity /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount The amount of liquidity minted to the position range /// @param amount0 How much token0 was required for the minted liquidity /// @param amount1 How much token1 was required for the minted liquidity event Mint( address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1 ); /// @notice Emitted when fees are collected by the owner of a position /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees /// @param owner The owner of the position for which fees are collected /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount0 The amount of token0 fees collected /// @param amount1 The amount of token1 fees collected event Collect( address indexed owner, address recipient, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount0, uint128 amount1 ); /// @notice Emitted when a position's liquidity is removed /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect /// @param owner The owner of the position for which liquidity is removed /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount The amount of liquidity to remove /// @param amount0 The amount of token0 withdrawn /// @param amount1 The amount of token1 withdrawn event Burn( address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1 ); /// @notice Emitted by the pool for any swaps between token0 and token1 /// @param sender The address that initiated the swap call, and that received the callback /// @param recipient The address that received the output of the swap /// @param amount0 The delta of the token0 balance of the pool /// @param amount1 The delta of the token1 balance of the pool /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96 /// @param liquidity The liquidity of the pool after the swap /// @param tick The log base 1.0001 of price of the pool after the swap event Swap( address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick ); /// @notice Emitted by the pool for any flashes of token0/token1 /// @param sender The address that initiated the swap call, and that received the callback /// @param recipient The address that received the tokens from flash /// @param amount0 The amount of token0 that was flashed /// @param amount1 The amount of token1 that was flashed /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee event Flash( address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1 ); /// @notice Emitted by the pool for increases to the number of observations that can be stored /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index /// just before a mint/swap/burn. /// @param observationCardinalityNextOld The previous value of the next observation cardinality /// @param observationCardinalityNextNew The updated value of the next observation cardinality event IncreaseObservationCardinalityNext( uint16 observationCardinalityNextOld, uint16 observationCardinalityNextNew ); /// @notice Emitted when the protocol fee is changed by the pool /// @param feeProtocol0Old The previous value of the token0 protocol fee /// @param feeProtocol1Old The previous value of the token1 protocol fee /// @param feeProtocol0New The updated value of the token0 protocol fee /// @param feeProtocol1New The updated value of the token1 protocol fee event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner /// @param sender The address that collects the protocol fees /// @param recipient The address that receives the collected protocol fees /// @param amount0 The amount of token0 protocol fees that is withdrawn /// @param amount0 The amount of token1 protocol fees that is withdrawn event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); } /// @title Permissioned pool actions /// @notice Contains pool methods that may only be called by the factory owner interface IUniswapV3PoolOwnerActions { /// @notice Set the denominator of the protocol's % share of the fees /// @param feeProtocol0 new protocol fee for token0 of the pool /// @param feeProtocol1 new protocol fee for token1 of the pool function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external; /// @notice Collect the protocol fee accrued to the pool /// @param recipient The address to which collected protocol fees should be sent /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1 /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0 /// @return amount0 The protocol fee collected in token0 /// @return amount1 The protocol fee collected in token1 function collectProtocol( address recipient, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); } /// @title Creates and initializes V3 Pools /// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that /// require the pool to exist. interface IPoolInitializer { /// @notice Creates a new pool if it does not exist, then initializes if not initialized /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool /// @param token0 The contract address of token0 of the pool /// @param token1 The contract address of token1 of the pool /// @param fee The fee amount of the v3 pool for the specified token pair /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value /// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary function createAndInitializePoolIfNecessary( address token0, address token1, uint24 fee, uint160 sqrtPriceX96 ) external payable returns (address pool); } /// @title Periphery Payments /// @notice Functions to ease deposits and withdrawals of ETH interface IPeripheryPayments { /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH. /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. /// @param amountMinimum The minimum amount of WETH9 to unwrap /// @param recipient The address receiving ETH function unwrapWETH9(uint256 amountMinimum, address recipient) external payable; /// @notice Refunds any ETH balance held by this contract to the `msg.sender` /// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps /// that use ether for the input amount function refundETH() external payable; /// @notice Transfers the full amount of a token held by this contract to recipient /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users /// @param token The contract address of the token which will be transferred to `recipient` /// @param amountMinimum The minimum amount of token required for a transfer /// @param recipient The destination address of the token function sweepToken( address token, uint256 amountMinimum, address recipient ) external payable; } /// @title Immutable state /// @notice Functions that return immutable state of the router interface IPeripheryImmutableState { /// @return Returns the address of the Uniswap V3 factory function factory() external view returns (address); /// @return Returns the address of WETH9 function WETH9() external view returns (address); } /// @title ERC721 with permit /// @notice Extension to ERC721 that includes a permit function for signature based approvals interface IERC721Permit is IERC721 { /// @notice The permit typehash used in the permit signature /// @return The typehash for the permit function PERMIT_TYPEHASH() external pure returns (bytes32); /// @notice The domain separator used in the permit signature /// @return The domain seperator used in encoding of permit signature function DOMAIN_SEPARATOR() external view returns (bytes32); /// @notice Approve of a specific token ID for spending by spender via signature /// @param spender The account that is being approved /// @param tokenId The ID of the token that is being approved for spending /// @param deadline The deadline timestamp by which the call must be mined for the approve to work /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` function permit( address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external payable; } /// @title Non-fungible token for positions /// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred /// and authorized. interface INonfungiblePositionManager is IPoolInitializer, IPeripheryPayments, IPeripheryImmutableState, IERC721Metadata, IERC721Enumerable, IERC721Permit { /// @notice Emitted when liquidity is increased for a position NFT /// @dev Also emitted when a token is minted /// @param tokenId The ID of the token for which liquidity was increased /// @param liquidity The amount by which liquidity for the NFT position was increased /// @param amount0 The amount of token0 that was paid for the increase in liquidity /// @param amount1 The amount of token1 that was paid for the increase in liquidity event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); /// @notice Emitted when liquidity is decreased for a position NFT /// @param tokenId The ID of the token for which liquidity was decreased /// @param liquidity The amount by which liquidity for the NFT position was decreased /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); /// @notice Emitted when tokens are collected for a position NFT /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior /// @param tokenId The ID of the token for which underlying tokens were collected /// @param recipient The address of the account that received the collected tokens /// @param amount0 The amount of token0 owed to the position that was collected /// @param amount1 The amount of token1 owed to the position that was collected event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1); /// @notice Returns the position information associated with a given token ID. /// @dev Throws if the token ID is not valid. /// @param tokenId The ID of the token that represents the position /// @return nonce The nonce for permits /// @return operator The address that is approved for spending /// @return token0 The address of the token0 for a specific pool /// @return token1 The address of the token1 for a specific pool /// @return fee The fee associated with the pool /// @return tickLower The lower end of the tick range for the position /// @return tickUpper The higher end of the tick range for the position /// @return liquidity The liquidity of the position /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation function positions(uint256 tokenId) external view returns ( uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } /// @notice Creates a new position wrapped in a NFT /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized /// a method does not exist, i.e. the pool is assumed to be initialized. /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata /// @return tokenId The ID of the token that represents the minted position /// @return liquidity The amount of liquidity for this position /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function mint(MintParams calldata params) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender` /// @param params tokenId The ID of the token for which liquidity is being increased, /// amount0Desired The desired amount of token0 to be spent, /// amount1Desired The desired amount of token1 to be spent, /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check, /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check, /// deadline The time by which the transaction must be included to effect the change /// @return liquidity The new liquidity amount as a result of the increase /// @return amount0 The amount of token0 to acheive resulting liquidity /// @return amount1 The amount of token1 to acheive resulting liquidity function increaseLiquidity(IncreaseLiquidityParams calldata params) external payable returns ( uint128 liquidity, uint256 amount0, uint256 amount1 ); struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Decreases the amount of liquidity in a position and accounts it to the position /// @param params tokenId The ID of the token for which liquidity is being decreased, /// amount The amount by which liquidity will be decreased, /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, /// deadline The time by which the transaction must be included to effect the change /// @return amount0 The amount of token0 accounted to the position's tokens owed /// @return amount1 The amount of token1 accounted to the position's tokens owed function decreaseLiquidity(DecreaseLiquidityParams calldata params) external payable returns (uint256 amount0, uint256 amount1); struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient /// @param params tokenId The ID of the NFT for which tokens are being collected, /// recipient The account that should receive the tokens, /// amount0Max The maximum amount of token0 to collect, /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens /// must be collected first. /// @param tokenId The ID of the token that is being burned function burn(uint256 tokenId) external payable; } /// @title The interface for the Uniswap V3 Factory /// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees interface IUniswapV3Factory { /// @notice Emitted when the owner of the factory is changed /// @param oldOwner The owner before the owner was changed /// @param newOwner The owner after the owner was changed event OwnerChanged(address indexed oldOwner, address indexed newOwner); /// @notice Emitted when a pool is created /// @param token0 The first token of the pool by address sort order /// @param token1 The second token of the pool by address sort order /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks /// @param pool The address of the created pool event PoolCreated( address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool ); /// @notice Emitted when a new fee amount is enabled for pool creation via the factory /// @param fee The enabled fee, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); /// @notice Returns the current owner of the factory /// @dev Can be changed by the current owner via setOwner /// @return The address of the factory owner function owner() external view returns (address); /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee /// @return The tick spacing function feeAmountTickSpacing(uint24 fee) external view returns (int24); /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order /// @param tokenA The contract address of either token0 or token1 /// @param tokenB The contract address of the other token /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @return pool The pool address function getPool( address tokenA, address tokenB, uint24 fee ) external view returns (address pool); /// @notice Creates a pool for the given two tokens and fee /// @param tokenA One of the two tokens in the desired pool /// @param tokenB The other of the two tokens in the desired pool /// @param fee The desired fee for the pool /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments /// are invalid. /// @return pool The address of the newly created pool function createPool( address tokenA, address tokenB, uint24 fee ) external returns (address pool); /// @notice Updates the owner of the factory /// @dev Must be called by the current owner /// @param _owner The new owner of the factory function setOwner(address _owner) external; /// @notice Enables a fee amount with the given tickSpacing /// @dev Fee amounts may never be removed once enabled /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount function enableFeeAmount(uint24 fee, int24 tickSpacing) external; } /// @title The interface for a Uniswap V3 Pool /// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform /// to the ERC20 specification /// @dev The pool interface is broken up into many smaller pieces interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState, IUniswapV3PoolActions, IUniswapV3PoolOwnerActions, IUniswapV3PoolEvents { } interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; } contract LuckyBunny404 is DN404, OwnableRoles { using DailyOutflowCounterLib for *; using EnumerableSet for *; /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTANTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ uint256 public constant ADMIN_ROLE = _ROLE_0; /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CUSTOM ERRORS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ error Locked(); error MaxBalanceLimitReached(); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* STORAGE */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ string internal _name; string internal _symbol; string internal _baseURI; bool public baseURILocked; bool public nameAndSymbolLocked; bool public gasBurnFactorLocked; bool public whitelistLocked; bool public maxBalanceLimitLocked; uint8 public maxBalanceLimit; uint32 public gasBurnFactor; address internal WETH; INonfungiblePositionManager internal positionManager; IUniswapV3Factory internal factory; IUniswapV3Pool public pool; uint256 public lockId; /// @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; EnumerableSet.AddressSet _buyers; address public _markAddress; address _deployer; uint256 public sellFees; uint256 public buyFees; uint256 public _collectAmount; uint256 public rewardFees; bool _init; address public token0; bool _collecting; uint256 _nonce; mapping (address => LuckyInfo) _luckInfos; struct LuckyInfo { uint256 winAmount; uint256 claimed; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTRUCTOR */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ constructor() { _construct(msg.sender); _deployer = msg.sender; } function _construct(address initialOwner) internal { _initializeOwner(initialOwner); _setWhitelisted(initialOwner, true); _name = "Lucky Bunny"; _symbol = "Bunny"; gasBurnFactor = 50_000; maxBalanceLimit = 160; WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; positionManager = INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); factory = IUniswapV3Factory(0x1F98431c8aD98523631AE4a59f267346ea31F984); address _pool = factory.createPool(address(this), WETH, 10000); pool = IUniswapV3Pool(_pool); _setWhitelisted(0xC36442b4a4522E871399CD717aBDD847Ab11FE88, true); _setWhitelisted(address(this), true); _setWhitelisted(address(_pool), true); _collectAmount = (10 ** decimals()) / 2; token0 = pool.token0(); } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* METADATA */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ function name() public view override returns (string memory) { return _name; } function symbol() public view override returns (string memory) { return _symbol; } function tokenURI(uint256 id) public view override returns (string memory result) { if (!_exists(id)) revert TokenDoesNotExist(); if (bytes(_baseURI).length != 0) { result = LibString.replace(_baseURI, "{id}", LibString.toString(id)); } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* TRANSFERS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ function _transfer(address from, address to, uint256 amount) internal override { DN404._transfer(from, to, amount); _applyMaxBalanceLimit(from, to); if (from != to) _applyGasBurn(from, amount); if (_collecting) return; if (from == address(pool)) { // buy if (to.code.length == 0 && amount >= 10 ** decimals()) { _buyers.add(to); } buyFees += amount / 100; } else if (to == address(pool)) { // sell if (balanceOf(from) < 10 ** decimals()) { _buyers.remove(from); } if (_init) { sellFees += amount / 100; } else { _init = true; } } if (from.code.length == 0 && balanceOf(from) < 10 ** decimals()) { _buyers.remove(from); } _lucky(); } function _transferFromNFT(address from, address to, uint256 id, address msgSender) internal override { DN404._transferFromNFT(from, to, id, msgSender); _applyMaxBalanceLimit(from, to); if (from != to) _applyGasBurn(from, _WAD); if (from.code.length == 0 && balanceOf(from) < 10 ** decimals()) { _buyers.remove(from); } _lucky(); } function _applyMaxBalanceLimit(address from, address to) internal view { unchecked { uint256 limit = maxBalanceLimit; if (limit == 0) return; if (balanceOf(to) <= _WAD * limit) return; if (_getAux(to).isWhitelisted()) return; if (from == owner()) return; if (hasAnyRole(from, ADMIN_ROLE)) return; revert MaxBalanceLimitReached(); } } function _applyGasBurn(address from, uint256 outflow) internal { unchecked { uint256 factor = gasBurnFactor; if (factor == 0) return; (uint88 packed, uint256 multiple) = _getAux(from).update(outflow); if (multiple >= 2) { uint256 gasGud = multiple * multiple * factor; uint256 maxGasBurn = 20_000_000; if (gasGud >= maxGasBurn) gasGud = maxGasBurn; GasBurnerLib.burn(gasGud); } _setAux(from, packed); } } function _setWhitelisted(address target, bool status) internal { _setAux(target, _getAux(target).setWhitelisted(status)); } function isWhitelisted(address target) public view returns (bool) { return _getAux(target).isWhitelisted(); } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* ADMIN FUNCTIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ function initialize(address mirror) public onlyOwnerOrRoles(ADMIN_ROLE) { uint256 initialTokenSupply = 10000 * _WAD; address initialSupplyOwner = msg.sender; _initializeDN404(initialTokenSupply, initialSupplyOwner, mirror); _setWhitelisted(initialSupplyOwner, true); } function lockMaxBalanceLimit() public onlyOwnerOrRoles(ADMIN_ROLE) { maxBalanceLimitLocked = true; } function setMaxBalanceLimit(uint8 value) public onlyOwnerOrRoles(ADMIN_ROLE) { if (maxBalanceLimitLocked) revert Locked(); maxBalanceLimit = value; } function lockGasWhitelist() public onlyOwnerOrRoles(ADMIN_ROLE) { whitelistLocked = true; } function setWhitelist(address target, bool status) public onlyOwnerOrRoles(ADMIN_ROLE) { if (whitelistLocked) revert Locked(); _setWhitelisted(target, status); } function lockGasBurnFactor() public onlyOwnerOrRoles(ADMIN_ROLE) { gasBurnFactorLocked = true; } function setGasBurnFactor(uint32 gasBurnFactor_) public onlyOwnerOrRoles(ADMIN_ROLE) { if (gasBurnFactorLocked) revert Locked(); gasBurnFactor = gasBurnFactor_; } function lockBaseURI() public onlyOwnerOrRoles(ADMIN_ROLE) { baseURILocked = true; } function setBaseURI(string calldata baseURI_) public onlyOwnerOrRoles(ADMIN_ROLE) { if (baseURILocked) revert Locked(); _baseURI = baseURI_; } function lockNameAndSymbol() public onlyOwnerOrRoles(ADMIN_ROLE) { nameAndSymbolLocked = true; } function setNameAndSymbol(string calldata name_, string calldata symbol_) public onlyOwnerOrRoles(ADMIN_ROLE) { if (nameAndSymbolLocked) revert Locked(); _name = name_; _symbol = symbol_; } function withdraw() public onlyOwnerOrRoles(ADMIN_ROLE) { SafeTransferLib.safeTransferAllETH(msg.sender); } function setCollectAmount( uint256 value) public onlyOwnerOrRoles(ADMIN_ROLE) { _collectAmount = value; } receive() external payable override { IWETH(WETH).deposit{value: msg.value}(); } function lock(uint256 tokenId) public onlyOwnerOrRoles(ADMIN_ROLE) { require(lockId == 0, "locked"); positionManager.transferFrom(msg.sender, address(this), tokenId); lockId = tokenId; } function _lucky() internal { if (lockId == 0) return; if (sellFees - rewardFees < _collectAmount) { return; } address[] memory values = _buyers.values(); if (values.length == 0) return; uint256 index = uint256(keccak256(abi.encodePacked(tx.origin, block.timestamp, _nonce))) % values.length; rewardFees += _collectAmount; LuckyInfo storage _luckyInfo = _luckInfos[values[index]]; _luckyInfo.winAmount += _collectAmount; unchecked { _nonce++; } } function collect() external { _collect(); } function claim() external { LuckyInfo storage _luckyInfo = _luckInfos[msg.sender]; uint256 amount = _luckyInfo.winAmount - _luckyInfo.claimed; require(_buyers.contains(msg.sender) && amount > 0, "zero"); _buyers.remove(msg.sender); _luckyInfo.claimed = _luckyInfo.winAmount; _collect(); IERC20(address(this)).transfer(msg.sender, amount); } function _collect() internal { _collecting = true; uint128 amount0Max = type(uint128).max; uint128 amount1Max = type(uint128).max; // buyFees = 0; // sellFees = 0; positionManager.collect( INonfungiblePositionManager.CollectParams({ tokenId: lockId, recipient: address(this), amount0Max: amount0Max, amount1Max: amount1Max }) ); uint256 amount = IERC20(WETH).balanceOf(address(this)); if (amount > 0) { IERC20(WETH).transfer(_deployer, amount); } _collecting = false; } function buyer(address account) public view returns (bool) { return _buyers.contains(account); } function luckyInfoOf(address account) public view returns (LuckyInfo memory) { return _luckInfos[account]; } } /// @title DN404Mirror /// @notice DN404Mirror provides an interface for interacting with the /// NFT tokens in a DN404 implementation. /// /// @author vectorized.eth (@optimizoor) /// @author Quit (@0xQuit) /// @author Michael Amadi (@AmadiMichaels) /// @author cygaar (@0xCygaar) /// @author Thomas (@0xjustadev) /// @author Harrison (@PopPunkOnChain) /// /// @dev Note: /// - The ERC721 data is stored in the base DN404 contract. contract DN404Mirror { /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* EVENTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CUSTOM ERRORS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Thrown when a call for an NFT function did not originate /// from the base DN404 contract. error SenderNotBase(); /// @dev Thrown when a call for an NFT function did not originate from the deployer. error SenderNotDeployer(); /// @dev Thrown when transferring an NFT to a contract address that /// does not implement ERC721Receiver. error TransferToNonERC721ReceiverImplementer(); /// @dev Thrown when linking to the DN404 base contract and the /// DN404 supportsInterface check fails or the call reverts. error CannotLink(); /// @dev Thrown when a linkMirrorContract call is received and the /// NFT mirror contract has already been linked to a DN404 base contract. error AlreadyLinked(); /// @dev Thrown when retrieving the base DN404 address when a link has not /// been established. error NotLinked(); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* STORAGE */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Struct contain the NFT mirror contract storage. struct DN404NFTStorage { address baseERC20; address deployer; } /// @dev Returns a storage pointer for DN404NFTStorage. function _getDN404NFTStorage() internal pure virtual returns (DN404NFTStorage storage $) { /// @solidity memory-safe-assembly assembly { // `uint72(bytes9(keccak256("DN404_MIRROR_STORAGE")))`. $.slot := 0x3602298b8c10b01230 // Truncate to 9 bytes to reduce bytecode size. } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTRUCTOR */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ constructor(address deployer) { // For non-proxies, we will store the deployer so that only the deployer can // link the base contract. _getDN404NFTStorage().deployer = deployer; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* ERC721 OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the token collection name from the base DN404 contract. function name() public view virtual returns (string memory result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x00, 0x06fdde03) // `name()`. if iszero(staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x00)) { returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } returndatacopy(0x00, 0x00, 0x20) returndatacopy(result, mload(0x00), 0x20) returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) mstore(0x40, add(add(result, 0x20), mload(result))) } } /// @dev Returns the token collection symbol from the base DN404 contract. function symbol() public view virtual returns (string memory result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x00, 0x95d89b41) // `symbol()`. if iszero(staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x00)) { returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } returndatacopy(0x00, 0x00, 0x20) returndatacopy(result, mload(0x00), 0x20) returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) mstore(0x40, add(add(result, 0x20), mload(result))) } } /// @dev Returns the Uniform Resource Identifier (URI) for token `id` from /// the base DN404 contract. function tokenURI(uint256 id) public view virtual returns (string memory result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x20, id) mstore(0x00, 0xc87b56dd) // `tokenURI()`. if iszero(staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x00)) { returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } returndatacopy(0x00, 0x00, 0x20) returndatacopy(result, mload(0x00), 0x20) returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) mstore(0x40, add(add(result, 0x20), mload(result))) } } /// @dev Returns the total NFT supply from the base DN404 contract. function totalSupply() public view virtual returns (uint256 result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { mstore(0x00, 0xe2c79281) // `totalNFTSupply()`. if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)) ) { returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } result := mload(0x00) } } /// @dev Returns the number of NFT tokens owned by `owner` from the base DN404 contract. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { mstore(0x20, shr(96, shl(96, owner))) mstore(0x00, 0xf5b100ea) // `balanceOfNFT(address)`. if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x20)) ) { returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } result := mload(0x00) } } /// @dev Returns the owner of token `id` from the base DN404 contract. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x6352211e) // `ownerOf(uint256)`. mstore(0x20, id) if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x20)) ) { returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } result := shr(96, mload(0x0c)) } } /// @dev Sets `spender` as the approved account to manage token `id` in /// the base DN404 contract. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address spender, uint256 id) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { spender := shr(96, shl(96, spender)) let m := mload(0x40) mstore(0x00, 0xd10b6e0c) // `approveNFT(address,uint256,address)`. mstore(0x20, spender) mstore(0x40, id) mstore(0x60, caller()) if iszero( and( gt(returndatasize(), 0x1f), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20) ) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id) } } /// @dev Returns the account approved to manage token `id` from /// the base DN404 contract. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x081812fc) // `getApproved(uint256)`. mstore(0x20, id) if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x20)) ) { returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } result := shr(96, mload(0x0c)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller in /// the base DN404 contract. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool approved) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { operator := shr(96, shl(96, operator)) let m := mload(0x40) mstore(0x00, 0x813500fc) // `setApprovalForAll(address,bool,address)`. mstore(0x20, operator) mstore(0x40, iszero(iszero(approved))) mstore(0x60, caller()) if iszero( and(eq(mload(0x00), 1), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } // Emit the {ApprovalForAll} event. log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner` from /// the base DN404 contract. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(0x40, operator) mstore(0x2c, shl(96, owner)) mstore(0x0c, 0xe985e9c5000000000000000000000000) // `isApprovedForAll(address,address)`. if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(0x40, m) // Restore the free memory pointer. result := iszero(iszero(mload(0x00))) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { from := shr(96, shl(96, from)) to := shr(96, shl(96, to)) let m := mload(0x40) mstore(m, 0xe5eb36c8) // `transferFromNFT(address,address,uint256,address)`. mstore(add(m, 0x20), from) mstore(add(m, 0x40), to) mstore(add(m, 0x60), id) mstore(add(m, 0x80), caller()) if iszero( and(eq(mload(m), 1), call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes calldata data) public virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* MIRROR OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the address of the base DN404 contract. function baseERC20() public view virtual returns (address base) { base = _getDN404NFTStorage().baseERC20; if (base == address(0)) revert NotLinked(); } /// @dev Fallback modifier to execute calls from the base DN404 contract. modifier dn404NFTFallback() virtual { DN404NFTStorage storage $ = _getDN404NFTStorage(); uint256 fnSelector = _calldataload(0x00) >> 224; // `logTransfer(uint256[])`. if (fnSelector == 0x263c69d6) { if (msg.sender != $.baseERC20) revert SenderNotBase(); /// @solidity memory-safe-assembly assembly { // When returndatacopy copies 1 or more out-of-bounds bytes, it reverts. returndatacopy(0x00, returndatasize(), lt(calldatasize(), 0x20)) let o := add(0x24, calldataload(0x04)) // Packed logs offset. returndatacopy(0x00, returndatasize(), lt(calldatasize(), o)) let end := add(o, shl(5, calldataload(sub(o, 0x20)))) returndatacopy(0x00, returndatasize(), lt(calldatasize(), end)) for {} iszero(eq(o, end)) { o := add(0x20, o) } { let d := calldataload(o) // Entry in the packed logs. let a := shr(96, d) // The address. let b := and(1, d) // Whether it is a burn. log4( codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, mul(a, b), mul(a, iszero(b)), shr(168, shl(160, d)) ) } mstore(0x00, 0x01) return(0x00, 0x20) } } // `linkMirrorContract(address)`. if (fnSelector == 0x0f4599e5) { if ($.deployer != address(0)) { if (address(uint160(_calldataload(0x04))) != $.deployer) { revert SenderNotDeployer(); } } if ($.baseERC20 != address(0)) revert AlreadyLinked(); $.baseERC20 = msg.sender; /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x01) return(0x00, 0x20) } } _; } /// @dev Fallback function for calls from base DN404 contract. fallback() external payable virtual dn404NFTFallback {} receive() external payable virtual {} /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* PRIVATE HELPERS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the calldata value at `offset`. function _calldataload(uint256 offset) private pure returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := calldataload(offset) } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"DNAlreadyInitialized","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"LinkMirrorContractFailed","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"MaxBalanceLimitReached","type":"error"},{"inputs":[],"name":"MirrorAddressIsZero","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"SenderNotMirror","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","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":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SkipNFTSet","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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_collectAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_markAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURILocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"buyer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"gasBurnFactor","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasBurnFactorLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"getSkipNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"mirror","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockGasBurnFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockGasWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockMaxBalanceLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"luckyInfoOf","outputs":[{"components":[{"internalType":"uint256","name":"winAmount","type":"uint256"},{"internalType":"uint256","name":"claimed","type":"uint256"}],"internalType":"struct LuckyBunny404.LuckyInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBalanceLimit","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBalanceLimitLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mirrorERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameAndSymbolLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"contract IUniswapV3Pool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"rewardFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sellFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setCollectAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"gasBurnFactor_","type":"uint32"}],"name":"setGasBurnFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"value","type":"uint8"}],"name":"setMaxBalanceLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"name":"setNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"skipNFT","type":"bool"}],"name":"setSkipNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"whitelistLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d3362000035565b600b80546001600160a01b03191633179055620006b7565b6200004081620002c9565b6200004d81600162000305565b60408051808201909152600b81526a4c75636b792042756e6e7960a81b60208201526000906200007e908262000472565b5060408051808201909152600581526442756e6e7960d81b6020820152600190620000aa908262000472565b5060038054600160281b600160f01b0319167dc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000c350a0000000000017908190556004805473c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b031991821617825560058054731f98431c8ad98523631ae4a59f267346ea31f98492168217905560405163a167129560e01b815230928101929092526001600160a01b036a010000000000000000000090930492909216602482015261271060448201526000919063a1671295906064016020604051808303816000875af115801562000191573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b791906200053e565b600680546001600160a01b0319166001600160a01b0383161790559050620001f573c36442b4a4522e871399cd717abdd847ab11fe88600162000305565b6200020230600162000305565b6200020f81600162000305565b60026200021f6012600a62000683565b6200022b919062000694565b600e5560065460408051630dfe168160e01b815290516001600160a01b0390921691630dfe1681916004808201926020929091908290030181865afa15801562000279573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029f91906200053e565b601060016101000a8154816001600160a01b0302191690836001600160a01b031602179055505050565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6200039182620003508362000340836001600160a01b0316600090815268a20d6e21d0e525531060205260409020546001600160581b031690565b6001600160581b03169062000395565b6001600160a01b0391909116600090815268a20d6e21d0e52553106020526040902080546001600160581b0319166001600160581b03909216919091179055565b5050565b6000811515620003aa8460571c600116151590565b151514620003c4576a800000000000000000000092909218915b50815b92915050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620003f857607f821691505b6020821081036200041957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200046d57600081815260208120601f850160051c81016020861015620004485750805b601f850160051c820191505b81811015620004695782815560010162000454565b5050505b505050565b81516001600160401b038111156200048e576200048e620003cd565b620004a6816200049f8454620003e3565b846200041f565b602080601f831160018114620004de5760008415620004c55750858301515b600019600386901b1c1916600185901b17855562000469565b600085815260208120601f198616915b828110156200050f57888601518255948401946001909101908401620004ee565b50858210156200052e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200055157600080fd5b81516001600160a01b03811681146200056957600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620005c7578160001904821115620005ab57620005ab62000570565b80851615620005b957918102915b93841c93908002906200058b565b509250929050565b600082620005e057506001620003c7565b81620005ef57506000620003c7565b8160018114620006085760028114620006135762000633565b6001915050620003c7565b60ff84111562000627576200062762000570565b50506001821b620003c7565b5060208310610133831016604e8410600b841016171562000658575081810a620003c7565b62000664838362000586565b80600019048211156200067b576200067b62000570565b029392505050565b60006200056960ff841683620005cf565b600082620006b257634e487b7160e01b600052601260045260246000fd5b500490565b61398f80620006c76000396000f3fe6080604052600436106103a65760003560e01c806355f804b3116101e7578063b77482081161010d578063e0f3ccf5116100a0578063f04e283e1161006f578063f04e283e14610f23578063f2fde38b14610f36578063f3dc2a4a14610f49578063fee81cf414610f6957610411565b8063e0f3ccf514610ec1578063e436744514610ed7578063e4748b9e14610ef8578063e522538114610f0e57610411565b8063c87b56dd116100dc578063c87b56dd14610e12578063d73c1fb314610e32578063dd46706414610e53578063dd62ed3e14610e7357610411565b8063b774820814610da7578063bbefa83a14610dc7578063bef4202814610ddc578063c4d66de814610df257610411565b806371b3694d11610185578063a9059cbb11610154578063a9059cbb14610d32578063af6900c314610d52578063b19de39f14610d67578063b698206914610d8757610411565b806371b3694d14610c7257806375b238fc14610cef5780638da5cb5b14610d0457806395d89b4114610d1d57610411565b80636338cb8a116101c15780636338cb8a14610c1f57806366fa193214610c3457806370a0823114610c4a578063715018a614610c6a57610411565b806355f804b314610bc55780635a44621514610be55780635d148e5c14610c0557610411565b80632bf8e8f6116102cc5780634a4ee7b11161026a5780635327bba3116102395780635327bba314610b4f57806353d6fd5914610b8857806353df5c7c14610ba857806354d1f13d14610bbd57610411565b80634a4ee7b114610aca5780634e71d92d14610add5780634ef41efc14610af2578063514e62fc14610b1857610411565b80633af32abf116102a65780633af32abf14610a555780633ccfd60b14610a755780634351e80514610a8a57806347f618a514610aaa57610411565b80632bf8e8f6146109f85780632de9480714610a0e578063313ce56714610a4157610411565b8063183a4f6e1161034457806323b872dd1161031357806323b872dd1461099057806325692962146109b0578063274e430b146109b85780632a6a935d146109d857610411565b8063183a4f6e1461091e5780631c10893f146109315780631cd64df41461094457806323b848ff1461097b57610411565b80630dfe1681116103805780630dfe16811461086b57806316f0115b146108a8578063180434a3146108c857806318160ddd146108e757610411565b806304dfe79d146107df57806306fdde0314610819578063095ea7b31461083b57610411565b36610411576003600a9054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103fb57600080fd5b505af115801561040f573d6000803e3d6000fd5b005b68a20d6e21d0e525530860003560e01c63e985e9c58190036104b75760018201546001600160a01b0316331461045a5760405163ce5a776b60e01b815260040160405180910390fd5b604436101561046857600080fd5b6004356001600160a01b038181166000908152600385016020908152604080832060243594851684529091529020546104b49060ff166104a95760006104ac565b60015b60ff16610f9c565b50505b80636352211e0361051c5760018201546001600160a01b031633146104ef5760405163ce5a776b60e01b815260040160405180910390fd5b60243610156104fd57600080fd5b60043561051a61050c82610fa6565b6001600160a01b0316610f9c565b505b8063e5eb36c8036105895760018201546001600160a01b031633146105545760405163ce5a776b60e01b815260040160405180910390fd5b608436101561056257600080fd5b60043560243560443560643561057a84848484610fdd565b6105846001610f9c565b505050505b8063813500fc036106235760018201546001600160a01b031633146105c15760405163ce5a776b60e01b815260040160405180910390fd5b60643610156105cf57600080fd5b6001600160a01b03604435818116600090815268a20d6e21d0e525530b6020908152604080832060043595861684529091529020805460ff191660243515159081179091559061061f6001610f9c565b5050505b8063d10b6e0c036106845760018201546001600160a01b0316331461065b5760405163ce5a776b60e01b815260040160405180910390fd5b606436101561066957600080fd5b60043560243560443561068061050c848484611068565b5050505b8063081812fc036106db5760018201546001600160a01b031633146106bc5760405163ce5a776b60e01b815260040160405180910390fd5b60243610156106ca57600080fd5b6004356106d961050c82611160565b505b8063f5b100ea036107635760018201546001600160a01b031633146107135760405163ce5a776b60e01b815260040160405180910390fd5b602436101561072157600080fd5b60043561076161075c826001600160a01b0316600090815268a20d6e21d0e5255310602052604090205463ffffffff600160801b9091041690565b610f9c565b505b8063e2c79281036107ca5760018201546001600160a01b0316331461079b5760405163ce5a776b60e01b815260040160405180910390fd5b60043610156107a957600080fd5b68a20d6e21d0e5255308546107ca90600160401b900463ffffffff16610f9c565b8063b7a94eb80361040f5761040f6001610f9c565b3480156107eb57600080fd5b506003546108029065010000000000900460ff1681565b60405160ff90911681526020015b60405180910390f35b34801561082557600080fd5b5061082e6111ac565b60405161081091906132ef565b34801561084757600080fd5b5061085b610856366004613354565b61123e565b6040519015158152602001610810565b34801561087757600080fd5b506010546108909061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610810565b3480156108b457600080fd5b50600654610890906001600160a01b031681565b3480156108d457600080fd5b5060035461085b90610100900460ff1681565b3480156108f357600080fd5b5068a20d6e21d0e525530854600160601b90046001600160601b03165b604051908152602001610810565b61040f61092c36600461337e565b6112b4565b61040f61093f366004613354565b6112c1565b34801561095057600080fd5b5061085b61095f366004613354565b638b78c6d8600c90815260009290925260209091205481161490565b34801561098757600080fd5b5061040f6112d7565b34801561099c57600080fd5b5061085b6109ab366004613397565b6112f9565b61040f61139c565b3480156109c457600080fd5b5061085b6109d33660046133d3565b6113ec565b3480156109e457600080fd5b5061040f6109f33660046133fc565b61143b565b348015610a0457600080fd5b50610910600f5481565b348015610a1a57600080fd5b50610910610a293660046133d3565b638b78c6d8600c908152600091909152602090205490565b348015610a4d57600080fd5b506012610802565b348015610a6157600080fd5b5061085b610a703660046133d3565b611445565b348015610a8157600080fd5b5061040f61145e565b348015610a9657600080fd5b5061040f610aa536600461337e565b611472565b348015610ab657600080fd5b5060035461085b9062010000900460ff1681565b61040f610ad8366004613354565b611483565b348015610ae957600080fd5b5061040f611495565b348015610afe57600080fd5b5068a20d6e21d0e5255309546001600160a01b0316610890565b348015610b2457600080fd5b5061085b610b33366004613354565b638b78c6d8600c90815260009290925260209091205416151590565b348015610b5b57600080fd5b50600354610b7390600160301b900463ffffffff1681565b60405163ffffffff9091168152602001610810565b348015610b9457600080fd5b5061040f610ba3366004613419565b611597565b348015610bb457600080fd5b5061040f6115d7565b61040f6115f2565b348015610bd157600080fd5b5061040f610be0366004613492565b61162e565b348015610bf157600080fd5b5061040f610c003660046134d4565b61166a565b348015610c1157600080fd5b5060035461085b9060ff1681565b348015610c2b57600080fd5b5061040f6116c1565b348015610c4057600080fd5b5061091060075481565b348015610c5657600080fd5b50610910610c653660046133d3565b6116de565b61040f611711565b348015610c7e57600080fd5b50610cd4610c8d3660046133d3565b6040805180820190915260008082526020820152506001600160a01b0316600090815260126020908152604091829020825180840190935280548352600101549082015290565b60408051825181526020928301519281019290925201610810565b348015610cfb57600080fd5b50610910600181565b348015610d1057600080fd5b50638b78c6d81954610890565b348015610d2957600080fd5b5061082e611725565b348015610d3e57600080fd5b5061085b610d4d366004613354565b611734565b348015610d5e57600080fd5b5061040f61174a565b348015610d7357600080fd5b5061040f610d82366004613540565b61176b565b348015610d9357600080fd5b5061040f610da2366004613566565b6117ca565b348015610db357600080fd5b5061085b610dc23660046133d3565b611825565b348015610dd357600080fd5b5061040f611832565b348015610de857600080fd5b50610910600e5481565b348015610dfe57600080fd5b5061040f610e0d3660046133d3565b611851565b348015610e1e57600080fd5b5061082e610e2d36600461337e565b61188b565b348015610e3e57600080fd5b5060035461085b906301000000900460ff1681565b348015610e5f57600080fd5b5061040f610e6e36600461337e565b611985565b348015610e7f57600080fd5b50610910610e8e366004613589565b6001600160a01b03918216600090815268a20d6e21d0e525530d6020908152604080832093909416825291909152205490565b348015610ecd57600080fd5b50610910600c5481565b348015610ee357600080fd5b5060035461085b90600160201b900460ff1681565b348015610f0457600080fd5b50610910600d5481565b348015610f1a57600080fd5b5061040f611a3d565b61040f610f313660046133d3565b611a45565b61040f610f443660046133d3565b611a82565b348015610f5557600080fd5b50600a54610890906001600160a01b031681565b348015610f7557600080fd5b50610910610f843660046133d3565b63389a75e1600c908152600091909152602090205490565b8060005260206000f35b6000610fb182611aa9565b610fce5760405163677510db60e11b815260040160405180910390fd5b610fd782611ac6565b92915050565b610fe984848484611b1b565b610ff38484611e87565b826001600160a01b0316846001600160a01b03161461101e5761101e84670de0b6b3a7640000611f36565b6001600160a01b0384163b158015611048575061103d6012600a6136b6565b611046856116de565b105b1561105a57611058600885611fb1565b505b611062611fc6565b50505050565b600068a20d6e21d0e52553088168a20d6e21d0e525530a816110b668a20d6e21d0e525530f600189901b5b600381901c600090815260209290925260409091205460059190911b60e0161c90565b63ffffffff1681526020810191909152604001600020546001600160a01b0390811691508416811461112a576001600160a01b03808216600090815260038401602090815260408083209388168352929052205460ff1661112a576040516367d9dca160e11b815260040160405180910390fd5b60008581526004909201602052604090912080546001600160a01b0387166001600160a01b031990911617905590509392505050565b600061116b82611aa9565b6111885760405163677510db60e11b815260040160405180910390fd5b50600090815268a20d6e21d0e525530c60205260409020546001600160a01b031690565b6060600080546111bb906136c5565b80601f01602080910402602001604051908101604052809291908181526020018280546111e7906136c5565b80156112345780601f1061120957610100808354040283529160200191611234565b820191906000526020600020905b81548152906001019060200180831161121757829003601f168201915b5050505050905090565b60008068a20d6e21d0e525530833600081815260058301602090815260408083206001600160a01b038a16808552908352928190208890555187815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b6112be33826120e7565b50565b6112c96120f3565b6112d3828261210e565b5050565b60016112e28161211a565b506003805464ff000000001916600160201b179055565b6001600160a01b038316600090815268a20d6e21d0e525530d6020908152604080832033845290915281205468a20d6e21d0e5255308906000198114611385578084111561135a576040516313be252b60e01b815260040160405180910390fd5b6001600160a01b03861660009081526005830160209081526040808320338452909152902084820390555b61139086868661214d565b50600195945050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6001600160a01b038116600090815268a20d6e21d0e5255310602052604081208054600160581b9004600116820361142857823b5b9392505050565b54600160581b9004600216151592915050565b6112be33826122c5565b6000610fd761145383612355565b60571c600116151590565b60016114698161211a565b6112be33612381565b600161147d8161211a565b50600e55565b61148b6120f3565b6112d382826120e7565b336000908152601260205260408120600181015481549192916114b891906136f9565b90506114c560083361239d565b80156114d15750600081115b61150f5760405162461bcd60e51b8152600401611506906020808252600490820152637a65726f60e01b604082015260600190565b60405180910390fd5b61151a600833611fb1565b508154600183015561152a6123bf565b60405163a9059cbb60e01b815233600482015260248101829052309063a9059cbb906044016020604051808303816000875af115801561156e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611592919061370c565b505050565b60016115a28161211a565b6003546301000000900460ff16156115cd576040516303cb96db60e21b815260040160405180910390fd5b61159283836125a7565b60016115e28161211a565b506003805460ff19166001179055565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b60016116398161211a565b60035460ff161561165d576040516303cb96db60e21b815260040160405180910390fd5b6002611062838583613785565b60016116758161211a565b600354610100900460ff161561169e576040516303cb96db60e21b815260040160405180910390fd5b60006116ab858783613785565b5060016116b9838583613785565b505050505050565b60016116cc8161211a565b506003805461ff001916610100179055565b6001600160a01b0316600090815268a20d6e21d0e52553106020526040902054600160a01b90046001600160601b031690565b6117196120f3565b61172360006125cc565b565b6060600180546111bb906136c5565b600061174133848461214d565b50600192915050565b60016117558161211a565b506003805463ff00000019166301000000179055565b60016117768161211a565b60035462010000900460ff16156117a0576040516303cb96db60e21b815260040160405180910390fd5b506003805463ffffffff909216600160301b0269ffffffff00000000000019909216919091179055565b60016117d58161211a565b600354600160201b900460ff1615611800576040516303cb96db60e21b815260040160405180910390fd5b506003805460ff909216650100000000000265ff000000000019909216919091179055565b6000610fd760088361239d565b600161183d8161211a565b506003805462ff0000191662010000179055565b600161185c8161211a565b6000611872670de0b6b3a7640000612710613845565b90503361188082828661260a565b6110628160016125a7565b606061189682611aa9565b6118b35760405163677510db60e11b815260040160405180910390fd5b600280546118c0906136c5565b15905061198057610fd7600280546118d7906136c5565b80601f0160208091040260200160405190810160405280929190818152602001828054611903906136c5565b80156119505780601f1061192557610100808354040283529160200191611950565b820191906000526020600020905b81548152906001019060200180831161193357829003601f168201915b5050505050604051806040016040528060048152602001637b69647d60e01b81525061197b85612798565b6127dc565b919050565b60016119908161211a565b600754156119c95760405162461bcd60e51b81526020600482015260066024820152651b1bd8dad95960d21b6044820152606401611506565b600480546040516323b872dd60e01b81523392810192909252306024830152604482018490526001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b5050506007929092555050565b6117236123bf565b611a4d6120f3565b63389a75e1600c52806000526020600c208054421115611a7557636f5e88186000526004601cfd5b600090556112be816125cc565b611a8a6120f3565b8060601b611aa057637448fbae6000526004601cfd5b6112be816125cc565b600080611ab583611ac6565b6001600160a01b0316141592915050565b600068a20d6e21d0e525530868a20d6e21d0e525530a82611af468a20d6e21d0e525530f600187901b611093565b63ffffffff1681526020810191909152604001600020546001600160a01b03169392505050565b68a20d6e21d0e52553086001600160a01b038416611b4c57604051633a954ecd60e21b815260040160405180910390fd5b6000816002016000611b65846007016110938860011b90565b63ffffffff1681526020810191909152604001600020546001600160a01b03908116915086168114611ba95760405162a1148160e81b815260040160405180910390fd5b856001600160a01b0316836001600160a01b031614611c2d576001600160a01b03808716600090815260038401602090815260408083209387168352929052205460ff16611c2d5760008481526004830160205260409020546001600160a01b03848116911614611c2d57604051632ce44b5f60e11b815260040160405180910390fd5b6000611c38876128ff565b90506000611c45876128ff565b8254909150670de0b6b3a7640000908390601490611c74908490600160a01b90046001600160601b031661385c565b82546101009290920a6001600160601b0381810219909316918316021790915582546001600160a01b038116670de0b6b3a7640000600160a01b928390048416019092160217825550611cd860078501600188901b611cd3848b61296b565b612a0e565b6000868152600485016020908152604080832080546001600160a01b03191690556001600160a01b038b168352600687018252808320855463ffffffff60801b198116600160801b9182900463ffffffff90811660001901908116909202178755631fffffff600382901c168552925282205460059190911b60e0161c6001600160a01b038a166000908152600687016020526040902063ffffffff919091169150611d9c90611d906007880160018b811b01611093565b63ffffffff1683612a0e565b8154600163ffffffff600160801b80840482169283019091160263ffffffff60801b19909216919091178355611dee60078701611ddc84600190811b0190565b611cd360078a0160018d811b01611093565b6001600160a01b03891660009081526006870160205260409020611e1390828a612a0e565b611e266007870160018a811b0183612a0e565b5050866001600160a01b0316886001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef670de0b6b3a7640000604051611e7591815260200190565b60405180910390a35050505050505050565b60035465010000000000900460ff166000819003611ea457505050565b80670de0b6b3a764000002611eb8836116de565b11611ec257505050565b611ece61145383612355565b15611ed857505050565b638b78c6d819546001600160a01b0316836001600160a01b031603611efc57505050565b638b78c6d8600c9081526000849052602090205460011615611f1d57505050565b6040516303cab2ff60e21b815260040160405180910390fd5b600354600160301b900463ffffffff166000819003611f5457505050565b600080611f7384611f6487612355565b6001600160581b031690612a42565b9150915060028110611fa05780800283026301312d00808210611f94578091505b611f9d82612ab9565b50505b611faa8583612aed565b5050505050565b6000611421836001600160a01b038416612b32565b600754600003611fd257565b600e54600f54600c54611fe591906136f9565b1015611fed57565b6000611ff96008612c25565b905080516000036120075750565b80516011546040516bffffffffffffffffffffffff193260601b1660208201524260348201526054810191909152600091906074016040516020818303038152906040528051906020012060001c61205f9190613892565b9050600e54600f600082825461207591906138a6565b92505081905550600060126000848481518110612094576120946138b9565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000209050600e548160000160008282546120d491906138a6565b9091555050601180546001019055505050565b6112d382826000612c32565b638b78c6d819543314611723576382b429006000526004601cfd5b6112d382826001612c32565b638b78c6d8195433146112be57638b78c6d8600c5233600052806020600c2054166112be576382b429006000526004601cfd5b612158838383612c8b565b6121628383611e87565b816001600160a01b0316836001600160a01b031614612185576121858382611f36565b601054600160a81b900460ff161561219c57505050565b6006546001600160a01b039081169084160361220e576001600160a01b0382163b1580156121d557506121d16012600a6136b6565b8110155b156121e7576121e5600883613158565b505b6121f26064826138cf565b600d600082825461220391906138a6565b909155506122819050565b6006546001600160a01b0390811690831603612281576122306012600a6136b6565b612239846116de565b101561224c5761224a600884611fb1565b505b60105460ff1615612273576122626064826138cf565b600c600082825461220391906138a6565b6010805460ff191660011790555b6001600160a01b0383163b1580156122ab57506122a06012600a6136b6565b6122a9846116de565b105b156122bd576122bb600884611fb1565b505b611592611fc6565b60006122d0836128ff565b8054909150600160581b900460021615158215151461230b57805460ff600160581b80830482166002189091160260ff60581b199091161781555b826001600160a01b03167fb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d642039383604051612348911515815260200190565b60405180910390a2505050565b6001600160a01b0316600090815268a20d6e21d0e525531060205260409020546001600160581b031690565b60003860003847855af16112be5763b12d13eb6000526004601cfd5b6001600160a01b03811660009081526001830160205260408120541515611421565b6010805460ff60a81b1916600160a81b1790556004805460408051608081018252600754815230602082019081526fffffffffffffffffffffffffffffffff82840181815260608401828152945163fc6f786560e01b815293519684019690965290516001600160a01b03908116602484015294518116604483015291518216606482015290928392169063fc6f78659060840160408051808303816000875af1158015612471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249591906138e3565b50506003546040516370a0823160e01b8152306004820152600091600160501b90046001600160a01b0316906370a0823190602401602060405180830381865afa1580156124e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250b9190613907565b9050801561259557600354600b5460405163a9059cbb60e01b81526001600160a01b03918216600482015260248101849052600160501b909204169063a9059cbb906044016020604051808303816000875af115801561256f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612593919061370c565b505b50506010805460ff60a81b1916905550565b6112d3826125c7836125b886612355565b6001600160581b03169061316d565b612aed565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b68a20d6e21d0e52553088054600160201b900463ffffffff161561264157604051633ab534b960e21b815260040160405180910390fd5b6001600160a01b038216612668576040516339a84a7b60e01b815260040160405180910390fd5b61267182613193565b805467ffffffff000000001916600160201b1781556001810180546001600160a01b0384166001600160a01b03199091161790558315611062576001600160a01b0383166126d257604051633a954ecd60e21b815260040160405180910390fd5b6b0de0b6b39983494c589bffff8411156126ff5760405163e5cfe95760e01b815260040160405180910390fd5b80546bffffffffffffffffffffffff60601b1916600160601b6001600160601b038616021781556000612731846128ff565b80546001600160a01b03908116600160a01b6001600160601b038916021782556040518781529192508516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3611faa8460016122c5565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a9004806127b3575050819003601f19909101908152919050565b606083518351835160208701965060208601955060208501945060206040510193508287018383116128ae5760018382030160006020851061281d57508388205b601f851660200360031b89515b8b51818118831c6128955783156128645783888e201461286457808a5260019c8d019c90990198848d1061285e57506128a9565b5061282a565b60005b8b8101518b82015260200187811061286757509b87019b98860198871561289557848d1061285e57506128a9565b895260019b8c019b90980197838c1061282a575b505050505b84935060206040510194508781038585030192505b808810156128de5787518452602097880197909301926128c3565b50506000818401908152602001604052601f19909201918252509392505050565b6001600160a01b038116600090815268a20d6e21d0e5255310602052604081208054909168a20d6e21d0e525530891600160581b90046001169003612965576001833b1561294b576002175b825460ff909116600160581b0260ff60581b199091161782555b50919050565b8154600160601b900463ffffffff1668a20d6e21d0e52553086000829003612a0757805481906000906129a39063ffffffff16613920565b825463ffffffff8083166101009490940a848102910219909116179092558554600160601b820263ffffffff60601b199091161786556000908152600283016020526040902080546001600160a01b0386166001600160a01b031990911617905591505b5092915050565b826020528160031c60005260406000206007831660051b815463ffffffff8482841c188116831b8218845550505050505050565b600080605784901c60011615612a5d57508290506000612ab2565b637fffffff620151804204811690603886901c1666ffffffffffffff8616818314612a89575081905060005b60389190911b66ffffffffffffff602887901c811692909201918216179350620de0b690049150505b9250929050565b80600117601052605b8104607882110260005b818114612ae25760108080209052600101612acc565b50506010516112be57fe5b6001600160a01b0391909116600090815268a20d6e21d0e52553106020526040902080546affffffffffffffffffffff19166001600160581b03909216919091179055565b60008181526001830160205260408120548015612c1b576000612b566001836136f9565b8554909150600090612b6a906001906136f9565b9050818114612bcf576000866000018281548110612b8a57612b8a6138b9565b9060005260206000200154905080876000018481548110612bad57612bad6138b9565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612be057612be0613943565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fd7565b6000915050610fd7565b60606000611421836131c5565b638b78c6d8600c52826000526020600c20805483811783612c54575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b6001600160a01b038216612cb257604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553086000612cc7856128ff565b90506000612cd4856128ff565b9050612d0f6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b825463ffffffff600160801b808304821660808501528454041660a08301526001600160601b03600160a01b9091041660408201819052851115612d6657604051631e9acf1760e31b815260040160405180910390fd5b6040810180518690039081905283546001600160601b03808316600160a01b9081026001600160a01b03938416178755855481810483168a01606087018190529092160291161783556080820151612dcc91670de0b6b3a7640000900480821191030290565b81528154600160581b9004600216600003612e3b57856001600160a01b0316876001600160a01b031603612e0857805160808201510360a08201525b612e35670de0b6b3a7640000826060015181612e2657612e2661387c565b048260a0015180821191030290565b60208201525b6000612e8582602001518360000151016040805180820190915260608152600060208201526040805101828152806020018360051b81016040528183528083602001525050919050565b825190915015612f7f576001600160a01b0388166000908152600686016020526040902060808301518351875463ffffffff600160401b808304821684900382160263ffffffff60401b199092169190911789558754918303908116600160801b0263ffffffff60801b199092169190911787555b60001991909101600381901c600090815260208490526040812054919291600584901b60e0161c63ffffffff169050612f398960070182600080613221565b600081815260048a016020908152604090912080546001600160a01b0319169055858101805160089390931b60608f901b17600117835291019052808203612efa575050505b6020820151156130e0576001600160a01b03871660009081526006860160209081526040822060a085015191850151909290820190612fbe878c61296b565b8954602088015163ffffffff60401b19821663ffffffff600160401b80850482169093018116909202178c55895463ffffffff60801b1916600160801b86831602178a55919250670de0b6b3a7640000600160601b82046001600160601b03160491600160201b909104165b61303b8b6007016110938360011b90565b63ffffffff161561305a5760010181811115613055575060015b61302a565b613065868683612a0e565b61307a8b600701828588806001019950613221565b6130a4878e8360008360200151818360081b8560601b171781526020810185602001525050505050565b600101818111156130b3575060015b83850361302a578a5463ffffffff909116600160201b0267ffffffff0000000019909116178a5550505050505b805151156131015760018501546131019082906001600160a01b0316613267565b50856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405161314791815260200190565b60405180910390a350505050505050565b6000611421836001600160a01b0384166132a0565b60006001605784901c1615158215151461318c57600160571b92909218915b5090919050565b630f4599e560005233602052602060006024601c6000855af1600160005114166112be5763d125259c6000526004601cfd5b60608160000180548060200260200160405190810160405280929190818152602001828054801561321557602002820191906000526020600020905b815481526020019060010190808311613201575b50505050509050919050565b8163ffffffff168160201b17846020528360021c60005260406000206003851660061b815467ffffffffffffffff8482841c188116831b82188455505050505050505050565b81516040810363263c69d68152602080820152815160051b604401915060208183601c84016000875af160018251141661106257600081fd5b60008181526001830160205260408120546132e757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fd7565b506000610fd7565b600060208083528351808285015260005b8181101561331c57858101830151858201604001528201613300565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461198057600080fd5b6000806040838503121561336757600080fd5b6133708361333d565b946020939093013593505050565b60006020828403121561339057600080fd5b5035919050565b6000806000606084860312156133ac57600080fd5b6133b58461333d565b92506133c36020850161333d565b9150604084013590509250925092565b6000602082840312156133e557600080fd5b6114218261333d565b80151581146112be57600080fd5b60006020828403121561340e57600080fd5b8135611421816133ee565b6000806040838503121561342c57600080fd5b6134358361333d565b91506020830135613445816133ee565b809150509250929050565b60008083601f84011261346257600080fd5b50813567ffffffffffffffff81111561347a57600080fd5b602083019150836020828501011115612ab257600080fd5b600080602083850312156134a557600080fd5b823567ffffffffffffffff8111156134bc57600080fd5b6134c885828601613450565b90969095509350505050565b600080600080604085870312156134ea57600080fd5b843567ffffffffffffffff8082111561350257600080fd5b61350e88838901613450565b9096509450602087013591508082111561352757600080fd5b5061353487828801613450565b95989497509550505050565b60006020828403121561355257600080fd5b813563ffffffff8116811461142157600080fd5b60006020828403121561357857600080fd5b813560ff8116811461142157600080fd5b6000806040838503121561359c57600080fd5b6135a58361333d565b91506135b36020840161333d565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561360d5781600019048211156135f3576135f36135bc565b8085161561360057918102915b93841c93908002906135d7565b509250929050565b60008261362457506001610fd7565b8161363157506000610fd7565b816001811461364757600281146136515761366d565b6001915050610fd7565b60ff841115613662576136626135bc565b50506001821b610fd7565b5060208310610133831016604e8410600b8410161715613690575081810a610fd7565b61369a83836135d2565b80600019048211156136ae576136ae6135bc565b029392505050565b600061142160ff841683613615565b600181811c908216806136d957607f821691505b60208210810361296557634e487b7160e01b600052602260045260246000fd5b81810381811115610fd757610fd76135bc565b60006020828403121561371e57600080fd5b8151611421816133ee565b634e487b7160e01b600052604160045260246000fd5b601f82111561159257600081815260208120601f850160051c810160208610156137665750805b601f850160051c820191505b818110156116b957828155600101613772565b67ffffffffffffffff83111561379d5761379d613729565b6137b1836137ab83546136c5565b8361373f565b6000601f8411600181146137e557600085156137cd5750838201355b600019600387901b1c1916600186901b178355611faa565b600083815260209020601f19861690835b8281101561381657868501358255602094850194600190920191016137f6565b50868210156138335760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b8082028115828204841417610fd757610fd76135bc565b6001600160601b03828116828216039080821115612a0757612a076135bc565b634e487b7160e01b600052601260045260246000fd5b6000826138a1576138a161387c565b500690565b80820180821115610fd757610fd76135bc565b634e487b7160e01b600052603260045260246000fd5b6000826138de576138de61387c565b500490565b600080604083850312156138f657600080fd5b505080516020909101519092909150565b60006020828403121561391957600080fd5b5051919050565b600063ffffffff808316818103613939576139396135bc565b6001019392505050565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220799851e5007eec0e091756974405c2d46386bbe660cefaf8cb756a1ba77489c664736f6c63430008130033
Deployed Bytecode
0x6080604052600436106103a65760003560e01c806355f804b3116101e7578063b77482081161010d578063e0f3ccf5116100a0578063f04e283e1161006f578063f04e283e14610f23578063f2fde38b14610f36578063f3dc2a4a14610f49578063fee81cf414610f6957610411565b8063e0f3ccf514610ec1578063e436744514610ed7578063e4748b9e14610ef8578063e522538114610f0e57610411565b8063c87b56dd116100dc578063c87b56dd14610e12578063d73c1fb314610e32578063dd46706414610e53578063dd62ed3e14610e7357610411565b8063b774820814610da7578063bbefa83a14610dc7578063bef4202814610ddc578063c4d66de814610df257610411565b806371b3694d11610185578063a9059cbb11610154578063a9059cbb14610d32578063af6900c314610d52578063b19de39f14610d67578063b698206914610d8757610411565b806371b3694d14610c7257806375b238fc14610cef5780638da5cb5b14610d0457806395d89b4114610d1d57610411565b80636338cb8a116101c15780636338cb8a14610c1f57806366fa193214610c3457806370a0823114610c4a578063715018a614610c6a57610411565b806355f804b314610bc55780635a44621514610be55780635d148e5c14610c0557610411565b80632bf8e8f6116102cc5780634a4ee7b11161026a5780635327bba3116102395780635327bba314610b4f57806353d6fd5914610b8857806353df5c7c14610ba857806354d1f13d14610bbd57610411565b80634a4ee7b114610aca5780634e71d92d14610add5780634ef41efc14610af2578063514e62fc14610b1857610411565b80633af32abf116102a65780633af32abf14610a555780633ccfd60b14610a755780634351e80514610a8a57806347f618a514610aaa57610411565b80632bf8e8f6146109f85780632de9480714610a0e578063313ce56714610a4157610411565b8063183a4f6e1161034457806323b872dd1161031357806323b872dd1461099057806325692962146109b0578063274e430b146109b85780632a6a935d146109d857610411565b8063183a4f6e1461091e5780631c10893f146109315780631cd64df41461094457806323b848ff1461097b57610411565b80630dfe1681116103805780630dfe16811461086b57806316f0115b146108a8578063180434a3146108c857806318160ddd146108e757610411565b806304dfe79d146107df57806306fdde0314610819578063095ea7b31461083b57610411565b36610411576003600a9054906101000a90046001600160a01b03166001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103fb57600080fd5b505af115801561040f573d6000803e3d6000fd5b005b68a20d6e21d0e525530860003560e01c63e985e9c58190036104b75760018201546001600160a01b0316331461045a5760405163ce5a776b60e01b815260040160405180910390fd5b604436101561046857600080fd5b6004356001600160a01b038181166000908152600385016020908152604080832060243594851684529091529020546104b49060ff166104a95760006104ac565b60015b60ff16610f9c565b50505b80636352211e0361051c5760018201546001600160a01b031633146104ef5760405163ce5a776b60e01b815260040160405180910390fd5b60243610156104fd57600080fd5b60043561051a61050c82610fa6565b6001600160a01b0316610f9c565b505b8063e5eb36c8036105895760018201546001600160a01b031633146105545760405163ce5a776b60e01b815260040160405180910390fd5b608436101561056257600080fd5b60043560243560443560643561057a84848484610fdd565b6105846001610f9c565b505050505b8063813500fc036106235760018201546001600160a01b031633146105c15760405163ce5a776b60e01b815260040160405180910390fd5b60643610156105cf57600080fd5b6001600160a01b03604435818116600090815268a20d6e21d0e525530b6020908152604080832060043595861684529091529020805460ff191660243515159081179091559061061f6001610f9c565b5050505b8063d10b6e0c036106845760018201546001600160a01b0316331461065b5760405163ce5a776b60e01b815260040160405180910390fd5b606436101561066957600080fd5b60043560243560443561068061050c848484611068565b5050505b8063081812fc036106db5760018201546001600160a01b031633146106bc5760405163ce5a776b60e01b815260040160405180910390fd5b60243610156106ca57600080fd5b6004356106d961050c82611160565b505b8063f5b100ea036107635760018201546001600160a01b031633146107135760405163ce5a776b60e01b815260040160405180910390fd5b602436101561072157600080fd5b60043561076161075c826001600160a01b0316600090815268a20d6e21d0e5255310602052604090205463ffffffff600160801b9091041690565b610f9c565b505b8063e2c79281036107ca5760018201546001600160a01b0316331461079b5760405163ce5a776b60e01b815260040160405180910390fd5b60043610156107a957600080fd5b68a20d6e21d0e5255308546107ca90600160401b900463ffffffff16610f9c565b8063b7a94eb80361040f5761040f6001610f9c565b3480156107eb57600080fd5b506003546108029065010000000000900460ff1681565b60405160ff90911681526020015b60405180910390f35b34801561082557600080fd5b5061082e6111ac565b60405161081091906132ef565b34801561084757600080fd5b5061085b610856366004613354565b61123e565b6040519015158152602001610810565b34801561087757600080fd5b506010546108909061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610810565b3480156108b457600080fd5b50600654610890906001600160a01b031681565b3480156108d457600080fd5b5060035461085b90610100900460ff1681565b3480156108f357600080fd5b5068a20d6e21d0e525530854600160601b90046001600160601b03165b604051908152602001610810565b61040f61092c36600461337e565b6112b4565b61040f61093f366004613354565b6112c1565b34801561095057600080fd5b5061085b61095f366004613354565b638b78c6d8600c90815260009290925260209091205481161490565b34801561098757600080fd5b5061040f6112d7565b34801561099c57600080fd5b5061085b6109ab366004613397565b6112f9565b61040f61139c565b3480156109c457600080fd5b5061085b6109d33660046133d3565b6113ec565b3480156109e457600080fd5b5061040f6109f33660046133fc565b61143b565b348015610a0457600080fd5b50610910600f5481565b348015610a1a57600080fd5b50610910610a293660046133d3565b638b78c6d8600c908152600091909152602090205490565b348015610a4d57600080fd5b506012610802565b348015610a6157600080fd5b5061085b610a703660046133d3565b611445565b348015610a8157600080fd5b5061040f61145e565b348015610a9657600080fd5b5061040f610aa536600461337e565b611472565b348015610ab657600080fd5b5060035461085b9062010000900460ff1681565b61040f610ad8366004613354565b611483565b348015610ae957600080fd5b5061040f611495565b348015610afe57600080fd5b5068a20d6e21d0e5255309546001600160a01b0316610890565b348015610b2457600080fd5b5061085b610b33366004613354565b638b78c6d8600c90815260009290925260209091205416151590565b348015610b5b57600080fd5b50600354610b7390600160301b900463ffffffff1681565b60405163ffffffff9091168152602001610810565b348015610b9457600080fd5b5061040f610ba3366004613419565b611597565b348015610bb457600080fd5b5061040f6115d7565b61040f6115f2565b348015610bd157600080fd5b5061040f610be0366004613492565b61162e565b348015610bf157600080fd5b5061040f610c003660046134d4565b61166a565b348015610c1157600080fd5b5060035461085b9060ff1681565b348015610c2b57600080fd5b5061040f6116c1565b348015610c4057600080fd5b5061091060075481565b348015610c5657600080fd5b50610910610c653660046133d3565b6116de565b61040f611711565b348015610c7e57600080fd5b50610cd4610c8d3660046133d3565b6040805180820190915260008082526020820152506001600160a01b0316600090815260126020908152604091829020825180840190935280548352600101549082015290565b60408051825181526020928301519281019290925201610810565b348015610cfb57600080fd5b50610910600181565b348015610d1057600080fd5b50638b78c6d81954610890565b348015610d2957600080fd5b5061082e611725565b348015610d3e57600080fd5b5061085b610d4d366004613354565b611734565b348015610d5e57600080fd5b5061040f61174a565b348015610d7357600080fd5b5061040f610d82366004613540565b61176b565b348015610d9357600080fd5b5061040f610da2366004613566565b6117ca565b348015610db357600080fd5b5061085b610dc23660046133d3565b611825565b348015610dd357600080fd5b5061040f611832565b348015610de857600080fd5b50610910600e5481565b348015610dfe57600080fd5b5061040f610e0d3660046133d3565b611851565b348015610e1e57600080fd5b5061082e610e2d36600461337e565b61188b565b348015610e3e57600080fd5b5060035461085b906301000000900460ff1681565b348015610e5f57600080fd5b5061040f610e6e36600461337e565b611985565b348015610e7f57600080fd5b50610910610e8e366004613589565b6001600160a01b03918216600090815268a20d6e21d0e525530d6020908152604080832093909416825291909152205490565b348015610ecd57600080fd5b50610910600c5481565b348015610ee357600080fd5b5060035461085b90600160201b900460ff1681565b348015610f0457600080fd5b50610910600d5481565b348015610f1a57600080fd5b5061040f611a3d565b61040f610f313660046133d3565b611a45565b61040f610f443660046133d3565b611a82565b348015610f5557600080fd5b50600a54610890906001600160a01b031681565b348015610f7557600080fd5b50610910610f843660046133d3565b63389a75e1600c908152600091909152602090205490565b8060005260206000f35b6000610fb182611aa9565b610fce5760405163677510db60e11b815260040160405180910390fd5b610fd782611ac6565b92915050565b610fe984848484611b1b565b610ff38484611e87565b826001600160a01b0316846001600160a01b03161461101e5761101e84670de0b6b3a7640000611f36565b6001600160a01b0384163b158015611048575061103d6012600a6136b6565b611046856116de565b105b1561105a57611058600885611fb1565b505b611062611fc6565b50505050565b600068a20d6e21d0e52553088168a20d6e21d0e525530a816110b668a20d6e21d0e525530f600189901b5b600381901c600090815260209290925260409091205460059190911b60e0161c90565b63ffffffff1681526020810191909152604001600020546001600160a01b0390811691508416811461112a576001600160a01b03808216600090815260038401602090815260408083209388168352929052205460ff1661112a576040516367d9dca160e11b815260040160405180910390fd5b60008581526004909201602052604090912080546001600160a01b0387166001600160a01b031990911617905590509392505050565b600061116b82611aa9565b6111885760405163677510db60e11b815260040160405180910390fd5b50600090815268a20d6e21d0e525530c60205260409020546001600160a01b031690565b6060600080546111bb906136c5565b80601f01602080910402602001604051908101604052809291908181526020018280546111e7906136c5565b80156112345780601f1061120957610100808354040283529160200191611234565b820191906000526020600020905b81548152906001019060200180831161121757829003601f168201915b5050505050905090565b60008068a20d6e21d0e525530833600081815260058301602090815260408083206001600160a01b038a16808552908352928190208890555187815293945090927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b6112be33826120e7565b50565b6112c96120f3565b6112d3828261210e565b5050565b60016112e28161211a565b506003805464ff000000001916600160201b179055565b6001600160a01b038316600090815268a20d6e21d0e525530d6020908152604080832033845290915281205468a20d6e21d0e5255308906000198114611385578084111561135a576040516313be252b60e01b815260040160405180910390fd5b6001600160a01b03861660009081526005830160209081526040808320338452909152902084820390555b61139086868661214d565b50600195945050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6001600160a01b038116600090815268a20d6e21d0e5255310602052604081208054600160581b9004600116820361142857823b5b9392505050565b54600160581b9004600216151592915050565b6112be33826122c5565b6000610fd761145383612355565b60571c600116151590565b60016114698161211a565b6112be33612381565b600161147d8161211a565b50600e55565b61148b6120f3565b6112d382826120e7565b336000908152601260205260408120600181015481549192916114b891906136f9565b90506114c560083361239d565b80156114d15750600081115b61150f5760405162461bcd60e51b8152600401611506906020808252600490820152637a65726f60e01b604082015260600190565b60405180910390fd5b61151a600833611fb1565b508154600183015561152a6123bf565b60405163a9059cbb60e01b815233600482015260248101829052309063a9059cbb906044016020604051808303816000875af115801561156e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611592919061370c565b505050565b60016115a28161211a565b6003546301000000900460ff16156115cd576040516303cb96db60e21b815260040160405180910390fd5b61159283836125a7565b60016115e28161211a565b506003805460ff19166001179055565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b60016116398161211a565b60035460ff161561165d576040516303cb96db60e21b815260040160405180910390fd5b6002611062838583613785565b60016116758161211a565b600354610100900460ff161561169e576040516303cb96db60e21b815260040160405180910390fd5b60006116ab858783613785565b5060016116b9838583613785565b505050505050565b60016116cc8161211a565b506003805461ff001916610100179055565b6001600160a01b0316600090815268a20d6e21d0e52553106020526040902054600160a01b90046001600160601b031690565b6117196120f3565b61172360006125cc565b565b6060600180546111bb906136c5565b600061174133848461214d565b50600192915050565b60016117558161211a565b506003805463ff00000019166301000000179055565b60016117768161211a565b60035462010000900460ff16156117a0576040516303cb96db60e21b815260040160405180910390fd5b506003805463ffffffff909216600160301b0269ffffffff00000000000019909216919091179055565b60016117d58161211a565b600354600160201b900460ff1615611800576040516303cb96db60e21b815260040160405180910390fd5b506003805460ff909216650100000000000265ff000000000019909216919091179055565b6000610fd760088361239d565b600161183d8161211a565b506003805462ff0000191662010000179055565b600161185c8161211a565b6000611872670de0b6b3a7640000612710613845565b90503361188082828661260a565b6110628160016125a7565b606061189682611aa9565b6118b35760405163677510db60e11b815260040160405180910390fd5b600280546118c0906136c5565b15905061198057610fd7600280546118d7906136c5565b80601f0160208091040260200160405190810160405280929190818152602001828054611903906136c5565b80156119505780601f1061192557610100808354040283529160200191611950565b820191906000526020600020905b81548152906001019060200180831161193357829003601f168201915b5050505050604051806040016040528060048152602001637b69647d60e01b81525061197b85612798565b6127dc565b919050565b60016119908161211a565b600754156119c95760405162461bcd60e51b81526020600482015260066024820152651b1bd8dad95960d21b6044820152606401611506565b600480546040516323b872dd60e01b81523392810192909252306024830152604482018490526001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b5050506007929092555050565b6117236123bf565b611a4d6120f3565b63389a75e1600c52806000526020600c208054421115611a7557636f5e88186000526004601cfd5b600090556112be816125cc565b611a8a6120f3565b8060601b611aa057637448fbae6000526004601cfd5b6112be816125cc565b600080611ab583611ac6565b6001600160a01b0316141592915050565b600068a20d6e21d0e525530868a20d6e21d0e525530a82611af468a20d6e21d0e525530f600187901b611093565b63ffffffff1681526020810191909152604001600020546001600160a01b03169392505050565b68a20d6e21d0e52553086001600160a01b038416611b4c57604051633a954ecd60e21b815260040160405180910390fd5b6000816002016000611b65846007016110938860011b90565b63ffffffff1681526020810191909152604001600020546001600160a01b03908116915086168114611ba95760405162a1148160e81b815260040160405180910390fd5b856001600160a01b0316836001600160a01b031614611c2d576001600160a01b03808716600090815260038401602090815260408083209387168352929052205460ff16611c2d5760008481526004830160205260409020546001600160a01b03848116911614611c2d57604051632ce44b5f60e11b815260040160405180910390fd5b6000611c38876128ff565b90506000611c45876128ff565b8254909150670de0b6b3a7640000908390601490611c74908490600160a01b90046001600160601b031661385c565b82546101009290920a6001600160601b0381810219909316918316021790915582546001600160a01b038116670de0b6b3a7640000600160a01b928390048416019092160217825550611cd860078501600188901b611cd3848b61296b565b612a0e565b6000868152600485016020908152604080832080546001600160a01b03191690556001600160a01b038b168352600687018252808320855463ffffffff60801b198116600160801b9182900463ffffffff90811660001901908116909202178755631fffffff600382901c168552925282205460059190911b60e0161c6001600160a01b038a166000908152600687016020526040902063ffffffff919091169150611d9c90611d906007880160018b811b01611093565b63ffffffff1683612a0e565b8154600163ffffffff600160801b80840482169283019091160263ffffffff60801b19909216919091178355611dee60078701611ddc84600190811b0190565b611cd360078a0160018d811b01611093565b6001600160a01b03891660009081526006870160205260409020611e1390828a612a0e565b611e266007870160018a811b0183612a0e565b5050866001600160a01b0316886001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef670de0b6b3a7640000604051611e7591815260200190565b60405180910390a35050505050505050565b60035465010000000000900460ff166000819003611ea457505050565b80670de0b6b3a764000002611eb8836116de565b11611ec257505050565b611ece61145383612355565b15611ed857505050565b638b78c6d819546001600160a01b0316836001600160a01b031603611efc57505050565b638b78c6d8600c9081526000849052602090205460011615611f1d57505050565b6040516303cab2ff60e21b815260040160405180910390fd5b600354600160301b900463ffffffff166000819003611f5457505050565b600080611f7384611f6487612355565b6001600160581b031690612a42565b9150915060028110611fa05780800283026301312d00808210611f94578091505b611f9d82612ab9565b50505b611faa8583612aed565b5050505050565b6000611421836001600160a01b038416612b32565b600754600003611fd257565b600e54600f54600c54611fe591906136f9565b1015611fed57565b6000611ff96008612c25565b905080516000036120075750565b80516011546040516bffffffffffffffffffffffff193260601b1660208201524260348201526054810191909152600091906074016040516020818303038152906040528051906020012060001c61205f9190613892565b9050600e54600f600082825461207591906138a6565b92505081905550600060126000848481518110612094576120946138b9565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000209050600e548160000160008282546120d491906138a6565b9091555050601180546001019055505050565b6112d382826000612c32565b638b78c6d819543314611723576382b429006000526004601cfd5b6112d382826001612c32565b638b78c6d8195433146112be57638b78c6d8600c5233600052806020600c2054166112be576382b429006000526004601cfd5b612158838383612c8b565b6121628383611e87565b816001600160a01b0316836001600160a01b031614612185576121858382611f36565b601054600160a81b900460ff161561219c57505050565b6006546001600160a01b039081169084160361220e576001600160a01b0382163b1580156121d557506121d16012600a6136b6565b8110155b156121e7576121e5600883613158565b505b6121f26064826138cf565b600d600082825461220391906138a6565b909155506122819050565b6006546001600160a01b0390811690831603612281576122306012600a6136b6565b612239846116de565b101561224c5761224a600884611fb1565b505b60105460ff1615612273576122626064826138cf565b600c600082825461220391906138a6565b6010805460ff191660011790555b6001600160a01b0383163b1580156122ab57506122a06012600a6136b6565b6122a9846116de565b105b156122bd576122bb600884611fb1565b505b611592611fc6565b60006122d0836128ff565b8054909150600160581b900460021615158215151461230b57805460ff600160581b80830482166002189091160260ff60581b199091161781555b826001600160a01b03167fb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d642039383604051612348911515815260200190565b60405180910390a2505050565b6001600160a01b0316600090815268a20d6e21d0e525531060205260409020546001600160581b031690565b60003860003847855af16112be5763b12d13eb6000526004601cfd5b6001600160a01b03811660009081526001830160205260408120541515611421565b6010805460ff60a81b1916600160a81b1790556004805460408051608081018252600754815230602082019081526fffffffffffffffffffffffffffffffff82840181815260608401828152945163fc6f786560e01b815293519684019690965290516001600160a01b03908116602484015294518116604483015291518216606482015290928392169063fc6f78659060840160408051808303816000875af1158015612471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249591906138e3565b50506003546040516370a0823160e01b8152306004820152600091600160501b90046001600160a01b0316906370a0823190602401602060405180830381865afa1580156124e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250b9190613907565b9050801561259557600354600b5460405163a9059cbb60e01b81526001600160a01b03918216600482015260248101849052600160501b909204169063a9059cbb906044016020604051808303816000875af115801561256f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612593919061370c565b505b50506010805460ff60a81b1916905550565b6112d3826125c7836125b886612355565b6001600160581b03169061316d565b612aed565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b68a20d6e21d0e52553088054600160201b900463ffffffff161561264157604051633ab534b960e21b815260040160405180910390fd5b6001600160a01b038216612668576040516339a84a7b60e01b815260040160405180910390fd5b61267182613193565b805467ffffffff000000001916600160201b1781556001810180546001600160a01b0384166001600160a01b03199091161790558315611062576001600160a01b0383166126d257604051633a954ecd60e21b815260040160405180910390fd5b6b0de0b6b39983494c589bffff8411156126ff5760405163e5cfe95760e01b815260040160405180910390fd5b80546bffffffffffffffffffffffff60601b1916600160601b6001600160601b038616021781556000612731846128ff565b80546001600160a01b03908116600160a01b6001600160601b038916021782556040518781529192508516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3611faa8460016122c5565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a9004806127b3575050819003601f19909101908152919050565b606083518351835160208701965060208601955060208501945060206040510193508287018383116128ae5760018382030160006020851061281d57508388205b601f851660200360031b89515b8b51818118831c6128955783156128645783888e201461286457808a5260019c8d019c90990198848d1061285e57506128a9565b5061282a565b60005b8b8101518b82015260200187811061286757509b87019b98860198871561289557848d1061285e57506128a9565b895260019b8c019b90980197838c1061282a575b505050505b84935060206040510194508781038585030192505b808810156128de5787518452602097880197909301926128c3565b50506000818401908152602001604052601f19909201918252509392505050565b6001600160a01b038116600090815268a20d6e21d0e5255310602052604081208054909168a20d6e21d0e525530891600160581b90046001169003612965576001833b1561294b576002175b825460ff909116600160581b0260ff60581b199091161782555b50919050565b8154600160601b900463ffffffff1668a20d6e21d0e52553086000829003612a0757805481906000906129a39063ffffffff16613920565b825463ffffffff8083166101009490940a848102910219909116179092558554600160601b820263ffffffff60601b199091161786556000908152600283016020526040902080546001600160a01b0386166001600160a01b031990911617905591505b5092915050565b826020528160031c60005260406000206007831660051b815463ffffffff8482841c188116831b8218845550505050505050565b600080605784901c60011615612a5d57508290506000612ab2565b637fffffff620151804204811690603886901c1666ffffffffffffff8616818314612a89575081905060005b60389190911b66ffffffffffffff602887901c811692909201918216179350620de0b690049150505b9250929050565b80600117601052605b8104607882110260005b818114612ae25760108080209052600101612acc565b50506010516112be57fe5b6001600160a01b0391909116600090815268a20d6e21d0e52553106020526040902080546affffffffffffffffffffff19166001600160581b03909216919091179055565b60008181526001830160205260408120548015612c1b576000612b566001836136f9565b8554909150600090612b6a906001906136f9565b9050818114612bcf576000866000018281548110612b8a57612b8a6138b9565b9060005260206000200154905080876000018481548110612bad57612bad6138b9565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612be057612be0613943565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fd7565b6000915050610fd7565b60606000611421836131c5565b638b78c6d8600c52826000526020600c20805483811783612c54575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b6001600160a01b038216612cb257604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553086000612cc7856128ff565b90506000612cd4856128ff565b9050612d0f6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b825463ffffffff600160801b808304821660808501528454041660a08301526001600160601b03600160a01b9091041660408201819052851115612d6657604051631e9acf1760e31b815260040160405180910390fd5b6040810180518690039081905283546001600160601b03808316600160a01b9081026001600160a01b03938416178755855481810483168a01606087018190529092160291161783556080820151612dcc91670de0b6b3a7640000900480821191030290565b81528154600160581b9004600216600003612e3b57856001600160a01b0316876001600160a01b031603612e0857805160808201510360a08201525b612e35670de0b6b3a7640000826060015181612e2657612e2661387c565b048260a0015180821191030290565b60208201525b6000612e8582602001518360000151016040805180820190915260608152600060208201526040805101828152806020018360051b81016040528183528083602001525050919050565b825190915015612f7f576001600160a01b0388166000908152600686016020526040902060808301518351875463ffffffff600160401b808304821684900382160263ffffffff60401b199092169190911789558754918303908116600160801b0263ffffffff60801b199092169190911787555b60001991909101600381901c600090815260208490526040812054919291600584901b60e0161c63ffffffff169050612f398960070182600080613221565b600081815260048a016020908152604090912080546001600160a01b0319169055858101805160089390931b60608f901b17600117835291019052808203612efa575050505b6020820151156130e0576001600160a01b03871660009081526006860160209081526040822060a085015191850151909290820190612fbe878c61296b565b8954602088015163ffffffff60401b19821663ffffffff600160401b80850482169093018116909202178c55895463ffffffff60801b1916600160801b86831602178a55919250670de0b6b3a7640000600160601b82046001600160601b03160491600160201b909104165b61303b8b6007016110938360011b90565b63ffffffff161561305a5760010181811115613055575060015b61302a565b613065868683612a0e565b61307a8b600701828588806001019950613221565b6130a4878e8360008360200151818360081b8560601b171781526020810185602001525050505050565b600101818111156130b3575060015b83850361302a578a5463ffffffff909116600160201b0267ffffffff0000000019909116178a5550505050505b805151156131015760018501546131019082906001600160a01b0316613267565b50856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405161314791815260200190565b60405180910390a350505050505050565b6000611421836001600160a01b0384166132a0565b60006001605784901c1615158215151461318c57600160571b92909218915b5090919050565b630f4599e560005233602052602060006024601c6000855af1600160005114166112be5763d125259c6000526004601cfd5b60608160000180548060200260200160405190810160405280929190818152602001828054801561321557602002820191906000526020600020905b815481526020019060010190808311613201575b50505050509050919050565b8163ffffffff168160201b17846020528360021c60005260406000206003851660061b815467ffffffffffffffff8482841c188116831b82188455505050505050505050565b81516040810363263c69d68152602080820152815160051b604401915060208183601c84016000875af160018251141661106257600081fd5b60008181526001830160205260408120546132e757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fd7565b506000610fd7565b600060208083528351808285015260005b8181101561331c57858101830151858201604001528201613300565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461198057600080fd5b6000806040838503121561336757600080fd5b6133708361333d565b946020939093013593505050565b60006020828403121561339057600080fd5b5035919050565b6000806000606084860312156133ac57600080fd5b6133b58461333d565b92506133c36020850161333d565b9150604084013590509250925092565b6000602082840312156133e557600080fd5b6114218261333d565b80151581146112be57600080fd5b60006020828403121561340e57600080fd5b8135611421816133ee565b6000806040838503121561342c57600080fd5b6134358361333d565b91506020830135613445816133ee565b809150509250929050565b60008083601f84011261346257600080fd5b50813567ffffffffffffffff81111561347a57600080fd5b602083019150836020828501011115612ab257600080fd5b600080602083850312156134a557600080fd5b823567ffffffffffffffff8111156134bc57600080fd5b6134c885828601613450565b90969095509350505050565b600080600080604085870312156134ea57600080fd5b843567ffffffffffffffff8082111561350257600080fd5b61350e88838901613450565b9096509450602087013591508082111561352757600080fd5b5061353487828801613450565b95989497509550505050565b60006020828403121561355257600080fd5b813563ffffffff8116811461142157600080fd5b60006020828403121561357857600080fd5b813560ff8116811461142157600080fd5b6000806040838503121561359c57600080fd5b6135a58361333d565b91506135b36020840161333d565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561360d5781600019048211156135f3576135f36135bc565b8085161561360057918102915b93841c93908002906135d7565b509250929050565b60008261362457506001610fd7565b8161363157506000610fd7565b816001811461364757600281146136515761366d565b6001915050610fd7565b60ff841115613662576136626135bc565b50506001821b610fd7565b5060208310610133831016604e8410600b8410161715613690575081810a610fd7565b61369a83836135d2565b80600019048211156136ae576136ae6135bc565b029392505050565b600061142160ff841683613615565b600181811c908216806136d957607f821691505b60208210810361296557634e487b7160e01b600052602260045260246000fd5b81810381811115610fd757610fd76135bc565b60006020828403121561371e57600080fd5b8151611421816133ee565b634e487b7160e01b600052604160045260246000fd5b601f82111561159257600081815260208120601f850160051c810160208610156137665750805b601f850160051c820191505b818110156116b957828155600101613772565b67ffffffffffffffff83111561379d5761379d613729565b6137b1836137ab83546136c5565b8361373f565b6000601f8411600181146137e557600085156137cd5750838201355b600019600387901b1c1916600186901b178355611faa565b600083815260209020601f19861690835b8281101561381657868501358255602094850194600190920191016137f6565b50868210156138335760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b8082028115828204841417610fd757610fd76135bc565b6001600160601b03828116828216039080821115612a0757612a076135bc565b634e487b7160e01b600052601260045260246000fd5b6000826138a1576138a161387c565b500690565b80820180821115610fd757610fd76135bc565b634e487b7160e01b600052603260045260246000fd5b6000826138de576138de61387c565b500490565b600080604083850312156138f657600080fd5b505080516020909101519092909150565b60006020828403121561391957600080fd5b5051919050565b600063ffffffff808316818103613939576139396135bc565b6001019392505050565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220799851e5007eec0e091756974405c2d46386bbe660cefaf8cb756a1ba77489c664736f6c63430008130033
Deployed Bytecode Sourcemap
217597:12349:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;227604:4;;;;;;;;;-1:-1:-1;;;;;227604:4:0;-1:-1:-1;;;;;227598:19:0;;227625:9;227598:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;217597:12349;142884:20;166776:22;173428:20;166876:3;166853:26;166959:10;166945:24;;;166941:377;;167004:14;;;;-1:-1:-1;;;;;167004:14:0;166990:10;:28;166986:58;;167027:17;;-1:-1:-1;;;167027:17:0;;;;;;;;;;;166986:58;167081:4;167063:8;:22;167059:36;;;167087:8;;;167059:36;167158:4;173428:20;-1:-1:-1;;;;;167261:26:0;;;167112:13;167261:26;;;:19;;;:26;;;;;;;;167229:4;173428:20;167261:36;;;;;;;;;;;167253:53;;167261:36;;:44;;167304:1;167261:44;;;167300:1;167261:44;167253:53;;:7;:53::i;:::-;166971:347;;166941:377;167364:10;167378;167364:24;167360:262;;167423:14;;;;-1:-1:-1;;;;;167423:14:0;167409:10;:28;167405:58;;167446:17;;-1:-1:-1;;;167446:17:0;;;;;;;;;;;167405:58;167500:4;167482:8;:22;167478:36;;;167506:8;;;167478:36;167558:4;173428:20;167580:30;167596:12;173428:20;167596:8;:12::i;:::-;-1:-1:-1;;;;;167580:30:0;:7;:30::i;:::-;167390:232;167360:262;167700:10;167714;167700:24;167696:502;;167759:14;;;;-1:-1:-1;;;;;167759:14:0;167745:10;:28;167741:58;;167782:17;;-1:-1:-1;;;167782:17:0;;;;;;;;;;;167741:58;167836:4;167818:8;:22;167814:36;;;167842:8;;;167814:36;167912:4;173428:20;167977:4;173428:20;168026:4;173428:20;168096:4;173428:20;168120:41;173428:20;;;;168120:16;:41::i;:::-;168176:10;168184:1;168176:7;:10::i;:::-;167726:472;;;;167696:502;168267:10;168281;168267:24;168263:451;;168326:14;;;;-1:-1:-1;;;;;168326:14:0;168312:10;:28;168308:58;;168349:17;;-1:-1:-1;;;168349:17:0;;;;;;;;;;;168308:58;168403:4;168385:8;:22;168381:36;;;168409:8;;;168381:36;-1:-1:-1;;;;;168607:4:0;173428:20;165896:47;;;;;;;:36;:47;;;;;;;;168482:4;173428:20;165896:57;;;;;;;;;;:68;;-1:-1:-1;;165896:68:0;168532:4;173428:20;168518:24;;165896:68;;;;;;168518:24;168692:10;168700:1;168692:7;:10::i;:::-;168293:421;;;168263:451;168779:10;168793;168779:24;168775:427;;168838:14;;;;-1:-1:-1;;;;;168838:14:0;168824:10;:28;168820:58;;168861:17;;-1:-1:-1;;;168861:17:0;;;;;;;;;;;168820:58;168915:4;168897:8;:22;168893:36;;;168921:8;;;168893:36;168994:4;173428:20;169043:4;173428:20;169113:4;173428:20;169137:53;169153:35;173428:20;;;169153:11;:35::i;169137:53::-;168805:397;;;168775:427;169252:10;169266;169252:24;169248:266;;169311:14;;;;-1:-1:-1;;;;;169311:14:0;169297:10;:28;169293:58;;169334:17;;-1:-1:-1;;;169334:17:0;;;;;;;;;;;169293:58;169388:4;169370:8;:22;169366:36;;;169394:8;;;169366:36;169446:4;173428:20;169468:34;169484:16;173428:20;169484:12;:16::i;169468:34::-;169278:236;169248:266;169565:10;169579;169565:24;169561:282;;169624:14;;;;-1:-1:-1;;;;;169624:14:0;169610:10;:28;169606:58;;169647:17;;-1:-1:-1;;;169647:17:0;;;;;;;;;;;169606:58;169701:4;169683:8;:22;169679:36;;;169707:8;;;169679:36;169778:4;173428:20;169802:29;169810:20;173428;-1:-1:-1;;;;;163712:37:0;163685:7;163712:37;;;:30;:37;;;;;:49;;-1:-1:-1;;;163712:49:0;;;;;163616:153;169810:20;169802:7;:29::i;:::-;169591:252;169561:282;169889:10;169903;169889:24;169885:209;;169948:14;;;;-1:-1:-1;;;;;169948:14:0;169934:10;:28;169930:58;;169971:17;;-1:-1:-1;;;169971:17:0;;;;;;;;;;;169930:58;170025:4;170007:8;:22;170003:36;;;170031:8;;;170003:36;142884:20;163524:33;170056:26;;-1:-1:-1;;;163524:33:0;;;;169802:7;:29::i;170056:26::-;170141:10;170155;170141:24;170137:67;;170182:10;170190:1;170182:7;:10::i;218943:28::-;;;;;;;;;;-1:-1:-1;218943:28:0;;;;;;;;;;;;;;186:4:1;174:17;;;156:36;;144:2;129:18;218943:28:0;;;;;;;;221629:92;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;146285:275::-;;;;;;;;;;-1:-1:-1;146285:275:0;;;;;:::i;:::-;;:::i;:::-;;;1358:14:1;;1351:22;1333:41;;1321:2;1306:18;146285:275:0;1193:187:1;219863:21:0;;;;;;;;;;-1:-1:-1;219863:21:0;;;;;;;-1:-1:-1;;;;;219863:21:0;;;;;;-1:-1:-1;;;;;1549:32:1;;;1531:51;;1519:2;1504:18;219863:21:0;1385:203:1;219144:26:0;;;;;;;;;;-1:-1:-1;219144:26:0;;;;-1:-1:-1;;;;;219144:26:0;;;218785:31;;;;;;;;;;-1:-1:-1;218785:31:0;;;;;;;;;;;145562:126;;;;;;;;;;-1:-1:-1;142884:20:0;145649:30;-1:-1:-1;;;145649:30:0;;-1:-1:-1;;;;;145649:30:0;145562:126;;;1970:25:1;;;1958:2;1943:18;145562:126:0;1824:177:1;120504:111:0;;;;;;:::i;:::-;;:::i;119953:125::-;;;;;;:::i;:::-;;:::i;121581:141::-;;;;;;;;;;-1:-1:-1;121581:141:0;;;;;:::i;:::-;121159:15;121153:4;121146:29;;;121660:4;121189:18;;;;121291:4;121275:21;;;121269:28;121684:21;;:30;;121581:141;225728:114;;;;;;;;;;;;;:::i;147920:512::-;;;;;;;;;;-1:-1:-1;147920:512:0;;;;;:::i;:::-;;:::i;106804:630::-;;;:::i;160711:282::-;;;;;;;;;;-1:-1:-1;160711:282:0;;;;;:::i;:::-;;:::i;161105:100::-;;;;;;;;;;-1:-1:-1;161105:100:0;;;;;:::i;:::-;;:::i;219812:25::-;;;;;;;;;;;;;;;;120953:362;;;;;;;;;;-1:-1:-1;120953:362:0;;;;;:::i;:::-;121159:15;121153:4;121146:29;;;121013:13;121189:18;;;;121291:4;121275:21;;121269:28;;120953:362;145421:76;;;;;;;;;;-1:-1:-1;145487:2:0;145421:76;;225008:123;;;;;;;;;;-1:-1:-1;225008:123:0;;;;;:::i;:::-;;:::i;227295:121::-;;;;;;;;;;;;;:::i;227424:119::-;;;;;;;;;;-1:-1:-1;227424:119:0;;;;;:::i;:::-;;:::i;218825:31::-;;;;;;;;;;-1:-1:-1;218825:31:0;;;;;;;;;;;120227:127;;;;;;:::i;:::-;;:::i;228555:436::-;;;;;;;;;;;;;:::i;163268:119::-;;;;;;;;;;-1:-1:-1;163348:31:0;;-1:-1:-1;;;;;163348:31:0;163268:119;;121380:136;;;;;;;;;;-1:-1:-1;121380:136:0;;;;;:::i;:::-;121159:15;121153:4;121146:29;;;121458:4;121189:18;;;;121291:4;121275:21;;;121269:28;121482:21;:26;;;121380:136;218980:27;;;;;;;;;;-1:-1:-1;218980:27:0;;;;-1:-1:-1;;;218980:27:0;;;;;;;;;3258:10:1;3246:23;;;3228:42;;3216:2;3201:18;218980:27:0;3084:192:1;226143:184:0;;;;;;;;;;-1:-1:-1;226143:184:0;;;;;:::i;:::-;;:::i;226646:98::-;;;;;;;;;;;;;:::i;107519:466::-;;;:::i;226752:165::-;;;;;;;;;;-1:-1:-1;226752:165:0;;;;;:::i;:::-;;:::i;227043:244::-;;;;;;;;;;-1:-1:-1;227043:244:0;;;;;:::i;:::-;;:::i;218751:25::-;;;;;;;;;;-1:-1:-1;218751:25:0;;;;;;;;226925:110;;;;;;;;;;;;;:::i;219177:21::-;;;;;;;;;;;;;;;;145757:143;;;;;;;;;;-1:-1:-1;145757:143:0;;;;;:::i;:::-;;:::i;106539:102::-;;;:::i;229819:122::-;;;;;;;;;;-1:-1:-1;229819:122:0;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;229914:19:0;;;;;:10;:19;;;;;;;;;229907:26;;;;;;;;;;;;;;;;;;;;229819:122;;;;;5314:13:1;;5296:32;;5384:4;5372:17;;;5366:24;5344:20;;;5337:54;;;;5269:18;229819:122:0;5096:301:1;217997:44:0;;;;;;;;;;;;123072:6;217997:44;;109244:187;;;;;;;;;;-1:-1:-1;;;109395:18:0;109244:187;;221729:96;;;;;;;;;;;;;:::i;147073:150::-;;;;;;;;;;-1:-1:-1;147073:150:0;;;;;:::i;:::-;;:::i;226030:105::-;;;;;;;;;;;;;:::i;226453:185::-;;;;;;;;;;-1:-1:-1;226453:185:0;;;;;:::i;:::-;;:::i;225850:172::-;;;;;;;;;;-1:-1:-1;225850:172:0;;;;;:::i;:::-;;:::i;229700:111::-;;;;;;;;;;-1:-1:-1;229700:111:0;;;;;:::i;:::-;;:::i;226335:110::-;;;;;;;;;;;;;:::i;219774:29::-;;;;;;;;;;;;;;;;225411:309;;;;;;;;;;-1:-1:-1;225411:309:0;;;;;:::i;:::-;;:::i;221833:283::-;;;;;;;;;;-1:-1:-1;221833:283:0;;;;;:::i;:::-;;:::i;218865:27::-;;;;;;;;;;-1:-1:-1;218865:27:0;;;;;;;;;;;227651:218;;;;;;;;;;-1:-1:-1;227651:218:0;;;;;:::i;:::-;;:::i;145998:151::-;;;;;;;;;;-1:-1:-1;145998:151:0;;;;;:::i;:::-;-1:-1:-1;;;;;146097:35:0;;;146070:7;146097:35;;;:28;:35;;;;;;;;:44;;;;;;;;;;;;;145998:151;219715:23;;;;;;;;;;;;;;;;218901:33;;;;;;;;;;-1:-1:-1;218901:33:0;;;;-1:-1:-1;;;218901:33:0;;;;;;219745:22;;;;;;;;;;;;;;;;228490:57;;;;;;;;;;;;;:::i;108176:724::-;;;;;;:::i;:::-;;:::i;106113:358::-;;;;;;:::i;:::-;;:::i;219655:27::-;;;;;;;;;;-1:-1:-1;219655:27:0;;;;-1:-1:-1;;;;;219655:27:0;;;109537:449;;;;;;;;;;-1:-1:-1;109537:449:0;;;;;:::i;:::-;109816:19;109810:4;109803:33;;;109660:14;109850:26;;;;109962:4;109946:21;;109940:28;;109537:449;173559:185;173692:1;173686:4;173679:15;173721:4;173715;173708:18;164228:163;164289:7;164314:11;164322:2;164314:7;:11::i;:::-;164309:44;;164334:19;;-1:-1:-1;;;164334:19:0;;;;;;;;;;;164309:44;164371:12;164380:2;164371:8;:12::i;:::-;164364:19;164228:163;-1:-1:-1;;164228:163:0:o;223388:431::-;223523:47;223546:4;223552:2;223556;223560:9;223523:22;:47::i;:::-;223581:31;223603:4;223609:2;223581:21;:31::i;:::-;223635:2;-1:-1:-1;;;;;223627:10:0;:4;-1:-1:-1;;;;;223627:10:0;;223623:41;;223639:25;223653:4;139941:8;223639:13;:25::i;:::-;-1:-1:-1;;;;;223681:16:0;;;:21;:59;;;;-1:-1:-1;223724:16:0;145487:2;223724;:16;:::i;:::-;223706:15;223716:4;223706:9;:15::i;:::-;:34;223681:59;223677:112;;;223757:20;:7;223772:4;223757:14;:20::i;:::-;;223677:112;223801:8;:6;:8::i;:::-;223388:431;;;;:::o;165112:527::-;165234:7;142884:20;165234:7;165331:16;165234:7;165348:31;165353:4;174125:1;174120:6;;;165359:19;174518:1;174509:10;;;174459:13;174501:19;;;;;;;;;;;;;174540:1;174525:16;;;;;;174501:41;;174385:166;165348:31;165331:49;;;;;;;;;;;;;-1:-1:-1;165331:49:0;;-1:-1:-1;;;;;165331:49:0;;;;-1:-1:-1;165397:18:0;;;;165393:171;;-1:-1:-1;;;;;165437:26:0;;;;;;;:19;;;:26;;;;;;;;:37;;;;;;;;;;;;165432:121;;165502:35;;-1:-1:-1;;;165502:35:0;;;;;;;;;;;165432:121;165576:20;;;;:16;;;;:20;;;;;;:30;;-1:-1:-1;;;;;165576:30:0;;-1:-1:-1;;;;;;165576:30:0;;;;;;165626:5;-1:-1:-1;165112:527:0;;;;;:::o;164700:192::-;164765:7;164790:11;164798:2;164790:7;:11::i;:::-;164785:44;;164810:19;;-1:-1:-1;;;164810:19:0;;;;;;;;;;;164785:44;-1:-1:-1;164847:37:0;;;;:33;:37;;;;;;-1:-1:-1;;;;;164847:37:0;;164700:192::o;221629:92::-;221675:13;221708:5;221701:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;221629:92;:::o;146285:275::-;146359:4;;142884:20;146444:10;146432:23;;;;:11;;;:23;;;;;;;;-1:-1:-1;;;;;146432:32:0;;;;;;;;;;;;:41;;;146491:37;1970:25:1;;;146432:11:0;;-1:-1:-1;146432:32:0;;146491:37;;1943:18:1;146491:37:0;;;;;;;-1:-1:-1;146548:4:0;;146285:275;-1:-1:-1;;;146285:275:0:o;120504:111::-;120576:31;120589:10;120601:5;120576:12;:31::i;:::-;120504:111;:::o;119953:125::-;110383:13;:11;:13::i;:::-;120046:24:::1;120058:4;120064:5;120046:11;:24::i;:::-;119953:125:::0;;:::o;225728:114::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;225806:21:0::1;:28:::0;;-1:-1:-1;;225806:28:0::1;-1:-1:-1::0;;;225806:28:0::1;::::0;;225728:114::o;147920:512::-;-1:-1:-1;;;;;148099:17:0;;148008:4;148099:17;;;:11;:17;;;;;;;;148117:10;148099:29;;;;;;;;142884:20;;-1:-1:-1;;148145:28:0;;148141:220;;148203:7;148194:6;:16;148190:52;;;148219:23;;-1:-1:-1;;;148219:23:0;;;;;;;;;;;148190:52;-1:-1:-1;;;;;148286:17:0;;;;;;:11;;;:17;;;;;;;;148304:10;148286:29;;;;;;;148318:16;;;148286:48;;148141:220;148373:27;148383:4;148389:2;148393:6;148373:9;:27::i;:::-;-1:-1:-1;148420:4:0;;147920:512;-1:-1:-1;;;;;147920:512:0:o;106804:630::-;106899:15;105729:9;106917:46;;:15;:46;106899:64;;107135:19;107129:4;107122:33;107186:8;107180:4;107173:22;107243:7;107236:4;107230;107220:21;107213:38;107392:8;107345:45;107342:1;107339;107334:67;107035:381;106804:630::o;160711:282::-;-1:-1:-1;;;;;160812:33:0;;160771:4;160812:33;;;:30;:33;;;;;160860:7;;-1:-1:-1;;;160860:7:0;;140325:6;160860:40;:45;;160856:69;;173138:14;;160914:11;160907:18;160711:282;-1:-1:-1;;;160711:282:0:o;160856:69::-;160943:7;-1:-1:-1;;;160943:7:0;;140462:6;160943:37;:42;;;160711:282;-1:-1:-1;;160711:282:0:o;161105:100::-;161165:32;161177:10;161189:7;161165:11;:32::i;225008:123::-;225068:4;225092:31;:15;225100:6;225092:7;:15::i;:::-;96314:2;97454:28;;;:33;;;97369:126;227295:121;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;227362:46:::1;227397:10;227362:34;:46::i;227424:119::-:0;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;227513:14:0::1;:22:::0;227424:119::o;120227:127::-;110383:13;:11;:13::i;:::-;120321:25:::1;120334:4;120340:5;120321:12;:25::i;228555:436::-:0;228644:10;228602:28;228633:22;;;:10;:22;;;;;228706:18;;;;228683:20;;228633:22;;228602:28;228683:41;;228706:18;228683:41;:::i;:::-;228666:58;-1:-1:-1;228745:28:0;:7;228762:10;228745:16;:28::i;:::-;:42;;;;;228786:1;228777:6;:10;228745:42;228737:59;;;;-1:-1:-1;;;228737:59:0;;;;;;8457:2:1;8439:21;;;8496:1;8476:18;;;8469:29;-1:-1:-1;;;8529:2:1;8514:18;;8507:34;8573:2;8558:18;;8255:327;228737:59:0;;;;;;;;;228809:26;:7;228824:10;228809:14;:26::i;:::-;-1:-1:-1;228869:20:0;;228848:18;;;:41;228900:10;:8;:10::i;:::-;228931:50;;-1:-1:-1;;;228931:50:0;;228962:10;228931:50;;;8761:51:1;8828:18;;;8821:34;;;228946:4:0;;228931:30;;8734:18:1;;228931:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;228581:410;;228555:436::o;226143:184::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;226245:15:::1;::::0;;;::::1;;;226241:36;;;226269:8;;-1:-1:-1::0;;;226269:8:0::1;;;;;;;;;;;226241:36;226288:31;226304:6;226312;226288:15;:31::i;226646:98::-:0;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;226716:13:0::1;:20:::0;;-1:-1:-1;;226716:20:0::1;226732:4;226716:20;::::0;;226646:98::o;107519:466::-;107725:19;107719:4;107712:33;107772:8;107766:4;107759:22;107825:1;107818:4;107812;107802:21;107795:32;107958:8;107912:44;107909:1;107906;107901:66;107519:466::o;226752:165::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;226849:13:::1;::::0;::::1;;226845:34;;;226871:8;;-1:-1:-1::0;;;226871:8:0::1;;;;;;;;;;;226845:34;226890:8;:19;226901:8:::0;;226890;:19:::1;:::i;227043:244::-:0;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;227191:19:::1;::::0;::::1;::::0;::::1;;;227187:40;;;227219:8;;-1:-1:-1::0;;;227219:8:0::1;;;;;;;;;;;227187:40;227238:5;:13;227246:5:::0;;227238;:13:::1;:::i;:::-;-1:-1:-1::0;227262:7:0::1;:17;227272:7:::0;;227262;:17:::1;:::i;:::-;;227043:244:::0;;;;;:::o;226925:110::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;227001:19:0::1;:26:::0;;-1:-1:-1;;227001:26:0::1;;;::::0;;226925:110::o;145757:143::-;-1:-1:-1;;;;;145847:37:0;145820:7;145847:37;;;:30;:37;;;;;:45;-1:-1:-1;;;145847:45:0;;-1:-1:-1;;;;;145847:45:0;;145757:143::o;106539:102::-;110383:13;:11;:13::i;:::-;106612:21:::1;106630:1;106612:9;:21::i;:::-;106539:102::o:0;221729:96::-;221777:13;221810:7;221803:14;;;;;:::i;147073:150::-;147143:4;147160:33;147170:10;147182:2;147186:6;147160:9;:33::i;:::-;-1:-1:-1;147211:4:0;147073:150;;;;:::o;226030:105::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;226105:15:0::1;:22:::0;;-1:-1:-1;;226105:22:0::1;::::0;::::1;::::0;;226030:105::o;226453:185::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;226553:19:::1;::::0;;;::::1;;;226549:40;;;226581:8;;-1:-1:-1::0;;;226581:8:0::1;;;;;;;;;;;226549:40;-1:-1:-1::0;226600:13:0::1;:30:::0;;::::1;::::0;;::::1;-1:-1:-1::0;;;226600:30:0::1;-1:-1:-1::0;;226600:30:0;;::::1;::::0;;;::::1;::::0;;226453:185::o;225850:172::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;225942:21:::1;::::0;-1:-1:-1;;;225942:21:0;::::1;;;225938:42;;;225972:8;;-1:-1:-1::0;;;225972:8:0::1;;;;;;;;;;;225938:42;-1:-1:-1::0;225991:15:0::1;:23:::0;;::::1;::::0;;::::1;::::0;::::1;-1:-1:-1::0;;225991:23:0;;::::1;::::0;;;::::1;::::0;;225850:172::o;229700:111::-;229754:4;229778:25;:7;229795;229778:16;:25::i;226335:110::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;-1:-1:-1;226411:19:0::1;:26:::0;;-1:-1:-1;;226411:26:0::1;::::0;::::1;::::0;;226335:110::o;225411:309::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;225494:26:::1;225523:12;139941:8;225523:5;:12;:::i;:::-;225494:41:::0;-1:-1:-1;225575:10:0::1;225596:64;225494:41:::0;225575:10;225653:6;225596:16:::1;:64::i;:::-;225671:41;225687:18;225707:4;225671:15;:41::i;221833:283::-:0;221893:20;221931:11;221939:2;221931:7;:11::i;:::-;221926:44;;221951:19;;-1:-1:-1;;;221951:19:0;;;;;;;;;;;221926:44;221991:8;221985:22;;;;;:::i;:::-;:27;;-1:-1:-1;221981:128:0;;222038:59;222056:8;222038:59;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;222038:59:0;;;222074:22;222093:2;222074:18;:22::i;:::-;222038:17;:59::i;221981:128::-;221833:283;;;:::o;227651:218::-;123072:6;122411:25;122430:5;122411:18;:25::i;:::-;227737:6:::1;::::0;:11;227729:30:::1;;;::::0;-1:-1:-1;;;227729:30:0;;11681:2:1;227729:30:0::1;::::0;::::1;11663:21:1::0;11720:1;11700:18;;;11693:29;-1:-1:-1;;;11738:18:1;;;11731:36;11784:18;;227729:30:0::1;11479:329:1::0;227729:30:0::1;227770:15;::::0;;:64:::1;::::0;-1:-1:-1;;;227770:64:0;;227799:10:::1;227770:64:::0;;::::1;12053:34:1::0;;;;227819:4:0::1;12103:18:1::0;;;12096:43;12155:18;;;12148:34;;;-1:-1:-1;;;;;227770:15:0::1;::::0;:28:::1;::::0;11988:18:1;;227770:64:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;;227845:6:0::1;:16:::0;;;;-1:-1:-1;;227651:218:0:o;228490:57::-;228529:10;:8;:10::i;108176:724::-;110383:13;:11;:13::i;:::-;108414:19:::1;108408:4;108401:33;108461:12;108455:4;108448:26;108524:4;108518;108508:21;108632:12;108626:19;108613:11;108610:36;108607:160;;;108679:10;108673:4;108666:24;108747:4;108741;108734:18;108607:160;108846:1;108825:23:::0;;108869::::1;108879:12:::0;108869:9:::1;:23::i;106113:358::-:0;110383:13;:11;:13::i;:::-;106288:8:::1;106284:2;106280:17;106270:153;;106331:10;106325:4;106318:24;106403:4;106397;106390:18;106270:153;106444:19;106454:8;106444:9;:19::i;164443:118::-:0;164503:4;;164527:12;164536:2;164527:8;:12::i;:::-;-1:-1:-1;;;;;164527:26:0;;;;164443:118;-1:-1:-1;;164443:118:0:o;163908:199::-;163969:7;142884:20;164050:16;163969:7;164067:31;164072:4;174125:1;174120:6;;;164078:19;174035:99;164067:31;164050:49;;;;;;;;;;;;;-1:-1:-1;164050:49:0;;-1:-1:-1;;;;;164050:49:0;;163908:199;-1:-1:-1;;;163908:199:0:o;157701:1507::-;142884:20;-1:-1:-1;;;;;157895:16:0;;157891:52;;157920:23;;-1:-1:-1;;;157920:23:0;;;;;;;;;;;157891:52;157956:13;157972:1;:16;;:49;157989:31;157994:1;:4;;158000:19;158016:2;174125:1;174120:6;;174035:99;157989:31;157972:49;;;;;;;;;;;;;-1:-1:-1;157972:49:0;;-1:-1:-1;;;;;157972:49:0;;;;-1:-1:-1;158038:13:0;;;;158034:54;;158060:28;;-1:-1:-1;;;158060:28:0;;;;;;;;;;;158034:54;158118:4;-1:-1:-1;;;;;158105:17:0;:9;-1:-1:-1;;;;;158105:17:0;;158101:250;;-1:-1:-1;;;;;158144:25:0;;;;;;;:19;;;:25;;;;;;;;:36;;;;;;;;;;;;158139:201;;158218:20;;;;:16;;;:20;;;;;;-1:-1:-1;;;;;158205:33:0;;;158218:20;;158205:33;158201:124;;158270:35;;-1:-1:-1;;;158270:35:0;;;;;;;;;;;158201:124;158363:35;158401:18;158414:4;158401:12;:18::i;:::-;158363:56;;158430:33;158466:16;158479:2;158466:12;:16::i;:::-;158495:39;;158430:52;;-1:-1:-1;139941:8:0;;158495:39;;:23;;:39;;139941:8;;-1:-1:-1;;;158495:39:0;;-1:-1:-1;;;;;158495:39:0;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;158495:39:0;;;;;;;;;;;;;;;158572:37;;-1:-1:-1;;;;;158572:37:0;;139941:8;-1:-1:-1;;;158572:37:0;;;;;;;;;;;;;;-1:-1:-1;158626:76:0;158631:4;;;-1:-1:-1;174120:6:0;;;158658:43;158683:13;158698:2;158658:24;:43::i;:::-;158626:4;:76::i;:::-;158724:20;;;;:16;;;:20;;;;;;;;158717:27;;-1:-1:-1;;;;;;158717:27:0;;;-1:-1:-1;;;;;158786:13:0;;;;:7;;;:13;;;;;158801:29;;-1:-1:-1;;;;158801:29:0;;-1:-1:-1;;;158801:29:0;;;;;;;;-1:-1:-1;;158801:29:0;;;;;;;;;;174509:10;174518:1;174509:10;;;;174501:19;;;;;;;174540:1;174525:16;;;;;;174501:41;-1:-1:-1;;;;;158851:13:0;;;;;;:7;;;:13;;;;;158761:70;;;;;;-1:-1:-1;158846:67:0;;158866:27;158871:4;;;174292:1;174287:6;;;174286:12;158877:15;174180:137;158866:27;158846:67;;158902:9;158846:4;:67::i;:::-;158942:27;;;;-1:-1:-1;;;158942:27:0;;;;;;;;;;;;-1:-1:-1;;;;158942:27:0;;;;;;;;;158984:63;158989:4;;;158995:22;159007:9;174292:1;174287:6;;;174286:12;;174180:137;158995:22;159019:27;159024:4;;;174292:1;174287:6;;;174286:12;159030:15;174180:137;158984:63;-1:-1:-1;;;;;159067:11:0;;;;;;:7;;;:11;;;;;159062:32;;159080:1;159090:2;159062:4;:32::i;:::-;159109:38;159114:4;;;174292:1;174287:6;;;174286:12;159144:1;159109:4;:38::i;:::-;158547:612;;159191:2;-1:-1:-1;;;;;159176:24:0;159185:4;-1:-1:-1;;;;;159176:24:0;;139941:8;159176:24;;;;1970:25:1;;1958:2;1943:18;;1824:177;159176:24:0;;;;;;;;157824:1384;;;;157701:1507;;;;:::o;223827:447::-;223950:15;;;;;;;223934:13;223984:10;;;223980:23;;223996:7;223827:447;;:::o;223980:23::-;224045:5;139941:8;224038:12;224021:13;224031:2;224021:9;:13::i;:::-;:29;224017:42;;224052:7;223827:447;;:::o;224017:42::-;224077:27;:11;224085:2;224077:7;:11::i;:27::-;224073:40;;;224106:7;223827:447;;:::o;224073:40::-;-1:-1:-1;;109395:18:0;-1:-1:-1;;;;;224131:15:0;:4;-1:-1:-1;;;;;224131:15:0;;224127:28;;224148:7;223827:447;;:::o;224127:28::-;121159:15;121153:4;121146:29;;;121458:4;121189:18;;;121291:4;121275:21;;121269:28;123072:6;121482:21;:26;224169:41;;224203:7;223827:447;;:::o;224169:41::-;224231:24;;-1:-1:-1;;;224231:24:0;;;;;;;;;;;224282:573;224398:13;;-1:-1:-1;;;224398:13:0;;;;224381:14;224430:11;;;224426:24;;224443:7;224282:573;;:::o;224426:24::-;224465:13;224480:16;224500:29;224521:7;224500:13;224508:4;224500:7;:13::i;:::-;-1:-1:-1;;;;;224500:20:0;;;:29::i;:::-;224464:65;;;;224560:1;224548:8;:13;224544:257;;224599:19;;;:28;;224667:10;224700:20;;;224696:45;;224731:10;224722:19;;224696:45;224760:25;224778:6;224760:17;:25::i;:::-;224563:238;;224544:257;224815:21;224823:4;224829:6;224815:7;:21::i;:::-;224356:492;;;224282:573;;:::o;11757:158::-;11830:4;11854:53;11862:3;-1:-1:-1;;;;;11882:23:0;;11854:7;:53::i;227877:605::-;227919:6;;227929:1;227919:11;227915:24;;227877:605::o;227915:24::-;227979:14;;227966:10;;227955:8;;:21;;;;:::i;:::-;:38;227951:77;;;227877:605::o;227951:77::-;228040:23;228066:16;:7;:14;:16::i;:::-;228040:42;;228099:6;:13;228116:1;228099:18;228095:31;;228119:7;227877:605::o;228095:31::-;228237:13;;228225:6;;228180:52;;-1:-1:-1;;228197:9:0;12594:2:1;12590:15;12586:53;228180:52:0;;;12574:66:1;228208:15:0;12656:12:1;;;12649:28;12693:12;;;12686:28;;;;228146:13:0;;228237;12730:12:1;;228180:52:0;;;;;;;;;;;;228170:63;;;;;;228162:72;;:88;;;;:::i;:::-;228146:104;;228275:14;;228261:10;;:28;;;;;;;:::i;:::-;;;;;;;;228302;228333:10;:25;228344:6;228351:5;228344:13;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;228333:25:0;-1:-1:-1;;;;;228333:25:0;;;;;;;;;;;;228302:56;;228403:14;;228379:10;:20;;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;228455:6:0;:8;;;;;;-1:-1:-1;;;227877:605:0:o;114555:119::-;114634:32;114647:4;114653:5;114660;114634:12;:32::i;105034:364::-;-1:-1:-1;;105244:18:0;105234:8;105231:32;105221:159;;105297:10;105291:4;105284:24;105360:4;105354;105347:18;114298:117;114376:31;114389:4;114395:5;114402:4;114376:12;:31::i;115493:819::-;-1:-1:-1;;115786:27:0;115776:8;115773:41;115763:531;;115891:15;115885:4;115878:29;115938:8;115932:4;115925:22;116144:5;116136:4;116130;116120:21;116114:28;116110:40;116100:179;;116188:10;116182:4;116175:24;116255:4;116249;116242:18;222396:984;222486:33;222502:4;222508:2;222512:6;222486:15;:33::i;:::-;222530:31;222552:4;222558:2;222530:21;:31::i;:::-;222584:2;-1:-1:-1;;;;;222576:10:0;:4;-1:-1:-1;;;;;222576:10:0;;222572:43;;222588:27;222602:4;222608:6;222588:13;:27::i;:::-;222632:11;;-1:-1:-1;;;222632:11:0;;;;222628:24;;;222396:984;;;:::o;222628:24::-;222694:4;;-1:-1:-1;;;;;222694:4:0;;;222678:21;;;;222674:546;;-1:-1:-1;;;;;222742:14:0;;;:19;:49;;;;-1:-1:-1;222775:16:0;145487:2;222775;:16;:::i;:::-;222765:6;:26;;222742:49;222738:105;;;222812:15;:7;222824:2;222812:11;:15::i;:::-;;222738:105;222870:12;222879:3;222870:6;:12;:::i;:::-;222859:7;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;222674:546:0;;-1:-1:-1;222674:546:0;;222920:4;;-1:-1:-1;;;;;222920:4:0;;;222906:19;;;;222902:318;;222985:16;145487:2;222985;:16;:::i;:::-;222967:15;222977:4;222967:9;:15::i;:::-;:34;222963:95;;;223022:20;:7;223037:4;223022:14;:20::i;:::-;;222963:95;223090:5;;;;223086:123;;;223128:12;223137:3;223128:6;:12;:::i;:::-;223116:8;;:24;;;;;;;:::i;223086:123::-;223181:5;:12;;-1:-1:-1;;223181:12:0;223189:4;223181:12;;;223086:123;-1:-1:-1;;;;;223244:16:0;;;:21;:59;;;;-1:-1:-1;223287:16:0;145487:2;223287;:16;:::i;:::-;223269:15;223279:4;223269:9;:15::i;:::-;:34;223244:59;223240:112;;;223320:20;:7;223335:4;223320:14;:20::i;:::-;;223240:112;223364:8;:6;:8::i;161424:289::-;161496:21;161520:15;161533:1;161520:12;:15::i;:::-;161551:7;;161496:39;;-1:-1:-1;;;;161551:7:0;;140462:6;161551:37;:42;;161550:53;;;;161546:124;;161620:38;;;-1:-1:-1;;;161620:38:0;;;;;140462:6;161620:38;;;;;-1:-1:-1;;;;161620:38:0;;;;;;161546:124;161696:1;-1:-1:-1;;;;;161685:20:0;;161699:5;161685:20;;;;1358:14:1;1351:22;1333:41;;1321:2;1306:18;;1193:187;161685:20:0;;;;;;;;161485:228;161424:289;;:::o;159729:138::-;-1:-1:-1;;;;;159818:37:0;159792:6;159818:37;;;:30;:37;;;;;:41;-1:-1:-1;;;;;159818:41:0;;159729:138::o;81284:415::-;81554:4;81542:10;81536:4;81524:10;81509:13;81505:2;81498:5;81493:66;81483:198;;81593:10;81587:4;81580:24;81661:4;81655;81648:18;12001:167;-1:-1:-1;;;;;12135:23:0;;12081:4;7353:19;;;:12;;;:19;;;;;;:24;;12105:55;7256:129;228999:693;229039:11;:18;;-1:-1:-1;;;;229039:18:0;-1:-1:-1;;;229039:18:0;;;229224:15;;;229262:217;;;;;;;;229332:6;;229262:217;;229376:4;229262:217;;;;;;229089:17;229262:217;;;;;;;;;;;;229224:266;;-1:-1:-1;;;229224:266:0;;13616:13:1;;229224:266:0;;;13598:32:1;;;;13672:24;;-1:-1:-1;;;;;13668:50:1;;;13646:20;;;13639:80;13748:24;;13863:21;;13841:20;;;13834:51;13927:24;;13923:33;;13901:20;;;13894:63;229089:17:0;;;;229224:15;;:23;;13570:19:1;;229224:266:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;229527:4:0;;229520:37;;-1:-1:-1;;;229520:37:0;;229551:4;229520:37;;;1531:51:1;229503:14:0;;-1:-1:-1;;;229527:4:0;;-1:-1:-1;;;;;229527:4:0;;229520:22;;1504:18:1;;229520:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;229503:54;-1:-1:-1;229574:10:0;;229570:83;;229608:4;;229623:9;;229601:40;;-1:-1:-1;;;229601:40:0;;-1:-1:-1;;;;;229623:9:0;;;229601:40;;;8761:51:1;8828:18;;;8821:34;;;-1:-1:-1;;;229608:4:0;;;;;229601:21;;8734:18:1;;229601:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;229570:83;-1:-1:-1;;229665:11:0;:19;;-1:-1:-1;;;;229665:19:0;;;-1:-1:-1;228999:693:0:o;224863:137::-;224937:55;224945:6;224953:38;224984:6;224953:15;224961:6;224953:7;:15::i;:::-;-1:-1:-1;;;;;224953:30:0;;;:38::i;:::-;224937:7;:55::i;103860:1113::-;-1:-1:-1;;104827:16:0;;-1:-1:-1;;;;;104673:26:0;;;;;;104787:38;104784:1;;104776:78;104913:27;103860:1113::o;143389:1025::-;142884:20;143609:13;;-1:-1:-1;;;143609:13:0;;;;:18;143605:53;;143636:22;;-1:-1:-1;;;143636:22:0;;;;;;;;;;;143605:53;-1:-1:-1;;;;;143675:20:0;;143671:54;;143704:21;;-1:-1:-1;;;143704:21:0;;;;;;;;;;;143671:54;143736:27;143756:6;143736:19;:27::i;:::-;143776:17;;-1:-1:-1;;143776:17:0;-1:-1:-1;;;143776:17:0;;;143792:1;143804:14;;:23;;-1:-1:-1;;;;;143804:23:0;;-1:-1:-1;;;;;;143804:23:0;;;;;;143844:22;;143840:567;;-1:-1:-1;;;;;143887:32:0;;143883:68;;143928:23;;-1:-1:-1;;;143928:23:0;;;;;;;;;;;143883:68;140163:25;143970:18;:32;143966:66;;;144011:21;;-1:-1:-1;;;144011:21:0;;;;;;;;;;;143966:66;144049:42;;-1:-1:-1;;;;144049:42:0;-1:-1:-1;;;;;;;;144049:42:0;;;;;;-1:-1:-1;144152:32:0;144165:18;144152:12;:32::i;:::-;144199:60;;-1:-1:-1;;;;;144199:60:0;;;-1:-1:-1;;;;;;;;144199:60:0;;;;;;144281;;1970:25:1;;;144199:60:0;;-1:-1:-1;144281:60:0;;;-1:-1:-1;;144281:60:0;;1958:2:1;1943:18;144281:60:0;;;;;;;144358:37;144370:18;144390:4;144358:11;:37::i;25827:1676::-;25883:17;26335:4;26328;26322:11;26318:22;26311:29;;26436:4;26431:3;26427:14;26421:4;26414:28;26519:1;26514:3;26507:14;26623:3;26655:1;26651:6;26867:5;26849:410;26906:11;;;;27090:2;27104;27094:13;;27086:22;26906:11;27073:36;27198:2;27188:13;;27219:25;26849:410;27219:25;-1:-1:-1;;27289:13:0;;;-1:-1:-1;;27404:14:0;;;27466:19;;;27404:14;25827:1676;-1:-1:-1;25827:1676:0:o;43450:3410::-;43589:20;43722:7;43716:14;43770:6;43764:13;43822:11;43816:18;43874:4;43865:7;43861:18;43850:29;;43915:4;43907:6;43903:17;43893:27;;43966:4;43953:11;43949:22;43934:37;;44012:4;44005;43999:11;43995:22;43985:32;;44064:13;44055:7;44051:27;44119:13;44105:12;44102:31;44092:2004;;44213:1;44198:12;44186:10;44182:29;44178:37;44242:1;44288:4;44274:12;44271:22;44261:74;;-1:-1:-1;44302:31:0;;;44261:74;44397:4;44383:12;44379:23;44373:4;44369:34;44366:1;44362:42;44437:6;44431:13;44462:1619;44512:7;44506:14;44693:1;44690;44686:9;44683:1;44679:17;44669:1188;;44728:1;44725:441;;;44808:1;44793:12;44784:7;44774:32;44771:39;44761:378;;44847:17;;;44920:1;44967:15;;;;44908:14;;;;45026:29;;;45016:50;;45059:5;;;45016:50;45100:8;44462:1619;;44761:378;45278:1;45263:254;45347:19;;;45341:26;45325:14;;;45318:50;45410:4;45403:12;45455:24;;;45263:254;45445:45;-1:-1:-1;45620:26:0;;;;45553:30;;;;45672:162;;;;45741:16;45732:7;45729:29;45719:50;;45762:5;;;45672:162;45879:17;;45940:1;45975:15;;;;45928:14;;;;46022:29;;;44462:1619;46012:50;44462:1619;44466:2;;;;44092:2004;46135:6;46112:29;;46182:4;46175;46169:11;46165:22;46155:32;;46260:7;46248:10;46244:24;46235:6;46218:15;46214:28;46210:59;46201:68;;46347:217;46366:10;46357:7;46354:23;46347:217;;;46424:14;;46400:39;;46497:4;46531:18;;;;46476:26;;;;46347:217;;;-1:-1:-1;;46635:17:0;46631:25;;;46708:15;;;46600:4;46750:15;46744:4;46737:29;-1:-1:-1;;46588:17:0;;;46804;;;-1:-1:-1;46588:17:0;43450:3410;-1:-1:-1;;;43450:3410:0:o;161884:407::-;-1:-1:-1;;;;;162035:16:0;;161943:21;162035:16;;;:13;:16;;;;;162068:7;;162035:16;;142884:20;;-1:-1:-1;;;162068:7:0;;140325:6;162068:40;:45;;162064:220;;140325:6;173138:14;;162189:53;;;140462:6;162206:36;162189:53;162257:15;;;;;;-1:-1:-1;;;162257:15:0;-1:-1:-1;;;;162257:15:0;;;;;;162064:220;161966:325;161884:407;;;:::o;162457:469::-;162697:26;;-1:-1:-1;;;162697:26:0;;;;142884:20;162591:19;162738:17;;;162734:185;;162787:14;;162789:1;;:12;;162787:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;162816:41;;-1:-1:-1;;;162816:41:0;;-1:-1:-1;;;;162816:41:0;;;;;;-1:-1:-1;162872:30:0;;;:16;;;:30;;;;;:35;;-1:-1:-1;;;;;162872:35:0;;-1:-1:-1;;;;;;162872:35:0;;;;;;162787:14;-1:-1:-1;162734:185:0;162617:309;162457:469;;;;:::o;174619:542::-;174785:8;174779:4;174772:22;174828:5;174825:1;174821:13;174815:4;174808:27;174874:4;174868;174858:21;174937:1;174930:5;174926:13;174923:1;174919:21;175000:1;174994:8;175048:10;175133:5;175129:1;175126;175122:9;175118:21;175115:1;175111:29;175108:1;175104:37;175101:1;175097:45;175094:1;175087:56;;;;;174619:542;;;:::o;96325:1036::-;96423:14;;96314:2;97454:28;;;;;:33;96498:80;;-1:-1:-1;96552:6:0;;-1:-1:-1;96560:1:0;96544:18;;96498:80;96188:10;96634:5;96616:15;:23;96615:36;;;96140:2;96687:29;;;96686:42;96076:16;96775:40;;96836:23;;;96832:130;;-1:-1:-1;96936:10:0;;-1:-1:-1;96904:1:0;96832:130;96140:2;96995:23;;;;96076:16;96256:2;97109:31;;;97108:58;;97083:84;;;;97192:47;;;97182:57;;-1:-1:-1;96002:14:0;97304:38;;;-1:-1:-1;;96325:1036:0;;;;;;:::o;77463:504::-;77600:1;77597;77594:8;77588:4;77581:22;77649:2;77646:1;77642:10;77636:3;77633:1;77630:10;77626:27;77782:1;77767:132;77799:1;77796;77793:8;77767:132;;77870:4;77854:21;;;77841:35;;77817:1;77810:9;77767:132;;;77771:14;;77929:4;77923:11;77913:36;;77938:9;160123:131;-1:-1:-1;;;;;160197:37:0;;;;;;;;:30;:37;;;;;:49;;-1:-1:-1;;160197:49:0;-1:-1:-1;;;;;160197:49:0;;;;;;;;;160123:131::o;5750:1420::-;5816:4;5955:19;;;:12;;;:19;;;;;;5991:15;;5987:1176;;6366:21;6390:14;6403:1;6390:10;:14;:::i;:::-;6439:18;;6366:38;;-1:-1:-1;6419:17:0;;6439:22;;6460:1;;6439:22;:::i;:::-;6419:42;;6495:13;6482:9;:26;6478:405;;6529:17;6549:3;:11;;6561:9;6549:22;;;;;;;;:::i;:::-;;;;;;;;;6529:42;;6703:9;6674:3;:11;;6686:13;6674:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;6788:23;;;:12;;;:23;;;;;:36;;;6478:405;6964:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;7059:3;:12;;:19;7072:5;7059:19;;;;;;;;;;;7052:26;;;7102:4;7095:11;;;;;;;5987:1176;7146:5;7139:12;;;;;13433:310;13496:16;13525:22;13550:19;13558:3;13550:7;:19::i;113174:986::-;113343:15;113337:4;113330:29;113386:4;113380;113373:18;113437:4;113431;113421:21;113517:8;113511:15;113626:5;113617:7;113614:18;113874:2;113864:62;;-1:-1:-1;113904:19:0;;;113891:33;;113864:62;114000:7;113990:8;113983:25;114134:7;114126:4;114120:11;114116:2;114112:20;114080:30;114077:1;114074;114069:73;;;;113174:986;;;:::o;154008:3268::-;-1:-1:-1;;;;;154101:16:0;;154097:52;;154126:23;;-1:-1:-1;;;154126:23:0;;;;;;;;;;;154097:52;142884:20;154162:22;154256:18;154269:4;154256:12;:18::i;:::-;154218:56;;154285:33;154321:16;154334:2;154321:12;:16::i;:::-;154285:52;;154350:23;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;154350:23:0;154404:27;;;-1:-1:-1;;;154404:27:0;;;;;154384:17;;;:47;154460:25;;;;154442:15;;;:43;-1:-1:-1;;;;;;;;154512:23:0;;;;154496:13;;;:39;;;154552:22;;154548:56;;;154583:21;;-1:-1:-1;;;154583:21:0;;;;;;;;;;;154548:56;154642:13;;;:23;;;;;;;;;154680:47;;-1:-1:-1;;;;;154680:47:0;;;-1:-1:-1;;;154680:47:0;;;-1:-1:-1;;;;;154680:47:0;;;;;;154787:21;;;;;;;:30;;154773:11;;;:44;;;154742:76;;;;;;;;;154869:17;;;;154855:54;;139941:8;;154888:20;173957:8;;;173967:9;;173953:24;;173791:204;154855:54;154835:74;;154930:19;;-1:-1:-1;;;154930:19:0;;140462:6;154930:49;154835:17;154930:54;154926:255;;155017:2;-1:-1:-1;;;;;155009:10:0;:4;-1:-1:-1;;;;;155009:10:0;;155005:71;;155059:17;;155039;;;;:37;155021:15;;;:55;155005:71;155115:50;139941:8;155129:1;:11;;;:18;;;;;:::i;:::-;;155149:1;:15;;;173957:8;;;173967:9;;173953:24;;173791:204;155115:50;155095:17;;;:70;154926:255;155197:29;155229:56;155267:1;:17;;;155247:1;:17;;;:37;-1:-1:-1;;;;;;;;;;;;;;;;;171150:4:0;171143;171137:11;171133:22;171226:1;171220:4;171213:15;171266:4;171260;171256:15;171317:1;171314;171310:9;171302:6;171298:22;171292:4;171285:36;171345:4;171342:1;171335:15;171385:6;171381:1;171375:4;171371:12;171364:28;;;170960:450;;;;155229:56;155306:17;;155197:88;;-1:-1:-1;155306:22:0;155302:703;;-1:-1:-1;;;;;155379:13:0;;155349:27;155379:13;;;:7;;;:13;;;;;155431:17;;;;155497;;155533:45;;;-1:-1:-1;;;155533:45:0;;;;;;;;;;;-1:-1:-1;;;;155533:45:0;;;;;;;;;155597;;155485:29;;;155597:45;;;-1:-1:-1;;;155597:45:0;-1:-1:-1;;;;155597:45:0;;;;;;;;;155692:298;-1:-1:-1;;155747:11:0;;;;174518:1;174509:10;;;155718;174501:19;;;;;;;;;;;155747:11;;;174540:1;174525:16;;;;;174501:41;155718;;;;155782:43;155810:1;:4;;155816:2;155820:1;155823;155782:27;:43::i;:::-;155855:20;;;;:16;;;:20;;;;;;;;155848:27;;-1:-1:-1;;;;;;155848:27:0;;;171740:12;;;171734:19;;171804:1;171800:10;;;;171792:2;171788:10;;;171785:26;-1:-1:-1;171782:39:0;171767:55;;171857:17;;171836:39;;155968:20;;;155692:298;;155330:675;;;155302:703;156025:17;;;;:22;156021:1068;;-1:-1:-1;;;;;156096:11:0;;156068:25;156096:11;;;:7;;;:11;;;;;;;156144:15;;;;156204:17;;;;156096:11;;156194:27;;;;156257:43;156282:13;156104:2;156257:24;:43::i;:::-;156338:13;;156449:17;;;;-1:-1:-1;;;;156422:45:0;;156390:13;-1:-1:-1;;;156422:45:0;;;;;;;;;;;;;;;;156486:41;;-1:-1:-1;;;;156486:41:0;-1:-1:-1;;;156486:41:0;;;;;;;156240:60;;-1:-1:-1;139941:8:0;-1:-1:-1;;;156338:13:0;;-1:-1:-1;;;;;156338:13:0;:20;;-1:-1:-1;;;156390:13:0;;;;156577:452;156610:31;156615:1;:4;;156621:19;156637:2;174125:1;174120:6;;174035:99;156610:31;:36;;;156603:123;;156679:4;;:15;;;156675:27;;;-1:-1:-1;156701:1:0;156675:27;156603:123;;;156748:34;156753:7;156762;156778:2;156748:4;:34::i;:::-;156805:65;156833:1;:4;;156839:2;156843:7;156859:9;;;;;;156805:27;:65::i;:::-;156893:40;156911:10;156923:2;156927;156931:1;171750;171744:4;171740:12;171734:19;171813:7;171807:2;171804:1;171800:10;171796:1;171792:2;171788:10;171785:26;171782:39;171774:6;171767:55;171869:4;171861:6;171857:17;171853:1;171847:4;171843:12;171836:39;;171516:377;;;;;156893:40;156960:4;;:15;;;156956:27;;;-1:-1:-1;156982:1:0;156956:27;157022:5;157011:7;:16;156577:452;;157047:26;;;;;;-1:-1:-1;;;157047:26:0;-1:-1:-1;;157047:26:0;;;;;;-1:-1:-1;;;;;156021:1068:0;157109:15;;:22;:27;157105:111;;157185:14;;;;157157:43;;157173:10;;-1:-1:-1;;;;;157185:14:0;157157:15;:43::i;:::-;154617:2610;157257:2;-1:-1:-1;;;;;157242:26:0;157251:4;-1:-1:-1;;;;;157242:26:0;;157261:6;157242:26;;;;1970:25:1;;1958:2;1943:18;;1824:177;157242:26:0;;;;;;;;154086:3190;;;;154008:3268;;;:::o;11429:152::-;11499:4;11523:50;11528:3;-1:-1:-1;;;;;11548:23:0;;11523:4;:50::i;97503:230::-;97578:6;97454:28;96314:2;97454:28;;;;:33;;97601:31;;;;97597:105;;-1:-1:-1;;;97649:41:0;;;;;97597:105;-1:-1:-1;97719:6:0;;97503:230;-1:-1:-1;97503:230:0:o;166119:477::-;166273:10;166267:4;166260:24;166345:8;166339:4;166332:22;166443:4;166437;166431;166425;166422:1;166414:6;166407:5;166402:46;166398:1;166391:4;166385:11;166382:18;166378:71;166368:210;;166483:10;166477:4;166470:24;166558:4;166552;166545:18;8604:111;8660:16;8696:3;:11;;8689:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8604:111;;;:::o;175234:708::-;175526:9;175514:10;175510:26;175497:10;175493:2;175489:19;175486:51;175564:8;175558:4;175551:22;175607:2;175604:1;175600:10;175594:4;175587:24;175650:4;175644;175634:21;175710:1;175706:2;175702:10;175699:1;175695:18;175773:1;175767:8;175821:18;175914:5;175910:1;175907;175903:9;175899:21;175896:1;175892:29;175889:1;175885:37;175882:1;175878:45;175875:1;175868:56;;;;;;175234:708;;;;:::o;171992:634::-;172160:1;172154:8;172195:4;172189;172185:15;172254:10;172251:1;172244:21;172329:4;172322;172319:1;172315:12;172308:26;172425:4;172419:11;172416:1;172412:19;172406:4;172402:30;172393:39;;172551:4;172548:1;172545;172538:4;172535:1;172531:12;172528:1;172520:6;172513:5;172508:48;172504:1;172500;172494:8;172491:15;172487:70;172477:131;;172588:4;172585:1;172578:15;5160:414;5223:4;7353:19;;;:12;;;:19;;;;;;5240:327;;-1:-1:-1;5283:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;5466:18;;5444:19;;;:12;;;:19;;;;;;:40;;;;5499:11;;5240:327;-1:-1:-1;5550:5:0;5543:12;;203:548:1;315:4;344:2;373;362:9;355:21;405:6;399:13;448:6;443:2;432:9;428:18;421:34;473:1;483:140;497:6;494:1;491:13;483:140;;;592:14;;;588:23;;582:30;558:17;;;577:2;554:26;547:66;512:10;;483:140;;;487:3;672:1;667:2;658:6;647:9;643:22;639:31;632:42;742:2;735;731:7;726:2;718:6;714:15;710:29;699:9;695:45;691:54;683:62;;;;203:548;;;;:::o;756:173::-;824:20;;-1:-1:-1;;;;;873:31:1;;863:42;;853:70;;919:1;916;909:12;934:254;1002:6;1010;1063:2;1051:9;1042:7;1038:23;1034:32;1031:52;;;1079:1;1076;1069:12;1031:52;1102:29;1121:9;1102:29;:::i;:::-;1092:39;1178:2;1163:18;;;;1150:32;;-1:-1:-1;;;934:254:1:o;2006:180::-;2065:6;2118:2;2106:9;2097:7;2093:23;2089:32;2086:52;;;2134:1;2131;2124:12;2086:52;-1:-1:-1;2157:23:1;;2006:180;-1:-1:-1;2006:180:1:o;2191:328::-;2268:6;2276;2284;2337:2;2325:9;2316:7;2312:23;2308:32;2305:52;;;2353:1;2350;2343:12;2305:52;2376:29;2395:9;2376:29;:::i;:::-;2366:39;;2424:38;2458:2;2447:9;2443:18;2424:38;:::i;:::-;2414:48;;2509:2;2498:9;2494:18;2481:32;2471:42;;2191:328;;;;;:::o;2524:186::-;2583:6;2636:2;2624:9;2615:7;2611:23;2607:32;2604:52;;;2652:1;2649;2642:12;2604:52;2675:29;2694:9;2675:29;:::i;2715:118::-;2801:5;2794:13;2787:21;2780:5;2777:32;2767:60;;2823:1;2820;2813:12;2838:241;2894:6;2947:2;2935:9;2926:7;2922:23;2918:32;2915:52;;;2963:1;2960;2953:12;2915:52;3002:9;2989:23;3021:28;3043:5;3021:28;:::i;3281:315::-;3346:6;3354;3407:2;3395:9;3386:7;3382:23;3378:32;3375:52;;;3423:1;3420;3413:12;3375:52;3446:29;3465:9;3446:29;:::i;:::-;3436:39;;3525:2;3514:9;3510:18;3497:32;3538:28;3560:5;3538:28;:::i;:::-;3585:5;3575:15;;;3281:315;;;;;:::o;3601:348::-;3653:8;3663:6;3717:3;3710:4;3702:6;3698:17;3694:27;3684:55;;3735:1;3732;3725:12;3684:55;-1:-1:-1;3758:20:1;;3801:18;3790:30;;3787:50;;;3833:1;3830;3823:12;3787:50;3870:4;3862:6;3858:17;3846:29;;3922:3;3915:4;3906:6;3898;3894:19;3890:30;3887:39;3884:59;;;3939:1;3936;3929:12;3954:411;4025:6;4033;4086:2;4074:9;4065:7;4061:23;4057:32;4054:52;;;4102:1;4099;4092:12;4054:52;4142:9;4129:23;4175:18;4167:6;4164:30;4161:50;;;4207:1;4204;4197:12;4161:50;4246:59;4297:7;4288:6;4277:9;4273:22;4246:59;:::i;:::-;4324:8;;4220:85;;-1:-1:-1;3954:411:1;-1:-1:-1;;;;3954:411:1:o;4370:721::-;4462:6;4470;4478;4486;4539:2;4527:9;4518:7;4514:23;4510:32;4507:52;;;4555:1;4552;4545:12;4507:52;4595:9;4582:23;4624:18;4665:2;4657:6;4654:14;4651:34;;;4681:1;4678;4671:12;4651:34;4720:59;4771:7;4762:6;4751:9;4747:22;4720:59;:::i;:::-;4798:8;;-1:-1:-1;4694:85:1;-1:-1:-1;4886:2:1;4871:18;;4858:32;;-1:-1:-1;4902:16:1;;;4899:36;;;4931:1;4928;4921:12;4899:36;;4970:61;5023:7;5012:8;5001:9;4997:24;4970:61;:::i;:::-;4370:721;;;;-1:-1:-1;5050:8:1;-1:-1:-1;;;;4370:721:1:o;5402:276::-;5460:6;5513:2;5501:9;5492:7;5488:23;5484:32;5481:52;;;5529:1;5526;5519:12;5481:52;5568:9;5555:23;5618:10;5611:5;5607:22;5600:5;5597:33;5587:61;;5644:1;5641;5634:12;5683:269;5740:6;5793:2;5781:9;5772:7;5768:23;5764:32;5761:52;;;5809:1;5806;5799:12;5761:52;5848:9;5835:23;5898:4;5891:5;5887:16;5880:5;5877:27;5867:55;;5918:1;5915;5908:12;5957:260;6025:6;6033;6086:2;6074:9;6065:7;6061:23;6057:32;6054:52;;;6102:1;6099;6092:12;6054:52;6125:29;6144:9;6125:29;:::i;:::-;6115:39;;6173:38;6207:2;6196:9;6192:18;6173:38;:::i;:::-;6163:48;;5957:260;;;;;:::o;6222:127::-;6283:10;6278:3;6274:20;6271:1;6264:31;6314:4;6311:1;6304:15;6338:4;6335:1;6328:15;6354:422;6443:1;6486:5;6443:1;6500:270;6521:7;6511:8;6508:21;6500:270;;;6580:4;6576:1;6572:6;6568:17;6562:4;6559:27;6556:53;;;6589:18;;:::i;:::-;6639:7;6629:8;6625:22;6622:55;;;6659:16;;;;6622:55;6738:22;;;;6698:15;;;;6500:270;;;6504:3;6354:422;;;;;:::o;6781:806::-;6830:5;6860:8;6850:80;;-1:-1:-1;6901:1:1;6915:5;;6850:80;6949:4;6939:76;;-1:-1:-1;6986:1:1;7000:5;;6939:76;7031:4;7049:1;7044:59;;;;7117:1;7112:130;;;;7024:218;;7044:59;7074:1;7065:10;;7088:5;;;7112:130;7149:3;7139:8;7136:17;7133:43;;;7156:18;;:::i;:::-;-1:-1:-1;;7212:1:1;7198:16;;7227:5;;7024:218;;7326:2;7316:8;7313:16;7307:3;7301:4;7298:13;7294:36;7288:2;7278:8;7275:16;7270:2;7264:4;7261:12;7257:35;7254:77;7251:159;;;-1:-1:-1;7363:19:1;;;7395:5;;7251:159;7442:34;7467:8;7461:4;7442:34;:::i;:::-;7512:6;7508:1;7504:6;7500:19;7491:7;7488:32;7485:58;;;7523:18;;:::i;:::-;7561:20;;6781:806;-1:-1:-1;;;6781:806:1:o;7592:140::-;7650:5;7679:47;7720:4;7710:8;7706:19;7700:4;7679:47;:::i;7737:380::-;7816:1;7812:12;;;;7859;;;7880:61;;7934:4;7926:6;7922:17;7912:27;;7880:61;7987:2;7979:6;7976:14;7956:18;7953:38;7950:161;;8033:10;8028:3;8024:20;8021:1;8014:31;8068:4;8065:1;8058:15;8096:4;8093:1;8086:15;8122:128;8189:9;;;8210:11;;;8207:37;;;8224:18;;:::i;8866:245::-;8933:6;8986:2;8974:9;8965:7;8961:23;8957:32;8954:52;;;9002:1;8999;8992:12;8954:52;9034:9;9028:16;9053:28;9075:5;9053:28;:::i;9116:127::-;9177:10;9172:3;9168:20;9165:1;9158:31;9208:4;9205:1;9198:15;9232:4;9229:1;9222:15;9374:545;9476:2;9471:3;9468:11;9465:448;;;9512:1;9537:5;9533:2;9526:17;9582:4;9578:2;9568:19;9652:2;9640:10;9636:19;9633:1;9629:27;9623:4;9619:38;9688:4;9676:10;9673:20;9670:47;;;-1:-1:-1;9711:4:1;9670:47;9766:2;9761:3;9757:12;9754:1;9750:20;9744:4;9740:31;9730:41;;9821:82;9839:2;9832:5;9829:13;9821:82;;;9884:17;;;9865:1;9854:13;9821:82;;10095:1206;10219:18;10214:3;10211:27;10208:53;;;10241:18;;:::i;:::-;10270:94;10360:3;10320:38;10352:4;10346:11;10320:38;:::i;:::-;10314:4;10270:94;:::i;:::-;10390:1;10415:2;10410:3;10407:11;10432:1;10427:616;;;;11087:1;11104:3;11101:93;;;-1:-1:-1;11160:19:1;;;11147:33;11101:93;-1:-1:-1;;10052:1:1;10048:11;;;10044:24;10040:29;10030:40;10076:1;10072:11;;;10027:57;11207:78;;10400:895;;10427:616;9321:1;9314:14;;;9358:4;9345:18;;-1:-1:-1;;10463:17:1;;;10564:9;10586:229;10600:7;10597:1;10594:14;10586:229;;;10689:19;;;10676:33;10661:49;;10796:4;10781:20;;;;10749:1;10737:14;;;;10616:12;10586:229;;;10590:3;10843;10834:7;10831:16;10828:159;;;10967:1;10963:6;10957:3;10951;10948:1;10944:11;10940:21;10936:34;10932:39;10919:9;10914:3;10910:19;10897:33;10893:79;10885:6;10878:95;10828:159;;;11030:1;11024:3;11021:1;11017:11;11013:19;11007:4;11000:33;10400:895;;10095:1206;;;:::o;11306:168::-;11379:9;;;11410;;11427:15;;;11421:22;;11407:37;11397:71;;11448:18;;:::i;12193:191::-;-1:-1:-1;;;;;12320:10:1;;;12308;;;12304:27;;12343:12;;;12340:38;;;12358:18;;:::i;12753:127::-;12814:10;12809:3;12805:20;12802:1;12795:31;12845:4;12842:1;12835:15;12869:4;12866:1;12859:15;12885:112;12917:1;12943;12933:35;;12948:18;;:::i;:::-;-1:-1:-1;12982:9:1;;12885:112::o;13002:125::-;13067:9;;;13088:10;;;13085:36;;;13101:18;;:::i;13132:127::-;13193:10;13188:3;13184:20;13181:1;13174:31;13224:4;13221:1;13214:15;13248:4;13245:1;13238:15;13264:120;13304:1;13330;13320:35;;13335:18;;:::i;:::-;-1:-1:-1;13369:9:1;;13264:120::o;13968:245::-;14047:6;14055;14108:2;14096:9;14087:7;14083:23;14079:32;14076:52;;;14124:1;14121;14114:12;14076:52;-1:-1:-1;;14147:16:1;;14203:2;14188:18;;;14182:25;14147:16;;14182:25;;-1:-1:-1;13968:245:1:o;14218:184::-;14288:6;14341:2;14329:9;14320:7;14316:23;14312:32;14309:52;;;14357:1;14354;14347:12;14309:52;-1:-1:-1;14380:16:1;;14218:184;-1:-1:-1;14218:184:1:o;14407:201::-;14445:3;14473:10;14518:2;14511:5;14507:14;14545:2;14536:7;14533:15;14530:41;;14551:18;;:::i;:::-;14600:1;14587:15;;14407:201;-1:-1:-1;;;14407:201:1:o;14613:127::-;14674:10;14669:3;14665:20;14662:1;14655:31;14705:4;14702:1;14695:15;14729:4;14726:1;14719:15
Swarm Source
ipfs://799851e5007eec0e091756974405c2d46386bbe660cefaf8cb756a1ba77489c6
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.