Feature Tip: Add private address tag to any address under My Name Tag !
ERC-721
Overview
Max Total Supply
0 PCTF{CUR74_2023}
Holders
12
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 PCTF{CUR74_2023}Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
CurtaPCTF2023
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {LibString} from "solady/utils/LibString.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {ERC721} from "solmate/tokens/ERC721.sol"; import {ICurtaPCTF2023} from "./interfaces/ICurtaPCTF2023.sol"; import {Base64} from "./utils/Base64.sol"; import {CurtaPCTF2023Art} from "./utils/CurtaPCTF2023Art.sol"; import {CurtaPCTF2023Audio} from "./utils/CurtaPCTF2023Audio.sol"; import {CurtaPCTF2023Metadata} from "./utils/CurtaPCTF2023Metadata.sol"; /// @title Curta ^ Paradigm CTF 2023 commemorative NFTs /// @author fiveoutofnine /// @notice An NFT collection to commemorate players of the Curta team for their /// participation and performance in the 2023 Paradigm CTF. In addition to /// displaying the team's results, the metadata of each token contains a 100% /// onchain-generated 1:38 minute long audio arrangement of "In the Hall of the /// "Mountain King" by Edvard Grieg with 3 layered melody lines and a bass line /// at 117.1875 BPM. contract CurtaPCTF2023 is ICurtaPCTF2023, ERC721, Owned { using LibString for uint256; // ------------------------------------------------------------------------- // Constants // ------------------------------------------------------------------------- /// @notice Description of the collection. string constant COLLECTION_DESCRIPTION = "An NFT collection to commemorate players of the Curta team for their p" "articipation and performance in the 2023 Paradigm CTF. In addition to " "displaying the team's results, the metadata of each token contains a 1" '00% onchain-generated 1:38 minute long audio arrangement of \\"In the ' 'Hall of the Mountain King\\" by Edvard Grieg with 3 layered melody lin' "es and a bass line at 117.1875 BPM."; // ------------------------------------------------------------------------- // Storage // ------------------------------------------------------------------------- /// @inheritdoc ICurtaPCTF2023 string public override baseURI; // ------------------------------------------------------------------------- // Constructor + functions // ------------------------------------------------------------------------- /// @param _owner Initial owner of the contract. constructor( address _owner ) ERC721("Curta ^ Paradigm CTF 2023 Player NFTs", "PCTF{CUR74_2023}") Owned(_owner) {} /// @inheritdoc ICurtaPCTF2023 function mint() external { // Get the token ID to mint for the player. The helper function will // revert if the player was not part of the team. uint256 tokenId = CurtaPCTF2023Metadata.getPlayerId(msg.sender); // Mint token. _mint(msg.sender, tokenId); } /// @inheritdoc ICurtaPCTF2023 function setBaseURI(string calldata _baseURI) external override onlyOwner { // Set new base URI. baseURI = _baseURI; // Emit event. emit SetBaseURI(_baseURI); } // ------------------------------------------------------------------------- // Onchain audio generation // ------------------------------------------------------------------------- /// @inheritdoc ICurtaPCTF2023 function getAudioWavFileHeader() external pure returns (bytes memory) { return CurtaPCTF2023Audio.getAudioWavFileHeader(); } /// @inheritdoc ICurtaPCTF2023 function getSoundValueAtSample( uint256 _tick ) external pure returns (uint8) { return CurtaPCTF2023Audio.getSoundValueAtSample(_tick); } // ------------------------------------------------------------------------- // ERC721Metadata // ------------------------------------------------------------------------- /// @notice Returns the adjusted URI for a given token ID. /// @dev Reverts if the token ID does not exist. Additionally, if `baseURI` /// is unset, `tokenURI` will directly return the URI generated onchain via /// {_tokenURI(uint256)}. Otherwise, it will return `baseURI + tokenId`. /// @param _id The token ID. /// @return The adjusted URI for the given token ID. function tokenURI( uint256 _id ) public view override returns (string memory) { // Revert if the token hasn't been minted. if (_ownerOf[_id] == address(0)) revert TokenUnminted(); return bytes(baseURI).length == 0 ? _tokenURI(_id) : string.concat(baseURI, _id.toString()); } /// @notice Returns the URI for a given token ID, as generated onchain. /// @param _id The token ID. /// @return The URI for the given token ID. function _tokenURI(uint256 _id) internal pure returns (string memory) { // Get name of the player the token is attributed to. string memory name = CurtaPCTF2023Metadata.getPlayerNameFromID(_id); return string.concat( "data:application/json;base64,", Base64.encode( abi.encodePacked( '{"name":"', name, unicode' ∈ Curta ^ Paradigm CTF 2023","description":"', COLLECTION_DESCRIPTION, '","animation_url":"data:text/html;charset=utf-8;base64' ",", Base64.encode( abi.encodePacked(CurtaPCTF2023Art.render(_id)) ), '","attributes":[{"trait_type":"Player","value":"', name, '"},{"trait_type":"Year","value":2023}]}' ) ) ); } // ------------------------------------------------------------------------- // Contract metadata // ------------------------------------------------------------------------- /// @inheritdoc ICurtaPCTF2023 function contractURI() external pure override returns (string memory) { return string.concat( "data:application/json;base64,", Base64.encode( abi.encodePacked( '{"name":"Curta ^ Paradigm CTF 2023 Player NFTs","descr' 'iption":"', COLLECTION_DESCRIPTION, '"}' ) ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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)); } /// @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 { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). 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, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @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 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. /// `smallString` must be null terminated, or behavior will be undefined. function fromSmallString(bytes32 smallString) internal pure returns (string memory result) { if (smallString == bytes32(0)) return result; /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} 1 {} { n := add(n, 1) if iszero(byte(n, smallString)) { break } // Scan for '\0'. } mstore(result, n) let o := add(result, 0x20) mstore(o, smallString) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @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`. For small strings up to 32 bytes. /// `b` must be null terminated, or behavior will be undefined. 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 x := and(b, add(not(b), 1)) let r := or(shl(8, iszero(b)), 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)))) result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, 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) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Simple single owner authorization mixin. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract Owned { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnershipTransferred(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner) { owner = _owner; emit OwnershipTransferred(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /// @title The interface for {CurtaPCTF2023} interface ICurtaPCTF2023 { // ------------------------------------------------------------------------- // Errors // ------------------------------------------------------------------------- /// @notice Emitted when a token hasn't been minted. error TokenUnminted(); // ------------------------------------------------------------------------- // Events // ------------------------------------------------------------------------- /// @notice Emitted when the base URI is set. /// @param baseURI The new base URI. event SetBaseURI(string baseURI); // ------------------------------------------------------------------------- // Storage // ------------------------------------------------------------------------- /// @dev If `baseURI` is unset, `tokenURI` will directly return the URI /// generated onchain via {CurtaPCTF2023._tokenURI(uint256)}. Otherwise, it /// will return `baseURI + tokenId`. /// @return The base URI for the token collection. function baseURI() external view returns (string memory); // ------------------------------------------------------------------------- // Functions // ------------------------------------------------------------------------- /// @notice Mints a token to the sender. /// @dev The sender must have been a player on the Curta ^ Paradigm CTF 2023 /// team (it will revert otherwise). function mint() external; /// @notice Sets the base URI for the token collection. /// @dev This function can only be called by the contract owner. /// @param _baseURI The new base URI for the token collection. function setBaseURI(string calldata _baseURI) external; // ------------------------------------------------------------------------- // Onchain audio generation // ------------------------------------------------------------------------- /// @notice Returns the WAV file header for the audio file for 1 full cycle /// of the token's sound with the parameters the token's sound was generated /// with: /// * Size: 196.61735kB (1572910 bytes) = 98.304s (1572864/8000/2) /// * Number of channels: 1 /// * Sample rate: 8000Hz /// * Bits/sample: 16 bits/sample function getAudioWavFileHeader() external pure returns (bytes memory); /// @notice Returns the sound value at a given time tick in the audio. /// @dev {CurtaPCTF2023}'s audio was generated at a sample rate of 8000Hz, /// which means that `_tick` increments by 1 every 1/8000 seconds. /// @param _tick The number of samples since the beginning of the audio at /// a frequency of 8000Hz to get the sound value at. /// @return The sound value at the given time tick, a value in the range /// `[0, 255]` (higher means louder). function getSoundValueAtSample(uint256 _tick) external pure returns (uint8); // ------------------------------------------------------------------------- // Metadata // ------------------------------------------------------------------------- /// @notice Returns the contract URI for this contract. /// @return The contract URI for this contract. function contractURI() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /// @title Base64 /// @author Brecht Devos - <[email protected]> /// @notice Provides a function for encoding some bytes in base64 library Base64 { string internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678" "9+/"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ""; string memory table = TABLE; uint256 encodedLength = ((data.length + 2) / 3) << 2; string memory result = new string(encodedLength + 0x20); assembly { mstore(result, encodedLength) let tablePtr := add(table, 1) let dataPtr := data let endPtr := add(dataPtr, mload(data)) let resultPtr := add(result, 0x20) for { } lt(dataPtr, endPtr) { } { dataPtr := add(dataPtr, 3) let input := mload(dataPtr) mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0x12, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(0xC, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(shr(6, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(0xF8, mload(add(tablePtr, and(input, 0x3F))))) resultPtr := add(resultPtr, 1) } switch mod(mload(data), 3) case 1 { mstore(sub(resultPtr, 2), shl(0xF0, 0x3D3D)) } case 2 { mstore(sub(resultPtr, 1), shl(0xF8, 0x3D)) } } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /// @title Curta ^ Paradigm CTF 2023 commemorative NFT visual art /// @notice A library for generating HTML output for {CurtaPCTF2023}. library CurtaPCTF2023Art { // ------------------------------------------------------------------------- // Constants // ------------------------------------------------------------------------- /// @notice Starting string for the HTML. string constant HTML_START = unicode"<style>button{height:20px;margin:0 auto;border:0;background:#00" unicode"E100;cursor:pointer;color:#000}button:hover{text-decoration:und" unicode"erline}.b{width:512px}.c{color:#00e100}.a{position:absolute;mar" unicode"gin:auto 0;border-radius:100%;top:6px;width:12px;height:12px}</" unicode"style><body style=width:640px;height:640px;margin:0><div class=" unicode'b style="height:512px;background:#161616;padding:64px"><div sty' unicode'le="background:#000;border-radius:8px;height:464px;overflow:hid' unicode'den;border:1px solid #343434;margin:20px 0"><div style=position' unicode":relative;display:flex;width:500px;height:24px;background:#dada" unicode"da;padding-left:6px;padding-right:6px><code style=font-weight:6" unicode"00;margin:auto;color:#484848>Curta ^ Paradigm CTF 2023</code><d" unicode"iv style=background:#ed6a5e;left:6px class=a></div><div style=b" unicode"ackground:#f5bf4f;left:22px class=a></div><div style=background" unicode':#62c555;left:38px class=a></div></div><pre style="width:496px;' unicode'height:292px;display:flex;padding:0px 8px;color:#fff;margin:0">' unicode"<code style=margin:auto>┌<span class=c>MEMBERS</span>───┐┌<span" unicode" class=c>CHALLENGES COMPLETED</span>───────────┐\n│"; /// @notice Ending string for the HTML. string constant HTML_END = unicode" ││100% 200.65│\n│ ││BLACK WOR" unicode"LD 182.80│\n│ ││HELLO WORLD " unicode"133.22│\n└──────────┘└───────────────────────────────┘</code></" unicode"pre><div class=b style=display:flex><button id=b><code>[ Submit" unicode" PCTF{CUR74_2023} ]</code></button></div><audio id=a>Your brows" unicode"er does not support the audio element</audio><div class=b style" unicode"=position:relative;height:128px><canvas id=d style=position:abs" unicode'olute width=512 height=128></canvas><div id=c style="border:.5p' unicode'x solid #00e100;height:127px;position:absolute;left:0"></div></' unicode'div></div><script>document.getElementById("b").addEventListener' unicode'("click",()=>{g=0;j=0;for(s="",t=0;t<3*2**18;t++){c="charCodeAt' unicode'",u=(t>>18)%3,r=(t)=>t&256?t&255:256-(t&255),a=30*t*2**(("%\'(*' unicode",(,,+'++*&**%'(*,(,1/,(,////\"[c](t>>11&31)+[0,12,7,19][t>>16&3" unicode'])/12-6),x=30*t*2**(("%,%,%,%,%,%,(/(/,3,3(0,3"[c](8*(t>>17&1?2' unicode":t>>15&1)+(t>>12&7)))/12-7),y=a*2,z=y*2;s+=String.fromCharCode(" unicode"(r(a)/(5-(u>1))+(u>0)/5*r(y)+(u>1)*(r(z)/5+r(x)/4))%256|0)}a=do" unicode'cument.getElementById("a");a.src="data:audio/wav;base64,UklGRi4' unicode'AGABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAGACA"+btoa(s);' unicode'a.play();setInterval(()=>{c=document.getElementById("c");c.styl' unicode'e.left=(Math.min(128*g+128,j++)*100/128)+"%";},32);h=()=>{d=doc' unicode'ument.getElementById("d").getContext("2d");d.clearRect(0,0,512,' unicode'128);d.fillStyle="#FFF";[...Array(4096)].map((_,i)=>{d.beginPat' unicode"h();d.arc(i/8,128-s.charCodeAt(32768*g+i*8)/2,1,0,2*Math.PI);d." unicode"fill();});g++;j=0;};h();setInterval(h,4096)})</script>"; // ------------------------------------------------------------------------- // `render` function // ------------------------------------------------------------------------- /// @notice Renders a HTML commemorating a player's participation and /// performance on the Curta team for the 2023 Paradigm CTF. /// @param _id ID of the player. /// @return HTML string. function render(uint256 _id) internal pure returns (string memory) { string memory html; // Block-scoping to prevent stack too deep error. { html = string.concat( HTML_START, _getHighlightedSpan("sudolabel", _id == 0), unicode" ││SUSPICIOUS CHARITY 369.96│\n│", _getHighlightedSpan("Kalzak", _id == 1), unicode" ││FREE REAL ESTATE 1.74│\n│", _getHighlightedSpan("seen", _id == 2), unicode" ││GRAINS OF SAND 343.99│\n│", _getHighlightedSpan("igorline", _id == 3), unicode" ││DROPPER 233.22│\n│", _getHighlightedSpan("pogo", _id == 4), unicode" ││COSMIC RADIATION 43.78│\n│", _getHighlightedSpan("popular", _id == 5), unicode" ││DRAGON TYRANT 425.13│\n│", _getHighlightedSpan("orenyomtov", _id == 6), unicode"││HOPPING INTO PLACE 316.55│\n│" ); } return string.concat( html, _getHighlightedSpan("0x796", _id == 7), unicode" ││ENTERPRISE BLOCKCHAIN 271.22│\n│", _getHighlightedSpan("plotchy", _id == 8), unicode" ││DAI++ 316.55│\n│", _getHighlightedSpan("forager", _id == 9), unicode" ││DODONT <span class=c>[FIRST BLOOD]</span> 233." unicode"10│\n│", _getHighlightedSpan("horsefacts", _id == 10), unicode"││OVEN 281.90│\n│", _getHighlightedSpan("datadanne", _id == 11), unicode" ││SKILL BASED GAME 214.03│\n│", _getHighlightedSpan("brock", _id == 12), HTML_END ); } /// @notice Helper function that returns a "highlighted" `<span/>` element /// if the player is selected (i.e. the corresponding token is attributed to /// them). /// @param _name Name of the player. /// @param _selected Whether the player is selected. /// @return HTML string for the span. function _getHighlightedSpan( string memory _name, bool _selected ) internal pure returns (string memory) { return _selected ? string.concat( "<span class=c style=font-weight:900;text-decoration:underl" "ine>", _name, "</span>" ) : _name; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {FixedPointMathLib as Math} from "solady/utils/FixedPointMathLib.sol"; /// @title Curta ^ Paradigm CTF 2023 commemorative NFT auditory art /// @notice A library for generating onchain audio for {CurtaPCTF2023}, which is /// a 1:38 minute long audio arrangement of "In the Hall of the Mountain King" /// by Edvard Grieg with 3 layered melody lines and a bass line at 117.1875 BPM. /// @dev The metadata returned by {CurtaPCTF2023} doesn't use this library for /// practical reasons. However, the same result can be yielded by calling /// {getSoundValueAtSample} for each sample in the range `[0, 786432]` and /// concatenating the result, prefixed with the header returned by /// {getAudioWavFileHeader}. library CurtaPCTF2023Audio { using Math for int256; using Math for uint256; // ------------------------------------------------------------------------- // Constants // ------------------------------------------------------------------------- /// @notice A bitpacked `uint256` of 8 bitpacked segments of 8-bit words /// representing quarter note pitch values for the bass line, where the note /// C3 has avalue of 62, and 1 is a semitone. uint256 constant BASS_NOTES = 0x332C3028332C332C2F282F282C252C252C252C252C252C25; /// @notice A bitpacked `uint256` of 8-bit words representing eigth note /// pitch values, for the melody line, where the note C3 has a value of 50, /// and 1 is a semitone. uint256 constant MELODY_NOTES = 0x2F2F2F2F2C282C2F312C282C2A2827252A2A262A2B2B272B2C2C282C2A282725; /// @notice A bitpacked `uint256` of 8-bit words representing tranpositions, /// to perform on the melody line every 2**16 samples, where 1 is a /// semitone. uint256 constant MELODY_TRANSPOSITIONS = 0x13070C00; // ------------------------------------------------------------------------- // Functions // ------------------------------------------------------------------------- /// @notice Returns the WAV file header for the audio file for 1 full cycle /// of the token's sound with the parameters the token's sound was generated /// with: /// * Size: 196.61735kB (1572910 bytes) = 98.304s (1572864/8000/2) /// * Number of channels: 1 /// * Sample rate: 8000Hz /// * Bits/sample: 16 bits/sample function getAudioWavFileHeader() internal pure returns (bytes memory) { // Note: base-64 encoding the following hex string yields: // "UklGRi4AGABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAGACA". return // "RIFF" chunk descriptor hex"52" hex"49" hex"46" hex"46" // "RIFF" in ASCII hex"2e" hex"00" hex"18" hex"00" // Size of the file (length of data chunk + 46 for the header) = 1572864 + 46 = 1572910 hex"57" hex"41" hex"56" hex"45" // "WAVE" in ASCII // "fmt " sub-chunk hex"66" hex"6d" hex"74" hex"20" // "fmt " in ASCII hex"10" hex"00" hex"00" hex"00" // Length of sub-chunk 1 = 16 hex"01" hex"00" hex"01" hex"00" // Audio format = 1 (PCM), Number of channels = 1 hex"40" hex"1f" hex"00" hex"00" // Sample rate = 8000Hz hex"40" hex"1f" hex"00" hex"00" // Byte rate (sample rate * bits/sample * channels) = 8000 * 1 * 1 = 8000 bytes/sec hex"01" hex"00" hex"10" hex"00" // Block align = 1, bits/sample = 16 // "data" sub-chunk hex"64" hex"61" hex"74" hex"61" // "data" in ASCII hex"00" hex"00" hex"18" hex"00" // Length of data chunk = (3 * 2 ** 18 * 16 / 8) = 1572864 bytes hex"80"; // Sample 1 } /// @notice Returns the sound value at a given time tick in the audio. /// @dev {CurtaPCTF2023}'s audio was generated at a sample rate of 8000Hz, /// which means that `_tick` increments by 1 every 1/8000 seconds. A full /// cycle of the audio is 3*2**18 = 786432 samples long, so `_tick` wraps /// around every 786432 samples (i.e. same values for equivalent /// `_tick % 786432`). /// @param _tick The number of samples since the beginning of the audio at /// a frequency of 8000Hz to get the sound value at. /// @return The sound value at the given time tick, a value in the range /// `[0, 255]` (higher means louder). function getSoundValueAtSample(uint256 _tick) internal pure returns (uint8) { // This function is equivalent to the following JavaScript code: // ```js // const getSoundValueAtSample = (tick) => { // const transformValue = (v) => v & 256 ? v & 255 : 256 - (v & 255); // const iteration = (tick >> 18) % 3; // const melodyLine1 = 30 * tick * 2 ** ( // ( // "%'(*,(,,+'++*&**%'(*,(,1/,(,////".charCodeAt(tick >> 11 & 31) // Theme // + [0, 12, 7, 19][tick >> 16 & 3]) / 12 - 6 // Adjustment // ); // const bassLine = 30 * tick * 2 ** ( // ("%,%,%,%,%,%,(/(/,3,3(0,3".charCodeAt( // 8 * (tick >> 17 & 1 ? 2 : tick >> 15 & 1) + (tick >> 12 & 7) // )) / 12 - 7 // ); // const melodyLine2 = melodyLine1 * 2; // const melodyLine3 = melodyLine2 * 2; // return transformValue(melodyLine1) / (5 - (iteration > 1)) // + (iteration > 0) / 5 * transformValue(melodyLine2) // + (iteration > 1) * (transformValue(melodyLine3) / 5 // + transformValue(bassLine) / 4); // } // ``` // Calculate the pitch of the value of the melody line at `_tick` as an // 18 decimal fixed point value in the range `[0, 255e18]`. int256 melody1 = int256(30 * _tick) * int256(2e18).powWad( (1e18 * int256( // Each note is 2**11 samples long (an eighth note at 117.1875 // BPM), so `_tick >> 11`. Then, we take `% 32` because the // melody line is 32 notes long. ((MELODY_NOTES >> (((_tick >> 11) & 31) << 3)) & 0xFF) // We adjust the melody's theme by transposing the theme // by the corresponding amount every 2**16 samples. By // adding to the pitch fetched for the melody line, we // effectively repeat the theme 4 times with different // transpositions. + ((MELODY_TRANSPOSITIONS >> (((_tick >> 16) & 3) << 3)) & 0xFF) )) / 12 - int256(6e18) ); // Calculate the pitch of the value of the bass line at `_tick` as an 18 // decimal fixed point value in the range `[0, 255e18]`. int256 bass = int256(30 * _tick) * int256(2e18).powWad( (1e18 * int256( (BASS_NOTES >> ( // Calculate the starting offset of the bass line segment to // read from. We want to read the segments in the following // order: 0, 1, 0, 1, 2, 2, 2, 2. Each segment is 8 quarter // notes long, or 2**15 samples long, so we can achieve this // sequence by returning 2 if `(_tick >> 17) & 1` is 1, or // taking the last bit of `_tick >> 15` otherwise. ((((_tick >> 17) & 1 == 1) ? 2 : (_tick >> 15) & 1) << 3) // Each note is 2**12 samples long (a quarter note at // 117.1875 BPM), so `_tick >> 12`. Then, we take // `% 8` because each segment of the bass line we read // from is 8 notes long. + ((_tick >> 12) & 7) )) & 0xFF )) / 12 - int256(7e18) ); // Same as the first melody line, except 1 octave higher. int256 melody2 = melody1 * 2; // Same as the first melody line, except 2 octaves higher. int256 melody3 = melody2 * 2; // Truncate and transform pitch values to integer triangle wave values // in the range `[0, 255]` for a more pleasant sound. uint256 transformedMelody1 = _toTruncatedTriangleWaveValue(melody1); uint256 transformedBass = _toTruncatedTriangleWaveValue(bass); uint256 transformedMelody2 = _toTruncatedTriangleWaveValue(melody2); uint256 transformedMelody3 = _toTruncatedTriangleWaveValue(melody3); // We want to vary the loudness of each line every 2**18 samples in the // following volume (loudness) progressions, where 0 is the quietest // and 1 is the loudest: // .-------------------------------------. // | Line | Rep. 0 | Rep. 1 | Rep. 2 | // |----------|--------|--------|--------| // | Melody 1 | 0.20 | 0.20 | 0.25 | // | Melody 2 | 0.00 | 0.20 | 0.20 | // | Melody 3 | 0.00 | 0.00 | 0.20 | // | Bass | 0.00 | 0.00 | 0.25 | // |----------|--------|--------|--------| // | TOTAL | 0.20 | 0.40 | 0.90 | // '-------------------------------------' // We achieve this with the following expression, which the `assembly` // block below is equivalent to: /// ```solidity // ( // (4 + iteration > 1) * transformedMelody1 // + 4 * (iteration > 0) * transformedMelody2 // + 4 * (iteration > 1) * transformedMelody3 // + 5 * (iteration > 1) * transformedBass // ) / 20 // ``` uint256 iteration = (_tick >> 18) % 3; uint8 soundValue; assembly { soundValue := and( div( add( add( mul(add(4, gt(iteration, 1)), transformedMelody1), mul(mul(4, gt(iteration, 0)), transformedMelody2) ), add( mul(mul(4, gt(iteration, 1)), transformedMelody3), mul(mul(5, gt(iteration, 1)), transformedBass) ) ), 20 ), 0xFF ) } return soundValue; } /// @notice Truncate an 18 decimal fixed point value `_value`'s decimal /// component, and transform it to be on a triangle wave in the range /// `[0, 255]`. /// @param _value The 18 decimal fixed point value to transform. /// @return The truncated and transformed value in the range `[0, 255]`. function _toTruncatedTriangleWaveValue(int256 _value) internal pure returns (uint256) { uint256 truncatedValue; assembly { // `_value` can never be negative, so we can safely assign it // to a `uint256` value. truncatedValue := div(_value, 1000000000000000000) // 1e18 } unchecked { return truncatedValue & 0x100 > 0 ? truncatedValue & 0xFF : 256 - (truncatedValue & 0xFF); // Will never underflow. } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /// @title Curta ^ Paradigm CTF 2023 commemorative NFT metadata /// @notice A library for returning the metadata associated with players of the /// Curta ^ Paradigm CTF 2023 team. /// @dev Players have predetermined IDs (equal to the ID of the token they can /// mint), names, and addresses (the addresses they can claim from). If a player /// is not part of the team (i.e. there's no associated ID/address associated), /// the functions will revert. library CurtaPCTF2023Metadata { // ------------------------------------------------------------------------- // Constants // ------------------------------------------------------------------------- /// @notice The address of sudolabel (sudolabel.eth). address constant SUDOLABEL = 0x655aF72e1500EB8A8d1c90856Ae3B8f148A78471; /// @notice The address of Kalzak (kalzak.eth). address constant KALZAK = 0xd4057e08B9d484d70C5977784fC1f6D82d45ff67; /// @notice The address of seen (eoa.sina.eth). address constant SEEN = 0x2de14DB256Db2597fe3c8Eed46eF5b20bA390823; /// @notice The address of igorline (igorline.eth). address constant IGORLINE = 0x14869c6bF40BBc73e45821F7c28FD792151b3f9A; /// @notice The address of pogo (minimooger.eth). address constant POGO = 0x6E82554d7C496baCcc8d0bCB104A50B772d22a1F; /// @notice The address of popular (p0pular.eth). address constant POPULAR = 0x0Fc363b52E49074a395B075a6814Cb8F37E8F8BE; /// @notice The address of orenyomtov (orenyomtov.eth). address constant ORENYOMTOV = 0xD04Dd74d0a905E857278ac3A8bDaFadcD8BF8e87; /// @notice The address of 0x796 (vicnaum.eth). address constant ZERO_X_796 = 0x79635b386B9bd6636Cd701879C32E6dd181C853F; /// @notice The address of plotchy (plotchy.eth). address constant PLOTCHY = 0x97735C60c5E3C2788b7EE570306775e687095D19; /// @notice The address of forager (forager.eth). address constant FORAGER = 0x286cD2FF7Ad1337BaA783C345080e5Af9bBa0b6e; /// @notice The address of horsefacts (horsefacts.eth). address constant HORSEFACTS = 0x79d31bFcA5Fda7A4F15b36763d2e44C99D811a6C; /// @notice The address of datadanne (datadanne.eth). address constant DATADANNE = 0xBDfeB5439f5daecb78A17Ff846645A8bDBbF5725; /// @notice The address of brocke (brocke.eth). address constant BROCKE = 0x230d31EEC85F4063a405B0F95bdE509C0d0A8b5D; // ------------------------------------------------------------------------- // Errors // ------------------------------------------------------------------------- /// @notice Emitted when a player wasn't part of the Curta ^ Paradigm CTF /// 2023 team. /// @param _player The nonexistant player. error NonexistantPlayer(address _player); /// @notice Emitted when ID doesn't map to a player. /// @param _id The nonexistant ID. error NonexistantPlayerID(uint256 _id); // ------------------------------------------------------------------------- // Functions // ------------------------------------------------------------------------- /// @notice Returns the address of the player the token is attributed to. /// @dev Reverts if the token ID does not exist. /// @param _id The token ID. /// @return The address of the player the token is attributed to. function getPlayerAddress(uint256 _id) internal pure returns (address) { if (_id == 0) return SUDOLABEL; else if (_id == 1) return KALZAK; else if (_id == 2) return SEEN; else if (_id == 3) return IGORLINE; else if (_id == 4) return POGO; else if (_id == 5) return POPULAR; else if (_id == 6) return ORENYOMTOV; else if (_id == 7) return ZERO_X_796; else if (_id == 8) return PLOTCHY; else if (_id == 9) return FORAGER; else if (_id == 10) return HORSEFACTS; else if (_id == 11) return DATADANNE; else if (_id == 12) return BROCKE; revert NonexistantPlayerID(_id); } /// @notice Returns the ID of the player the token is attributed to. /// @dev Reverts if the player was not part of the Curta ^ Paradigm CTF 2023 /// team. /// @param _player The player's address. /// @return The ID of the player the token is attributed to. function getPlayerId(address _player) internal pure returns (uint256) { if (_player == SUDOLABEL) return 0; else if (_player == KALZAK) return 1; else if (_player == SEEN) return 2; else if (_player == IGORLINE) return 3; else if (_player == POGO) return 4; else if (_player == POPULAR) return 5; else if (_player == ORENYOMTOV) return 6; else if (_player == ZERO_X_796) return 7; else if (_player == PLOTCHY) return 8; else if (_player == FORAGER) return 9; else if (_player == HORSEFACTS) return 10; else if (_player == DATADANNE) return 11; else if (_player == BROCKE) return 12; revert NonexistantPlayer(_player); } /// @notice Returns the name of the player the token is attributed to. /// @dev Reverts if the token ID does not exist. /// @param _id The token ID. /// @return The name of the player the token is attributed to. function getPlayerNameFromID( uint256 _id ) internal pure returns (string memory) { if (_id == 0) return "sudolabel"; else if (_id == 1) return "Kalzak"; else if (_id == 2) return "seen"; else if (_id == 3) return "igorline"; else if (_id == 4) return "pogo"; else if (_id == 5) return "popular"; else if (_id == 6) return "orenyomtov"; else if (_id == 7) return "0x796"; else if (_id == 8) return "plotchy"; else if (_id == 9) return "forager"; else if (_id == 10) return "horsefacts"; else if (_id == 11) return "datadanne"; else if (_id == 12) return "brocke"; revert NonexistantPlayerID(_id); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, either due to a /// multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The multiply-divide operation failed, either due to a /// multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return r; /// @solidity memory-safe-assembly assembly { // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. function lnWad(int256 x) internal pure returns (int256 r) { unchecked { /// @solidity memory-safe-assembly assembly { if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } } // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Compute k = log2(x) - 96, t = 159 - k = 255 - log2(x) = 255 ^ log2(x). int256 t; /// @solidity memory-safe-assembly assembly { t := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) t := or(t, shl(6, lt(0xffffffffffffffff, shr(t, x)))) t := or(t, shl(5, lt(0xffffffff, shr(t, x)))) t := or(t, shl(4, lt(0xffff, shr(t, x)))) t := or(t, shl(3, lt(0xff, shr(t, x)))) // forgefmt: disable-next-item t := xor(t, byte(and(0x1f, shr(shr(t, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) } // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x = int256(uint256(x << uint256(t)) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * (159 - t); // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Calculates `floor(a * b / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Least significant 256 bits of the product. let p0 := mul(x, y) let mm := mulmod(x, y, not(0)) // Most significant 256 bits of the product. let p1 := sub(mm, add(p0, lt(mm, p0))) // Handle non-overflow cases, 256 by 256 division. if iszero(p1) { if iszero(d) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } result := div(p0, d) break } // Make sure the result is less than `2**256`. Also prevents `d == 0`. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. // Compute remainder using mulmod. let r := mulmod(x, y, d) // `t` is the least significant bit of `d`. // Always greater or equal to 1. let t := and(d, sub(0, d)) // Divide `d` by `t`, which is a power of two. d := div(d, t) // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(mul(3, d), 2) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 result := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or(mul(sub(p1, gt(r, p0)), add(div(sub(0, t), t), 1)), div(sub(p0, r), t)), // inverse mod 2**256 mul(inv, sub(2, mul(d, inv))) ) break } } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { result = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { result := add(result, 1) if iszero(result) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if iszero(iszero(x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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)))) z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 9; if (x <= type(uint256).max / 10 ** 36 - 1) { x *= 10 ** 18; z = 1; } z *= sqrt(x); } } /// @dev Returns the cube root of `x`, denominated in `WAD`. function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 12; if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) { if (x >= type(uint256).max / 10 ** 36) { x *= 10 ** 18; z = 10 ** 6; } else { x *= 10 ** 36; z = 1; } } z *= cbrt(x); } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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 r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, 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(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the average of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
{ "remappings": [ "transmissions11/solmate/=lib/solmate/src/", "forge-std/=lib/forge-std/src/", "solady/=lib/solady/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"NonexistantPlayer","type":"error"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"NonexistantPlayerID","type":"error"},{"inputs":[],"name":"TokenUnminted","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"SetBaseURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"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":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAudioWavFileHeader","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tick","type":"uint256"}],"name":"getSoundValueAtSample","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620046ae380380620046ae8339810160408190526200003491620000e9565b80604051806060016040528060258152602001620046896025913960408051808201909152601081526f504354467b43555237345f323032337d60801b60208201526000620000848382620001c0565b506001620000938282620001c0565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350506200028c565b600060208284031215620000fc57600080fd5b81516001600160a01b03811681146200011457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200014657607f821691505b6020821081036200016757634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001bb57600081815260208120601f850160051c81016020861015620001965750805b601f850160051c820191505b81811015620001b757828155600101620001a2565b5050505b505050565b81516001600160401b03811115620001dc57620001dc6200011b565b620001f481620001ed845462000131565b846200016d565b602080601f8311600181146200022c5760008415620002135750858301515b600019600386901b1c1916600185901b178555620001b7565b600085815260208120601f198616915b828110156200025d578886015182559484019460019091019084016200023c565b50858210156200027c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6143ed806200029c6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80636c0360eb116100d8578063b88d4fde1161008c578063e8a3d48511610066578063e8a3d48514610334578063e985e9c51461033c578063f2fde38b1461036a57600080fd5b8063b88d4fde14610306578063bd59342414610319578063c87b56dd1461032157600080fd5b80638da5cb5b116100bd5780638da5cb5b146102cb57806395d89b41146102eb578063a22cb465146102f357600080fd5b80636c0360eb146102a257806370a08231146102aa57600080fd5b806323b872dd1161012f57806342842e0e1161011457806342842e0e1461026957806355f804b31461027c5780636352211e1461028f57600080fd5b806323b872dd14610231578063333a70041461024457600080fd5b8063081812fc11610160578063081812fc146101b9578063095ea7b3146102145780631249c58b1461022957600080fd5b806301ffc9a71461017c57806306fdde03146101a4575b600080fd5b61018f61018a366004612752565b61037d565b60405190151581526020015b60405180910390f35b6101ac610462565b60405161019b91906127dd565b6101ef6101c73660046127f0565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61022761022236600461282d565b6104f0565b005b61022761063f565b61022761023f366004612857565b610659565b6102576102523660046127f0565b610920565b60405160ff909116815260200161019b565b610227610277366004612857565b61092b565b61022761028a3660046128dc565b610a95565b6101ef61029d3660046127f0565b610b61565b6101ac610bf2565b6102bd6102b836600461291e565b610bff565b60405190815260200161019b565b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ac610ca7565b610227610301366004612939565b610cb4565b610227610314366004612975565b610d4b565b6101ac610ea5565b6101ac61032f3660046127f0565b610eb4565b6101ac610f5f565b61018f61034a3660046129e4565b600560209081526000928352604080842090915290825290205460ff1681565b61022761037836600461291e565b610fc8565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061041057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b8061045c57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805461046f90612a17565b80601f016020809104026020016040519081016040528092919081815260200182805461049b90612a17565b80156104e85780601f106104bd576101008083540402835291602001916104e8565b820191906000526020600020905b8154815290600101906020018083116104cb57829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610553575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b6105be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600061064a336110ba565b90506106563382611487565b50565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff8481169116146106e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d0000000000000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216610766576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b3373ffffffffffffffffffffffffffffffffffffffff841614806107ba575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b806107e8575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b61084e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061045c82611620565b610936838383610659565b73ffffffffffffffffffffffffffffffffffffffff82163b1580610a2a57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b6007610b23828483612b04565b507f23c8c9488efebfd474e85a7956de6f39b17c7ab88502d42a623db2d8e382bbaa8282604051610b55929190612c67565b60405180910390a15050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610bed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e5445440000000000000000000000000000000000000000000060448201526064016105b5565b919050565b6007805461046f90612a17565b600073ffffffffffffffffffffffffffffffffffffffff8216610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f41444452455353000000000000000000000000000000000000000060448201526064016105b5565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b6001805461046f90612a17565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610d56858585610659565b73ffffffffffffffffffffffffffffffffffffffff84163b1580610e3857506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a0290610dd19033908a90899089908990600401612c83565b6020604051808303816000875af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610e9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b5050505050565b6060610eaf6117f4565b905090565b60008181526002602052604090205460609073ffffffffffffffffffffffffffffffffffffffff16610f12576040517f1589363800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078054610f1f90612a17565b159050610f56576007610f3183611814565b604051602001610f42929190612cea565b60405160208183030381529060405261045c565b61045c82611876565b6060610fa4604051806101a0016040528061017f8152602001613baf61017f9139604051602001610f909190612d8f565b6040516020818303038152906040526118fc565b604051602001610fb49190612e21565b604051602081830303815290604052905090565b60065473ffffffffffffffffffffffffffffffffffffffff163314611049576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60007fffffffffffffffffffffffff9aa508d1eaff147572e36f7a951c470eb7587b8f73ffffffffffffffffffffffffffffffffffffffff83160161110157506000919050565b7fffffffffffffffffffffffff2bfa81f7462b7b28f3a68887b03e0927d2ba009973ffffffffffffffffffffffffffffffffffffffff83160161114657506001919050565b7fffffffffffffffffffffffffd21eb24da924da6801c37112b910a4df45c6f7dd73ffffffffffffffffffffffffffffffffffffffff83160161118b57506002919050565b7fffffffffffffffffffffffffeb7963940bf4438c1ba7de083d70286deae4c06673ffffffffffffffffffffffffffffffffffffffff8316016111d057506003919050565b7fffffffffffffffffffffffff917daab283b694533372f434efb5af488d2dd5e173ffffffffffffffffffffffffffffffffffffffff83160161121557506004919050565b7ffffffffffffffffffffffffff03c9c4ad1b6f8b5c6a4f8a597eb3470c817074273ffffffffffffffffffffffffffffffffffffffff83160161125a57506005919050565b7fffffffffffffffffffffffff2fb228b2f56fa17a8d8753c5742505232740717973ffffffffffffffffffffffffffffffffffffffff83160161129f57506006919050565b7fffffffffffffffffffffffff869ca4c79464299c9328fe7863cd1922e7e37ac173ffffffffffffffffffffffffffffffffffffffff8316016112e457506007919050565b7fffffffffffffffffffffffff688ca39f3a1c3d8774811a8fcf988a1978f6a2e773ffffffffffffffffffffffffffffffffffffffff83160161132957506008919050565b7fffffffffffffffffffffffffd7932d00852ecc845587c3cbaf7f1a506445f49273ffffffffffffffffffffffffffffffffffffffff83160161136e57506009919050565b7fffffffffffffffffffffffff862ce4035a02585b0ea4c989c2d1bb36627ee59473ffffffffffffffffffffffffffffffffffffffff8316016113b35750600a919050565b7fffffffffffffffffffffffff42014abc60a25134875e8007b99ba5742440a8db73ffffffffffffffffffffffffffffffffffffffff8316016113f85750600b919050565b7fffffffffffffffffffffffffdcf2ce1137a0bf9c5bfa4f06a421af63f2f574a373ffffffffffffffffffffffffffffffffffffffff83160161143d5750600c919050565b6040517f0fccfad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e54454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000806116ac6753444835ec580000600c61167760ff6313070c006018600d8a901c161c8116907f2f2f2f2f2c282c2f312c282c2a2827252a2a262a2b2b272b2c2c282c2a28272560f860088b901c161c16612e95565b61168990670de0b6b3a7640000612ea8565b6116939190612f23565b61169d9190612f8b565b671bc16d674ec8000090611acf565b6116b784601e612fb2565b6116c19190612ea8565b90506000611735676124fee993bc0000600c600787821c166003600160118a901c8116146116f657600f89901c6001166116f9565b60025b61170492911b612e95565b77332c3028332c332c2f282f282c252c252c252c252c252c25901c60ff16670de0b6b3a76400006116899190612ea8565b61174085601e612fb2565b61174a9190612ea8565b90506000611759836002612ea8565b90506000611768826002612ea8565b9050600061177585611b07565b9050600061178285611b07565b9050600061178f85611b07565b9050600061179c85611b07565b905060006117af600360128d901c612fc9565b9050600060ff601486600185116005020285600186116004020201866000861160040202896001871160040102010104169050809a5050505050505050505050919050565b60606040518060600160405280602d8152602001613b82602d9139905090565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061182f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6060600061188383611b33565b90506118d581604051806101a0016040528061017f8152602001613baf61017f91396118c16118b187611eb7565b604051602001610f909190612fdd565b84604051602001610f909493929190612ff9565b6040516020016118e59190612e21565b604051602081830303815290604052915050919050565b6060815160000361191b57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613d2e6040913990506000600260038551600261194c9190612e95565b61195691906131a8565b901b90506000611967826020612e95565b67ffffffffffffffff81111561197f5761197f612a87565b6040519080825280601f01601f1916602001820160405280156119a9576020820181803683370190505b509050818152600183018586518101602084015b81831015611a175760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b938201939093526004016119bd565b600389510660018114611a315760028114611a7b57611ac1565b7f3d3d0000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe830152611ac1565b7f3d000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301525b509398975050505050505050565b6000611b00670de0b6b3a764000083611ae7866122a4565b611af19190612ea8565b611afb9190612f23565b612507565b9392505050565b6000670de0b6b3a764000082046101008116611b2a578060ff1661010003611b00565b60ff1692915050565b606081600003611b7657505060408051808201909152600981527f7375646f6c6162656c0000000000000000000000000000000000000000000000602082015290565b81600103611bb757505060408051808201909152600681527f4b616c7a616b0000000000000000000000000000000000000000000000000000602082015290565b81600203611bf857505060408051808201909152600481527f7365656e00000000000000000000000000000000000000000000000000000000602082015290565b81600303611c3957505060408051808201909152600881527f69676f726c696e65000000000000000000000000000000000000000000000000602082015290565b81600403611c7a57505060408051808201909152600481527f706f676f00000000000000000000000000000000000000000000000000000000602082015290565b81600503611cbb57505060408051808201909152600781527f706f70756c617200000000000000000000000000000000000000000000000000602082015290565b81600603611cfc57505060408051808201909152600a81527f6f72656e796f6d746f7600000000000000000000000000000000000000000000602082015290565b81600703611d3d57505060408051808201909152600581527f3078373936000000000000000000000000000000000000000000000000000000602082015290565b81600803611d7e57505060408051808201909152600781527f706c6f7463687900000000000000000000000000000000000000000000000000602082015290565b81600903611dbf57505060408051808201909152600781527f666f726167657200000000000000000000000000000000000000000000000000602082015290565b81600a03611e0057505060408051808201909152600a81527f686f727365666163747300000000000000000000000000000000000000000000602082015290565b81600b03611e4157505060408051808201909152600981527f6461746164616e6e650000000000000000000000000000000000000000000000602082015290565b81600c03611e8257505060408051808201909152600681527f62726f636b650000000000000000000000000000000000000000000000000000602082015290565b6040517f7e082e57000000000000000000000000000000000000000000000000000000008152600481018390526024016105b5565b606080604051806104800160405280610448815260200161373a6104489139611f186040518060400160405280600981526020017f7375646f6c6162656c0000000000000000000000000000000000000000000000815250856000146126ef565b611f5a6040518060400160405280600681526020017f4b616c7a616b0000000000000000000000000000000000000000000000000000815250866001146126ef565b611f9c6040518060400160405280600481526020017f7365656e00000000000000000000000000000000000000000000000000000000815250876002146126ef565b611fde6040518060400160405280600881526020017f69676f726c696e65000000000000000000000000000000000000000000000000815250886003146126ef565b6120206040518060400160405280600481526020017f706f676f00000000000000000000000000000000000000000000000000000000815250896004146126ef565b6120626040518060400160405280600781526020017f706f70756c6172000000000000000000000000000000000000000000000000008152508a6005146126ef565b6120a46040518060400160405280600a81526020017f6f72656e796f6d746f76000000000000000000000000000000000000000000008152508b6006146126ef565b6040516020016120bb9897969594939291906131bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600582527f307837393600000000000000000000000000000000000000000000000000000060208301529150819061212790600786146126ef565b6121696040518060400160405280600781526020017f706c6f7463687900000000000000000000000000000000000000000000000000815250866008146126ef565b6121ab6040518060400160405280600781526020017f666f726167657200000000000000000000000000000000000000000000000000815250876009146126ef565b6121ed6040518060400160405280600a81526020017f686f72736566616374730000000000000000000000000000000000000000000081525088600a146126ef565b61222f6040518060400160405280600981526020017f6461746164616e6e65000000000000000000000000000000000000000000000081525089600b146126ef565b6122716040518060400160405280600581526020017f62726f636b0000000000000000000000000000000000000000000000000000008152508a600c146126ef565b60405180610680016040528061064a8152602001613d6e61064a91396040516020016118e5989796959493929190613478565b60008082136122bb57631615e6386000526004601cfd5b507ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be6fffffffffffffffffffffffffffffffff831160071b83811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1783811c9190911c601f169190911a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361253557919050565b680755bf798b4a1bf1e582126125535763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060816126fc5782611b00565b8260405160200161270d91906136a7565b604051602081830303815290604052905092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461065657600080fd5b60006020828403121561276457600080fd5b8135611b0081612724565b60005b8381101561278a578181015183820152602001612772565b50506000910152565b600081518084526127ab81602086016020860161276f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611b006020830184612793565b60006020828403121561280257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bed57600080fd5b6000806040838503121561284057600080fd5b61284983612809565b946020939093013593505050565b60008060006060848603121561286c57600080fd5b61287584612809565b925061288360208501612809565b9150604084013590509250925092565b60008083601f8401126128a557600080fd5b50813567ffffffffffffffff8111156128bd57600080fd5b6020830191508360208285010111156128d557600080fd5b9250929050565b600080602083850312156128ef57600080fd5b823567ffffffffffffffff81111561290657600080fd5b61291285828601612893565b90969095509350505050565b60006020828403121561293057600080fd5b611b0082612809565b6000806040838503121561294c57600080fd5b61295583612809565b91506020830135801515811461296a57600080fd5b809150509250929050565b60008060008060006080868803121561298d57600080fd5b61299686612809565b94506129a460208701612809565b935060408601359250606086013567ffffffffffffffff8111156129c757600080fd5b6129d388828901612893565b969995985093965092949392505050565b600080604083850312156129f757600080fd5b612a0083612809565b9150612a0e60208401612809565b90509250929050565b600181811c90821680612a2b57607f821691505b602082108103612a64577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215612a7c57600080fd5b8151611b0081612724565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115610a9057600081815260208120601f850160051c81016020861015612add5750805b601f850160051c820191505b81811015612afc57828155600101612ae9565b505050505050565b67ffffffffffffffff831115612b1c57612b1c612a87565b612b3083612b2a8354612a17565b83612ab6565b6000601f841160018114612b825760008515612b4c5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610e9e565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015612bd15786850135825560209485019460019092019101612bb1565b5086821015612c0c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612c7b602083018486612c1e565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152612cc3608083018486612c1e565b979650505050505050565b60008151612ce081856020860161276f565b9290920192915050565b6000808454612cf881612a17565b60018281168015612d105760018114612d4357612d72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450612d72565b8860005260208060002060005b85811015612d695781548a820152908401908201612d50565b50505082870194505b505050508351612d8681836020880161276f565b01949350505050565b7f7b226e616d65223a224375727461205e20506172616469676d2043544620323081527f323320506c61796572204e465473222c226465736372697074696f6e223a2200602082015260008251612ded81603f85016020870161276f565b7f227d000000000000000000000000000000000000000000000000000000000000603f939091019283015250604101919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612e5981601d85016020870161276f565b91909101601d0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561045c5761045c612e66565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615612ee057612ee0612e66565b818105831482151761045c5761045c612e66565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612f3257612f32612ef4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615612f8657612f86612e66565b500590565b8181036000831280158383131683831282161715612fab57612fab612e66565b5092915050565b808202811582820484141761045c5761045c612e66565b600082612fd857612fd8612ef4565b500690565b60008251612fef81846020870161276f565b9190910192915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008551613031816009850160208a0161276f565b7f20e28888204375727461205e20506172616469676d204354462032303233222c6009918401918201527f226465736372697074696f6e223a22000000000000000000000000000000000060298201528551613094816038840160208a0161276f565b7f222c22616e696d6174696f6e5f75726c223a22646174613a746578742f68746d603892909101918201527f6c3b636861727365743d7574662d383b6261736536342c000000000000000000605882015284516130f881606f84016020890161276f565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2250606f92909101918201527f6c61796572222c2276616c7565223a2200000000000000000000000000000000608f820152612cc3613159609f830186612cce565b7f227d2c7b2274726169745f74797065223a2259656172222c2276616c7565223a81527f323032337d5d7d00000000000000000000000000000000000000000000000000602082015260270190565b6000826131b7576131b7612ef4565b500490565b600089516131ce818460208e0161276f565b8951908301906131e2818360208e0161276f565b8082019150507f20e29482e29482535553504943494f555320434841524954592020202020202081527f3336392e3936e294820ae29482000000000000000000000000000000000000006020820152885161324481602d840160208d0161276f565b7f20202020e29482e2948246524545205245414c20455354415445202020202020602d92909101918201527f2020202020312e3734e294820ae2948200000000000000000000000000000000604d82015287516132a881605d840160208c0161276f565b7f202020202020e29482e29482475241494e53204f462053414e44202020202020605d92909101918201527f20202020203334332e3939e294820ae294820000000000000000000000000000607d82015261346961341a6134146133c56133bf61337061336a61331b608f89018f612cce565b7f2020e29482e2948244524f50504552202020202020202020202020202020202081527f203233332e3232e294820ae294820000000000000000000000000000000000006020820152602e0190565b8c612cce565b7f202020202020e29482e29482434f534d494320524144494154494f4e2020202081527f20202020202034332e3738e294820ae294820000000000000000000000000000602082015260320190565b89612cce565b7f202020e29482e29482445241474f4e20545952414e542020202020202020202081527f20203432352e3133e294820ae2948200000000000000000000000000000000006020820152602f0190565b86612cce565b7fe29482e29482484f5050494e4720494e544f20504c414345202020202020203381527f31362e3535e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b9b9a5050505050505050505050565b6000895161348a818460208e0161276f565b89519083019061349e818360208e0161276f565b8082019150507f2020202020e29482e29482454e544552505249534520424c4f434b434841494e81527f202020203237312e3232e294820ae2948200000000000000000000000000000060208201528851613500816031840160208d0161276f565b7f202020e29482e294824441492b2b202020202020202020202020202020202020603192909101918201527f20203331362e3535e294820ae29482000000000000000000000000000000000060518201528751613564816060840160208c0161276f565b7f202020e29482e29482444f444f4e54203c7370616e20636c6173733d633e5b46606092909101918201527f4952535420424c4f4f445d3c2f7370616e3e20202020203233332e3130e2948260808201527f0ae294820000000000000000000000000000000000000000000000000000000060a08201526134696136a161369b61364c6136466135f760a487018d612cce565b7fe29482e294824f56454e2020202020202020202020202020202020202020203281527f38312e3930e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b8a612cce565b7f20e29482e29482534b494c4c2042415345442047414d4520202020202020202081527f3231342e3033e294820ae29482000000000000000000000000000000000000006020820152602d0190565b87612cce565b85612cce565b7f3c7370616e20636c6173733d63207374796c653d666f6e742d7765696768743a81527f3930303b746578742d6465636f726174696f6e3a756e6465726c696e653e000060208201526000825161370581603e85016020870161276f565b7f3c2f7370616e3e00000000000000000000000000000000000000000000000000603e93909101928301525060450191905056fe3c7374796c653e627574746f6e7b6865696768743a323070783b6d617267696e3a30206175746f3b626f726465723a303b6261636b67726f756e643a233030453130303b637572736f723a706f696e7465723b636f6c6f723a233030307d627574746f6e3a686f7665727b746578742d6465636f726174696f6e3a756e6465726c696e657d2e627b77696474683a35313270787d2e637b636f6c6f723a233030653130307d2e617b706f736974696f6e3a6162736f6c7574653b6d617267696e3a6175746f20303b626f726465722d7261646975733a313030253b746f703a3670783b77696474683a313270783b6865696768743a313270787d3c2f7374796c653e3c626f6479207374796c653d77696474683a36343070783b6865696768743a36343070783b6d617267696e3a303e3c64697620636c6173733d62207374796c653d226865696768743a35313270783b6261636b67726f756e643a233136313631363b70616464696e673a36347078223e3c646976207374796c653d226261636b67726f756e643a233030303b626f726465722d7261646975733a3870783b6865696768743a34363470783b6f766572666c6f773a68696464656e3b626f726465723a31707820736f6c696420233334333433343b6d617267696e3a323070782030223e3c646976207374796c653d706f736974696f6e3a72656c61746976653b646973706c61793a666c65783b77696474683a35303070783b6865696768743a323470783b6261636b67726f756e643a236461646164613b70616464696e672d6c6566743a3670783b70616464696e672d72696768743a3670783e3c636f6465207374796c653d666f6e742d7765696768743a3630303b6d617267696e3a6175746f3b636f6c6f723a233438343834383e4375727461205e20506172616469676d2043544620323032333c2f636f64653e3c646976207374796c653d6261636b67726f756e643a236564366135653b6c6566743a36707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a236635626634663b6c6566743a3232707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a233632633535353b6c6566743a3338707820636c6173733d613e3c2f6469763e3c2f6469763e3c707265207374796c653d2277696474683a34393670783b6865696768743a32393270783b646973706c61793a666c65783b70616464696e673a307078203870783b636f6c6f723a236666663b6d617267696e3a30223e3c636f6465207374796c653d6d617267696e3a6175746f3ee2948c3c7370616e20636c6173733d633e4d454d424552533c2f7370616e3ee29480e29480e29480e29490e2948c3c7370616e20636c6173733d633e4348414c4c454e47455320434f4d504c455445443c2f7370616e3ee29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294900ae29482524946462e00180057415645666d74201000000001000100401f0000401f000001001000646174610000180080416e204e465420636f6c6c656374696f6e20746f20636f6d6d656d6f7261746520706c6179657273206f6620746865204375727461207465616d20666f722074686569722070617274696369706174696f6e20616e6420706572666f726d616e636520696e20746865203230323320506172616469676d204354462e20496e206164646974696f6e20746f20646973706c6179696e6720746865207465616d277320726573756c74732c20746865206d65746164617461206f66206561636820746f6b656e20636f6e7461696e7320612031303025206f6e636861696e2d67656e65726174656420313a3338206d696e757465206c6f6e6720617564696f20617272616e67656d656e74206f66205c22496e207468652048616c6c206f6620746865204d6f756e7461696e204b696e675c222062792045647661726420477269656720776974682033206c617965726564206d656c6f6479206c696e657320616e6420612062617373206c696e65206174203131372e313837352042504d2e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f2020202020e29482e29482313030252020202020202020202020202020202020202020203230302e3635e294820ae2948220202020202020202020e29482e29482424c41434b20574f524c4420202020202020202020202020203138322e3830e294820ae2948220202020202020202020e29482e2948248454c4c4f20574f524c4420202020202020202020202020203133332e3232e294820ae29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29498e29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294983c2f636f64653e3c2f7072653e3c64697620636c6173733d62207374796c653d646973706c61793a666c65783e3c627574746f6e2069643d623e3c636f64653e5b205375626d697420504354467b43555237345f323032337d205d3c2f636f64653e3c2f627574746f6e3e3c2f6469763e3c617564696f2069643d613e596f75722062726f7773657220646f6573206e6f7420737570706f72742074686520617564696f20656c656d656e743c2f617564696f3e3c64697620636c6173733d62207374796c653d706f736974696f6e3a72656c61746976653b6865696768743a31323870783e3c63616e7661732069643d64207374796c653d706f736974696f6e3a6162736f6c7574652077696474683d353132206865696768743d3132383e3c2f63616e7661733e3c6469762069643d63207374796c653d22626f726465723a2e35707820736f6c696420233030653130303b6865696768743a31323770783b706f736974696f6e3a6162736f6c7574653b6c6566743a30223e3c2f6469763e3c2f6469763e3c2f6469763e3c7363726970743e646f63756d656e742e676574456c656d656e744279496428226222292e6164644576656e744c697374656e65722822636c69636b222c28293d3e7b673d303b6a3d303b666f7228733d22222c743d303b743c332a322a2a31383b742b2b297b633d2263686172436f64654174222c753d28743e3e31382925332c723d2874293d3e74263235363f74263235353a3235362d287426323535292c613d33302a742a322a2a2828222527282a2c282c2c2b272b2b2a262a2a2527282a2c282c312f2c282c2f2f2f2f225b635d28743e3e3131263331292b5b302c31322c372c31395d5b743e3e313626335d292f31322d36292c783d33302a742a322a2a282822252c252c252c252c252c252c282f282f2c332c3328302c33225b635d28382a28743e3e313726313f323a743e3e31352631292b28743e3e313226372929292f31322d37292c793d612a322c7a3d792a323b732b3d537472696e672e66726f6d43686172436f64652828722861292f28352d28753e3129292b28753e30292f352a722879292b28753e31292a2872287a292f352b722878292f342929253235367c30297d613d646f63756d656e742e676574456c656d656e744279496428226122293b612e7372633d22646174613a617564696f2f7761763b6261736536342c556b6c47526934414741425851565a465a6d3130494241414141414241414541514238414145416641414142414167415a4746305951414147414341222b62746f612873293b612e706c617928293b736574496e74657276616c2828293d3e7b633d646f63756d656e742e676574456c656d656e744279496428226322293b632e7374796c652e6c6566743d284d6174682e6d696e283132382a672b3132382c6a2b2b292a3130302f313238292b2225223b7d2c3332293b683d28293d3e7b643d646f63756d656e742e676574456c656d656e744279496428226422292e676574436f6e746578742822326422293b642e636c6561725265637428302c302c3531322c313238293b642e66696c6c5374796c653d2223464646223b5b2e2e2e41727261792834303936295d2e6d617028285f2c69293d3e7b642e626567696e5061746828293b642e61726328692f382c3132382d732e63686172436f646541742833323736382a672b692a38292f322c312c302c322a4d6174682e5049293b642e66696c6c28293b7d293b672b2b3b6a3d303b7d3b6828293b736574496e74657276616c28682c34303936297d293c2f7363726970743ea2646970667358221220014028a5543be52c0f1d32e7068286c08c6bd65bd1b045bf34f55a45a8d5c19e64736f6c634300081500334375727461205e20506172616469676d20435446203230323320506c61796572204e4654730000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101775760003560e01c80636c0360eb116100d8578063b88d4fde1161008c578063e8a3d48511610066578063e8a3d48514610334578063e985e9c51461033c578063f2fde38b1461036a57600080fd5b8063b88d4fde14610306578063bd59342414610319578063c87b56dd1461032157600080fd5b80638da5cb5b116100bd5780638da5cb5b146102cb57806395d89b41146102eb578063a22cb465146102f357600080fd5b80636c0360eb146102a257806370a08231146102aa57600080fd5b806323b872dd1161012f57806342842e0e1161011457806342842e0e1461026957806355f804b31461027c5780636352211e1461028f57600080fd5b806323b872dd14610231578063333a70041461024457600080fd5b8063081812fc11610160578063081812fc146101b9578063095ea7b3146102145780631249c58b1461022957600080fd5b806301ffc9a71461017c57806306fdde03146101a4575b600080fd5b61018f61018a366004612752565b61037d565b60405190151581526020015b60405180910390f35b6101ac610462565b60405161019b91906127dd565b6101ef6101c73660046127f0565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61022761022236600461282d565b6104f0565b005b61022761063f565b61022761023f366004612857565b610659565b6102576102523660046127f0565b610920565b60405160ff909116815260200161019b565b610227610277366004612857565b61092b565b61022761028a3660046128dc565b610a95565b6101ef61029d3660046127f0565b610b61565b6101ac610bf2565b6102bd6102b836600461291e565b610bff565b60405190815260200161019b565b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ac610ca7565b610227610301366004612939565b610cb4565b610227610314366004612975565b610d4b565b6101ac610ea5565b6101ac61032f3660046127f0565b610eb4565b6101ac610f5f565b61018f61034a3660046129e4565b600560209081526000928352604080842090915290825290205460ff1681565b61022761037836600461291e565b610fc8565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061041057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b8061045c57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805461046f90612a17565b80601f016020809104026020016040519081016040528092919081815260200182805461049b90612a17565b80156104e85780601f106104bd576101008083540402835291602001916104e8565b820191906000526020600020905b8154815290600101906020018083116104cb57829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610553575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b6105be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600061064a336110ba565b90506106563382611487565b50565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff8481169116146106e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d0000000000000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216610766576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b3373ffffffffffffffffffffffffffffffffffffffff841614806107ba575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b806107e8575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b61084e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061045c82611620565b610936838383610659565b73ffffffffffffffffffffffffffffffffffffffff82163b1580610a2a57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b6007610b23828483612b04565b507f23c8c9488efebfd474e85a7956de6f39b17c7ab88502d42a623db2d8e382bbaa8282604051610b55929190612c67565b60405180910390a15050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610bed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e5445440000000000000000000000000000000000000000000060448201526064016105b5565b919050565b6007805461046f90612a17565b600073ffffffffffffffffffffffffffffffffffffffff8216610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f41444452455353000000000000000000000000000000000000000060448201526064016105b5565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b6001805461046f90612a17565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610d56858585610659565b73ffffffffffffffffffffffffffffffffffffffff84163b1580610e3857506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a0290610dd19033908a90899089908990600401612c83565b6020604051808303816000875af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190612a6a565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b610e9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e540000000000000000000000000000000060448201526064016105b5565b5050505050565b6060610eaf6117f4565b905090565b60008181526002602052604090205460609073ffffffffffffffffffffffffffffffffffffffff16610f12576040517f1589363800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078054610f1f90612a17565b159050610f56576007610f3183611814565b604051602001610f42929190612cea565b60405160208183030381529060405261045c565b61045c82611876565b6060610fa4604051806101a0016040528061017f8152602001613baf61017f9139604051602001610f909190612d8f565b6040516020818303038152906040526118fc565b604051602001610fb49190612e21565b604051602081830303815290604052905090565b60065473ffffffffffffffffffffffffffffffffffffffff163314611049576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016105b5565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60007fffffffffffffffffffffffff9aa508d1eaff147572e36f7a951c470eb7587b8f73ffffffffffffffffffffffffffffffffffffffff83160161110157506000919050565b7fffffffffffffffffffffffff2bfa81f7462b7b28f3a68887b03e0927d2ba009973ffffffffffffffffffffffffffffffffffffffff83160161114657506001919050565b7fffffffffffffffffffffffffd21eb24da924da6801c37112b910a4df45c6f7dd73ffffffffffffffffffffffffffffffffffffffff83160161118b57506002919050565b7fffffffffffffffffffffffffeb7963940bf4438c1ba7de083d70286deae4c06673ffffffffffffffffffffffffffffffffffffffff8316016111d057506003919050565b7fffffffffffffffffffffffff917daab283b694533372f434efb5af488d2dd5e173ffffffffffffffffffffffffffffffffffffffff83160161121557506004919050565b7ffffffffffffffffffffffffff03c9c4ad1b6f8b5c6a4f8a597eb3470c817074273ffffffffffffffffffffffffffffffffffffffff83160161125a57506005919050565b7fffffffffffffffffffffffff2fb228b2f56fa17a8d8753c5742505232740717973ffffffffffffffffffffffffffffffffffffffff83160161129f57506006919050565b7fffffffffffffffffffffffff869ca4c79464299c9328fe7863cd1922e7e37ac173ffffffffffffffffffffffffffffffffffffffff8316016112e457506007919050565b7fffffffffffffffffffffffff688ca39f3a1c3d8774811a8fcf988a1978f6a2e773ffffffffffffffffffffffffffffffffffffffff83160161132957506008919050565b7fffffffffffffffffffffffffd7932d00852ecc845587c3cbaf7f1a506445f49273ffffffffffffffffffffffffffffffffffffffff83160161136e57506009919050565b7fffffffffffffffffffffffff862ce4035a02585b0ea4c989c2d1bb36627ee59473ffffffffffffffffffffffffffffffffffffffff8316016113b35750600a919050565b7fffffffffffffffffffffffff42014abc60a25134875e8007b99ba5742440a8db73ffffffffffffffffffffffffffffffffffffffff8316016113f85750600b919050565b7fffffffffffffffffffffffffdcf2ce1137a0bf9c5bfa4f06a421af63f2f574a373ffffffffffffffffffffffffffffffffffffffff83160161143d5750600c919050565b6040517f0fccfad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e5400000000000000000000000000000060448201526064016105b5565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611590576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e54454400000000000000000000000000000000000060448201526064016105b5565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000806116ac6753444835ec580000600c61167760ff6313070c006018600d8a901c161c8116907f2f2f2f2f2c282c2f312c282c2a2827252a2a262a2b2b272b2c2c282c2a28272560f860088b901c161c16612e95565b61168990670de0b6b3a7640000612ea8565b6116939190612f23565b61169d9190612f8b565b671bc16d674ec8000090611acf565b6116b784601e612fb2565b6116c19190612ea8565b90506000611735676124fee993bc0000600c600787821c166003600160118a901c8116146116f657600f89901c6001166116f9565b60025b61170492911b612e95565b77332c3028332c332c2f282f282c252c252c252c252c252c25901c60ff16670de0b6b3a76400006116899190612ea8565b61174085601e612fb2565b61174a9190612ea8565b90506000611759836002612ea8565b90506000611768826002612ea8565b9050600061177585611b07565b9050600061178285611b07565b9050600061178f85611b07565b9050600061179c85611b07565b905060006117af600360128d901c612fc9565b9050600060ff601486600185116005020285600186116004020201866000861160040202896001871160040102010104169050809a5050505050505050505050919050565b60606040518060600160405280602d8152602001613b82602d9139905090565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061182f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6060600061188383611b33565b90506118d581604051806101a0016040528061017f8152602001613baf61017f91396118c16118b187611eb7565b604051602001610f909190612fdd565b84604051602001610f909493929190612ff9565b6040516020016118e59190612e21565b604051602081830303815290604052915050919050565b6060815160000361191b57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613d2e6040913990506000600260038551600261194c9190612e95565b61195691906131a8565b901b90506000611967826020612e95565b67ffffffffffffffff81111561197f5761197f612a87565b6040519080825280601f01601f1916602001820160405280156119a9576020820181803683370190505b509050818152600183018586518101602084015b81831015611a175760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b938201939093526004016119bd565b600389510660018114611a315760028114611a7b57611ac1565b7f3d3d0000000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe830152611ac1565b7f3d000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301525b509398975050505050505050565b6000611b00670de0b6b3a764000083611ae7866122a4565b611af19190612ea8565b611afb9190612f23565b612507565b9392505050565b6000670de0b6b3a764000082046101008116611b2a578060ff1661010003611b00565b60ff1692915050565b606081600003611b7657505060408051808201909152600981527f7375646f6c6162656c0000000000000000000000000000000000000000000000602082015290565b81600103611bb757505060408051808201909152600681527f4b616c7a616b0000000000000000000000000000000000000000000000000000602082015290565b81600203611bf857505060408051808201909152600481527f7365656e00000000000000000000000000000000000000000000000000000000602082015290565b81600303611c3957505060408051808201909152600881527f69676f726c696e65000000000000000000000000000000000000000000000000602082015290565b81600403611c7a57505060408051808201909152600481527f706f676f00000000000000000000000000000000000000000000000000000000602082015290565b81600503611cbb57505060408051808201909152600781527f706f70756c617200000000000000000000000000000000000000000000000000602082015290565b81600603611cfc57505060408051808201909152600a81527f6f72656e796f6d746f7600000000000000000000000000000000000000000000602082015290565b81600703611d3d57505060408051808201909152600581527f3078373936000000000000000000000000000000000000000000000000000000602082015290565b81600803611d7e57505060408051808201909152600781527f706c6f7463687900000000000000000000000000000000000000000000000000602082015290565b81600903611dbf57505060408051808201909152600781527f666f726167657200000000000000000000000000000000000000000000000000602082015290565b81600a03611e0057505060408051808201909152600a81527f686f727365666163747300000000000000000000000000000000000000000000602082015290565b81600b03611e4157505060408051808201909152600981527f6461746164616e6e650000000000000000000000000000000000000000000000602082015290565b81600c03611e8257505060408051808201909152600681527f62726f636b650000000000000000000000000000000000000000000000000000602082015290565b6040517f7e082e57000000000000000000000000000000000000000000000000000000008152600481018390526024016105b5565b606080604051806104800160405280610448815260200161373a6104489139611f186040518060400160405280600981526020017f7375646f6c6162656c0000000000000000000000000000000000000000000000815250856000146126ef565b611f5a6040518060400160405280600681526020017f4b616c7a616b0000000000000000000000000000000000000000000000000000815250866001146126ef565b611f9c6040518060400160405280600481526020017f7365656e00000000000000000000000000000000000000000000000000000000815250876002146126ef565b611fde6040518060400160405280600881526020017f69676f726c696e65000000000000000000000000000000000000000000000000815250886003146126ef565b6120206040518060400160405280600481526020017f706f676f00000000000000000000000000000000000000000000000000000000815250896004146126ef565b6120626040518060400160405280600781526020017f706f70756c6172000000000000000000000000000000000000000000000000008152508a6005146126ef565b6120a46040518060400160405280600a81526020017f6f72656e796f6d746f76000000000000000000000000000000000000000000008152508b6006146126ef565b6040516020016120bb9897969594939291906131bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600582527f307837393600000000000000000000000000000000000000000000000000000060208301529150819061212790600786146126ef565b6121696040518060400160405280600781526020017f706c6f7463687900000000000000000000000000000000000000000000000000815250866008146126ef565b6121ab6040518060400160405280600781526020017f666f726167657200000000000000000000000000000000000000000000000000815250876009146126ef565b6121ed6040518060400160405280600a81526020017f686f72736566616374730000000000000000000000000000000000000000000081525088600a146126ef565b61222f6040518060400160405280600981526020017f6461746164616e6e65000000000000000000000000000000000000000000000081525089600b146126ef565b6122716040518060400160405280600581526020017f62726f636b0000000000000000000000000000000000000000000000000000008152508a600c146126ef565b60405180610680016040528061064a8152602001613d6e61064a91396040516020016118e5989796959493929190613478565b60008082136122bb57631615e6386000526004601cfd5b507ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be6fffffffffffffffffffffffffffffffff831160071b83811c67ffffffffffffffff1060061b1783811c63ffffffff1060051b1783811c61ffff1060041b1783811c60ff1060031b1783811c9190911c601f169190911a1890811b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029190037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361253557919050565b680755bf798b4a1bf1e582126125535763a37bfec96000526004601cfd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060816126fc5782611b00565b8260405160200161270d91906136a7565b604051602081830303815290604052905092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461065657600080fd5b60006020828403121561276457600080fd5b8135611b0081612724565b60005b8381101561278a578181015183820152602001612772565b50506000910152565b600081518084526127ab81602086016020860161276f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611b006020830184612793565b60006020828403121561280257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bed57600080fd5b6000806040838503121561284057600080fd5b61284983612809565b946020939093013593505050565b60008060006060848603121561286c57600080fd5b61287584612809565b925061288360208501612809565b9150604084013590509250925092565b60008083601f8401126128a557600080fd5b50813567ffffffffffffffff8111156128bd57600080fd5b6020830191508360208285010111156128d557600080fd5b9250929050565b600080602083850312156128ef57600080fd5b823567ffffffffffffffff81111561290657600080fd5b61291285828601612893565b90969095509350505050565b60006020828403121561293057600080fd5b611b0082612809565b6000806040838503121561294c57600080fd5b61295583612809565b91506020830135801515811461296a57600080fd5b809150509250929050565b60008060008060006080868803121561298d57600080fd5b61299686612809565b94506129a460208701612809565b935060408601359250606086013567ffffffffffffffff8111156129c757600080fd5b6129d388828901612893565b969995985093965092949392505050565b600080604083850312156129f757600080fd5b612a0083612809565b9150612a0e60208401612809565b90509250929050565b600181811c90821680612a2b57607f821691505b602082108103612a64577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215612a7c57600080fd5b8151611b0081612724565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115610a9057600081815260208120601f850160051c81016020861015612add5750805b601f850160051c820191505b81811015612afc57828155600101612ae9565b505050505050565b67ffffffffffffffff831115612b1c57612b1c612a87565b612b3083612b2a8354612a17565b83612ab6565b6000601f841160018114612b825760008515612b4c5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610e9e565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015612bd15786850135825560209485019460019092019101612bb1565b5086821015612c0c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612c7b602083018486612c1e565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152612cc3608083018486612c1e565b979650505050505050565b60008151612ce081856020860161276f565b9290920192915050565b6000808454612cf881612a17565b60018281168015612d105760018114612d4357612d72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450612d72565b8860005260208060002060005b85811015612d695781548a820152908401908201612d50565b50505082870194505b505050508351612d8681836020880161276f565b01949350505050565b7f7b226e616d65223a224375727461205e20506172616469676d2043544620323081527f323320506c61796572204e465473222c226465736372697074696f6e223a2200602082015260008251612ded81603f85016020870161276f565b7f227d000000000000000000000000000000000000000000000000000000000000603f939091019283015250604101919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612e5981601d85016020870161276f565b91909101601d0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561045c5761045c612e66565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615612ee057612ee0612e66565b818105831482151761045c5761045c612e66565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612f3257612f32612ef4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615612f8657612f86612e66565b500590565b8181036000831280158383131683831282161715612fab57612fab612e66565b5092915050565b808202811582820484141761045c5761045c612e66565b600082612fd857612fd8612ef4565b500690565b60008251612fef81846020870161276f565b9190910192915050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008551613031816009850160208a0161276f565b7f20e28888204375727461205e20506172616469676d204354462032303233222c6009918401918201527f226465736372697074696f6e223a22000000000000000000000000000000000060298201528551613094816038840160208a0161276f565b7f222c22616e696d6174696f6e5f75726c223a22646174613a746578742f68746d603892909101918201527f6c3b636861727365743d7574662d383b6261736536342c000000000000000000605882015284516130f881606f84016020890161276f565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a2250606f92909101918201527f6c61796572222c2276616c7565223a2200000000000000000000000000000000608f820152612cc3613159609f830186612cce565b7f227d2c7b2274726169745f74797065223a2259656172222c2276616c7565223a81527f323032337d5d7d00000000000000000000000000000000000000000000000000602082015260270190565b6000826131b7576131b7612ef4565b500490565b600089516131ce818460208e0161276f565b8951908301906131e2818360208e0161276f565b8082019150507f20e29482e29482535553504943494f555320434841524954592020202020202081527f3336392e3936e294820ae29482000000000000000000000000000000000000006020820152885161324481602d840160208d0161276f565b7f20202020e29482e2948246524545205245414c20455354415445202020202020602d92909101918201527f2020202020312e3734e294820ae2948200000000000000000000000000000000604d82015287516132a881605d840160208c0161276f565b7f202020202020e29482e29482475241494e53204f462053414e44202020202020605d92909101918201527f20202020203334332e3939e294820ae294820000000000000000000000000000607d82015261346961341a6134146133c56133bf61337061336a61331b608f89018f612cce565b7f2020e29482e2948244524f50504552202020202020202020202020202020202081527f203233332e3232e294820ae294820000000000000000000000000000000000006020820152602e0190565b8c612cce565b7f202020202020e29482e29482434f534d494320524144494154494f4e2020202081527f20202020202034332e3738e294820ae294820000000000000000000000000000602082015260320190565b89612cce565b7f202020e29482e29482445241474f4e20545952414e542020202020202020202081527f20203432352e3133e294820ae2948200000000000000000000000000000000006020820152602f0190565b86612cce565b7fe29482e29482484f5050494e4720494e544f20504c414345202020202020203381527f31362e3535e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b9b9a5050505050505050505050565b6000895161348a818460208e0161276f565b89519083019061349e818360208e0161276f565b8082019150507f2020202020e29482e29482454e544552505249534520424c4f434b434841494e81527f202020203237312e3232e294820ae2948200000000000000000000000000000060208201528851613500816031840160208d0161276f565b7f202020e29482e294824441492b2b202020202020202020202020202020202020603192909101918201527f20203331362e3535e294820ae29482000000000000000000000000000000000060518201528751613564816060840160208c0161276f565b7f202020e29482e29482444f444f4e54203c7370616e20636c6173733d633e5b46606092909101918201527f4952535420424c4f4f445d3c2f7370616e3e20202020203233332e3130e2948260808201527f0ae294820000000000000000000000000000000000000000000000000000000060a08201526134696136a161369b61364c6136466135f760a487018d612cce565b7fe29482e294824f56454e2020202020202020202020202020202020202020203281527f38312e3930e294820ae2948200000000000000000000000000000000000000006020820152602c0190565b8a612cce565b7f20e29482e29482534b494c4c2042415345442047414d4520202020202020202081527f3231342e3033e294820ae29482000000000000000000000000000000000000006020820152602d0190565b87612cce565b85612cce565b7f3c7370616e20636c6173733d63207374796c653d666f6e742d7765696768743a81527f3930303b746578742d6465636f726174696f6e3a756e6465726c696e653e000060208201526000825161370581603e85016020870161276f565b7f3c2f7370616e3e00000000000000000000000000000000000000000000000000603e93909101928301525060450191905056fe3c7374796c653e627574746f6e7b6865696768743a323070783b6d617267696e3a30206175746f3b626f726465723a303b6261636b67726f756e643a233030453130303b637572736f723a706f696e7465723b636f6c6f723a233030307d627574746f6e3a686f7665727b746578742d6465636f726174696f6e3a756e6465726c696e657d2e627b77696474683a35313270787d2e637b636f6c6f723a233030653130307d2e617b706f736974696f6e3a6162736f6c7574653b6d617267696e3a6175746f20303b626f726465722d7261646975733a313030253b746f703a3670783b77696474683a313270783b6865696768743a313270787d3c2f7374796c653e3c626f6479207374796c653d77696474683a36343070783b6865696768743a36343070783b6d617267696e3a303e3c64697620636c6173733d62207374796c653d226865696768743a35313270783b6261636b67726f756e643a233136313631363b70616464696e673a36347078223e3c646976207374796c653d226261636b67726f756e643a233030303b626f726465722d7261646975733a3870783b6865696768743a34363470783b6f766572666c6f773a68696464656e3b626f726465723a31707820736f6c696420233334333433343b6d617267696e3a323070782030223e3c646976207374796c653d706f736974696f6e3a72656c61746976653b646973706c61793a666c65783b77696474683a35303070783b6865696768743a323470783b6261636b67726f756e643a236461646164613b70616464696e672d6c6566743a3670783b70616464696e672d72696768743a3670783e3c636f6465207374796c653d666f6e742d7765696768743a3630303b6d617267696e3a6175746f3b636f6c6f723a233438343834383e4375727461205e20506172616469676d2043544620323032333c2f636f64653e3c646976207374796c653d6261636b67726f756e643a236564366135653b6c6566743a36707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a236635626634663b6c6566743a3232707820636c6173733d613e3c2f6469763e3c646976207374796c653d6261636b67726f756e643a233632633535353b6c6566743a3338707820636c6173733d613e3c2f6469763e3c2f6469763e3c707265207374796c653d2277696474683a34393670783b6865696768743a32393270783b646973706c61793a666c65783b70616464696e673a307078203870783b636f6c6f723a236666663b6d617267696e3a30223e3c636f6465207374796c653d6d617267696e3a6175746f3ee2948c3c7370616e20636c6173733d633e4d454d424552533c2f7370616e3ee29480e29480e29480e29490e2948c3c7370616e20636c6173733d633e4348414c4c454e47455320434f4d504c455445443c2f7370616e3ee29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294900ae29482524946462e00180057415645666d74201000000001000100401f0000401f000001001000646174610000180080416e204e465420636f6c6c656374696f6e20746f20636f6d6d656d6f7261746520706c6179657273206f6620746865204375727461207465616d20666f722074686569722070617274696369706174696f6e20616e6420706572666f726d616e636520696e20746865203230323320506172616469676d204354462e20496e206164646974696f6e20746f20646973706c6179696e6720746865207465616d277320726573756c74732c20746865206d65746164617461206f66206561636820746f6b656e20636f6e7461696e7320612031303025206f6e636861696e2d67656e65726174656420313a3338206d696e757465206c6f6e6720617564696f20617272616e67656d656e74206f66205c22496e207468652048616c6c206f6620746865204d6f756e7461696e204b696e675c222062792045647661726420477269656720776974682033206c617965726564206d656c6f6479206c696e657320616e6420612062617373206c696e65206174203131372e313837352042504d2e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f2020202020e29482e29482313030252020202020202020202020202020202020202020203230302e3635e294820ae2948220202020202020202020e29482e29482424c41434b20574f524c4420202020202020202020202020203138322e3830e294820ae2948220202020202020202020e29482e2948248454c4c4f20574f524c4420202020202020202020202020203133332e3232e294820ae29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29498e29494e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e29480e294983c2f636f64653e3c2f7072653e3c64697620636c6173733d62207374796c653d646973706c61793a666c65783e3c627574746f6e2069643d623e3c636f64653e5b205375626d697420504354467b43555237345f323032337d205d3c2f636f64653e3c2f627574746f6e3e3c2f6469763e3c617564696f2069643d613e596f75722062726f7773657220646f6573206e6f7420737570706f72742074686520617564696f20656c656d656e743c2f617564696f3e3c64697620636c6173733d62207374796c653d706f736974696f6e3a72656c61746976653b6865696768743a31323870783e3c63616e7661732069643d64207374796c653d706f736974696f6e3a6162736f6c7574652077696474683d353132206865696768743d3132383e3c2f63616e7661733e3c6469762069643d63207374796c653d22626f726465723a2e35707820736f6c696420233030653130303b6865696768743a31323770783b706f736974696f6e3a6162736f6c7574653b6c6566743a30223e3c2f6469763e3c2f6469763e3c2f6469763e3c7363726970743e646f63756d656e742e676574456c656d656e744279496428226222292e6164644576656e744c697374656e65722822636c69636b222c28293d3e7b673d303b6a3d303b666f7228733d22222c743d303b743c332a322a2a31383b742b2b297b633d2263686172436f64654174222c753d28743e3e31382925332c723d2874293d3e74263235363f74263235353a3235362d287426323535292c613d33302a742a322a2a2828222527282a2c282c2c2b272b2b2a262a2a2527282a2c282c312f2c282c2f2f2f2f225b635d28743e3e3131263331292b5b302c31322c372c31395d5b743e3e313626335d292f31322d36292c783d33302a742a322a2a282822252c252c252c252c252c252c282f282f2c332c3328302c33225b635d28382a28743e3e313726313f323a743e3e31352631292b28743e3e313226372929292f31322d37292c793d612a322c7a3d792a323b732b3d537472696e672e66726f6d43686172436f64652828722861292f28352d28753e3129292b28753e30292f352a722879292b28753e31292a2872287a292f352b722878292f342929253235367c30297d613d646f63756d656e742e676574456c656d656e744279496428226122293b612e7372633d22646174613a617564696f2f7761763b6261736536342c556b6c47526934414741425851565a465a6d3130494241414141414241414541514238414145416641414142414167415a4746305951414147414341222b62746f612873293b612e706c617928293b736574496e74657276616c2828293d3e7b633d646f63756d656e742e676574456c656d656e744279496428226322293b632e7374796c652e6c6566743d284d6174682e6d696e283132382a672b3132382c6a2b2b292a3130302f313238292b2225223b7d2c3332293b683d28293d3e7b643d646f63756d656e742e676574456c656d656e744279496428226422292e676574436f6e746578742822326422293b642e636c6561725265637428302c302c3531322c313238293b642e66696c6c5374796c653d2223464646223b5b2e2e2e41727261792834303936295d2e6d617028285f2c69293d3e7b642e626567696e5061746828293b642e61726328692f382c3132382d732e63686172436f646541742833323736382a672b692a38292f322c312c302c322a4d6174682e5049293b642e66696c6c28293b7d293b672b2b3b6a3d303b7d3b6828293b736574496e74657276616c28682c34303936297d293c2f7363726970743ea2646970667358221220014028a5543be52c0f1d32e7068286c08c6bd65bd1b045bf34f55a45a8d5c19e64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f
-----Decoded View---------------
Arg [0] : _owner (address): 0x5dd2083A0D68C4EB8fEd93EF010D1b0D68B3880F
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005dd2083a0d68c4eb8fed93ef010d1b0d68b3880f
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.