ERC-721
Overview
Max Total Supply
1,302 CBP
Holders
350
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 CBPLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
CoinbasePunks
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // // _____ _ _ _ // | |___|_|___| |_ ___ ___ ___ ___ _ _ ___| |_ ___ // | --| . | | | . | .'|_ -| -_| | . | | | | '_|_ -| // |_____|___|_|_|_|___|__,|___|___| | _|___|_|_|_,_|___| // |_| // pragma solidity ^0.8.13; import "solmate/tokens/ERC721.sol"; import "solady/utils/LibString.sol"; import "solady/utils/SafeTransferLib.sol"; import "./layerzero/Ownable.sol"; import "./layerzero/NonblockingLzApp.sol"; contract CoinbasePunks is ERC721, Ownable, NonblockingLzApp { using LibString for uint256; /*////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////*/ error NoContracts(); error TooManyMints(); error IncorrectFunds(); error NotEnoughSupply(); error MintNotActive(); error NotTokenOwner(); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ uint256 public constant MAX_SUPPLY = 10000; uint256 public constant MAX_AMOUNT = 5; uint256 public price; uint256 public totalSupply; bool public mintActive; string public baseURI; // constructor requires the LayerZero endpoint for this chain constructor(address _endpoint) ERC721("Coinbase Punks", "CBP") NonblockingLzApp(_endpoint) { // mint 100 for the team + giveaways _mintPunks(100); } /*////////////////////////////////////////////////////////////// PUBLIC //////////////////////////////////////////////////////////////*/ function mint(uint256 amount) external payable { if (!mintActive) revert MintNotActive(); if (tx.origin != msg.sender) revert NoContracts(); if (amount > MAX_AMOUNT) revert TooManyMints(); if (msg.value != price * amount) revert IncorrectFunds(); if (amount + totalSupply > MAX_SUPPLY) revert NotEnoughSupply(); _mintPunks(amount); } // This function transfers the nft from sender on the // source chain to the same address on the destination chain function traverseChains(uint16 _chainId, uint256 tokenId) public payable { if (msg.sender == ownerOf(tokenId)) revert NotTokenOwner(); // burn NFT on this chain _burn(tokenId); // abi.encode() the payload with the values to send bytes memory payload = abi.encode(msg.sender, tokenId); // encode adapterParams to specify more gas for the destination uint16 version = 1; uint256 gasForDestinationLzReceive = 350000; bytes memory adapterParams = abi.encodePacked( version, gasForDestinationLzReceive ); _lzSend( // {value: messageFee} _chainId, // destination chainId payload, // abi.encode()'ed bytes payable(msg.sender), // refund address (LayerZero will refund any extra gas back to caller of send() address(0x0), // future param, unused for this adapterParams, // v1 adapterParams, specify custom destination gas qty msg.value ); } /*////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ function _mintPunks(uint256 amount) internal { uint256 currSupply = totalSupply; unchecked { uint256 i; for (; i < amount; ) { _mint(msg.sender, currSupply++); ++i; } } totalSupply = currSupply; } // callback is called when NFTs traverse chains function _nonblockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64, /*_nonce*/ bytes memory _payload ) internal override { // old way: // address sendBackToAddress; // assembly { // sendBackToAddress := mload(add(_srcAddress, 20)) // } // decode (address toAddr, uint256 tokenId) = abi.decode( _payload, (address, uint256) ); // mint the tokens back into existence on this chain _mint(toAddr, tokenId); } /*////////////////////////////////////////////////////////////// VIEW //////////////////////////////////////////////////////////////*/ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { return string(abi.encodePacked(baseURI, tokenId.toString())); } /*////////////////////////////////////////////////////////////// ADMIN //////////////////////////////////////////////////////////////*/ function flipMint() external onlyOwner { mintActive = !mintActive; } function setPrice(uint256 mintPrice) external onlyOwner { price = mintPrice; } function withdraw() external onlyOwner { SafeTransferLib.safeTransferETH(msg.sender, address(this).balance); } function setBaseURI(string memory uri) external onlyOwner { baseURI = uri; } }
// 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 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 toHexStringChecksumed(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, and(add(o, 31), not(31))) // 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 } } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) 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) // Zeroize the slot after the string. let last := add(add(result, 0x20), k) mstore(last, 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) // Store the length of the result. mstore(result, k) } } /// @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(32, and(searchLength, 31))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 32)) { 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 } } // Zeroize the slot after the string. mstore(output, 0) // Store the length. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 63), not(31)))) } } } /// @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(31) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 31), 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, 63), 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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) 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(31) 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, 31), 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, 63), 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(31) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(mload(a), 32), 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, mload(a)) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 32), 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, 31), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. 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)), 67108863) 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 } } // Restore the result. result := mload(0x40) // Stores the string length. mstore(result, length) // Zeroize the slot after the string. let last := add(add(result, 0x20), length) mstore(last, 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } } /// @dev Returns a lowercased copy of the string. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. 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 { for { 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)) } 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, 31))) result := add(result, shr(5, t)) } let last := result // Zeroize the slot after the string. mstore(last, 0) // Restore the result to the start of the free memory. result := mload(0x40) // Store the length of the result. mstore(result, sub(last, add(result, 0x20))) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // 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)) } 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) } let last := result // Zeroize the slot after the string. mstore(last, 0) // Restore the result to the start of the free memory. result := mload(0x40) // Store the length of the result. mstore(result, sub(last, add(result, 0x20))) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @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 behaviour 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 behaviour 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: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` (in wei) ETH to `to`. /// Reverts upon failure. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0, 0, 0, 0)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default /// for 99% of cases and can be overriden with the three-argument version of this /// function if necessary. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount) internal { // Manually inlined because the compiler doesn't inline functions with branches. /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend. /// /// Note: Does NOT revert upon failure. /// Returns whether the transfer of ETH is successful instead. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. success := call(gasStipend, to, amount, 0, 0, 0, 0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x20, from) // Store the `from` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x60, amount) // Store the `amount` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, from) // Store the `from` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x40, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x6a. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x3a, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x1a, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x3a. amount := mload(0x3a) // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0x095ea7b3000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, account) // Store the `account` argument. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x20, 0x20) ) ) } } }
// 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.0; import "./Ownable.sol"; import "solmate/tokens/ERC721.sol"; import "./interfaces/ILayerZeroReceiver.sol"; import "./interfaces/ILayerZeroUserApplicationConfig.sol"; import "./interfaces/ILayerZeroEndpoint.sol"; library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } } /* * a generic LzReceiver implementation */ abstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig { using BytesLib for bytes; // ua can not send payload larger than this by default, but it can be changed by the ua owner uint256 public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000; ILayerZeroEndpoint public immutable lzEndpoint; mapping(uint16 => bytes) public trustedRemoteLookup; mapping(uint16 => mapping(uint16 => uint256)) public minDstGasLookup; mapping(uint16 => uint256) public payloadSizeLimitLookup; address public precrime; event SetPrecrime(address precrime); event SetTrustedRemote(uint16 _remoteChainId, bytes _path); event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress); event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint256 _minDstGas); constructor(address _endpoint) { lzEndpoint = ILayerZeroEndpoint(_endpoint); } function lzReceive( uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload ) public virtual override { // lzReceive must be called by the endpoint for security require( _msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller" ); bytes memory trustedRemote = trustedRemoteLookup[_srcChainId]; // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote. require( _srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract" ); _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); } // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging function _blockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload ) internal virtual; function _lzSend( uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint256 _nativeFee ) internal virtual { bytes memory trustedRemote = trustedRemoteLookup[_dstChainId]; require( trustedRemote.length != 0, "LzApp: destination chain is not a trusted source" ); _checkPayloadSize(_dstChainId, _payload.length); lzEndpoint.send{value: _nativeFee}( _dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams ); } function _checkGasLimit( uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint256 _extraGas ) internal view virtual { uint256 providedGasLimit = _getGasLimit(_adapterParams); uint256 minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas; require(minGasLimit > 0, "LzApp: minGasLimit not set"); require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low"); } function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint256 gasLimit) { require(_adapterParams.length >= 34, "LzApp: invalid adapterParams"); assembly { gasLimit := mload(add(_adapterParams, 34)) } } function _checkPayloadSize(uint16 _dstChainId, uint256 _payloadSize) internal view virtual { uint256 payloadSizeLimit = payloadSizeLimitLookup[_dstChainId]; if (payloadSizeLimit == 0) { // use default if not set payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT; } require( _payloadSize <= payloadSizeLimit, "LzApp: payload size is too large" ); } //---------------------------UserApplication config---------------------------------------- function getConfig( uint16 _version, uint16 _chainId, address, uint256 _configType ) external view returns (bytes memory) { return lzEndpoint.getConfig( _version, _chainId, address(this), _configType ); } // generic config for LayerZero user Application function setConfig( uint16 _version, uint16 _chainId, uint256 _configType, bytes calldata _config ) external override onlyOwner { lzEndpoint.setConfig(_version, _chainId, _configType, _config); } function setSendVersion(uint16 _version) external override onlyOwner { lzEndpoint.setSendVersion(_version); } function setReceiveVersion(uint16 _version) external override onlyOwner { lzEndpoint.setReceiveVersion(_version); } function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner { lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress); } // _path = abi.encodePacked(remoteAddress, localAddress) // this function set the trusted path for the cross-chain communication function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external onlyOwner { trustedRemoteLookup[_srcChainId] = _path; emit SetTrustedRemote(_srcChainId, _path); } function setTrustedRemoteAddress( uint16 _remoteChainId, bytes calldata _remoteAddress ) external onlyOwner { trustedRemoteLookup[_remoteChainId] = abi.encodePacked( _remoteAddress, address(this) ); emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress); } function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) { bytes memory path = trustedRemoteLookup[_remoteChainId]; require(path.length != 0, "LzApp: no trusted path record"); return path.slice(0, path.length - 20); // the last 20 bytes should be address(this) } function setPrecrime(address _precrime) external onlyOwner { precrime = _precrime; emit SetPrecrime(_precrime); } function setMinDstGas( uint16 _dstChainId, uint16 _packetType, uint256 _minGas ) external onlyOwner { require(_minGas > 0, "LzApp: invalid minGas"); minDstGasLookup[_dstChainId][_packetType] = _minGas; emit SetMinDstGas(_dstChainId, _packetType, _minGas); } // if the size is 0, it means default size limit function setPayloadSizeLimit(uint16 _dstChainId, uint256 _size) external onlyOwner { payloadSizeLimitLookup[_dstChainId] = _size; } //--------------------------- VIEW FUNCTION ---------------------------------------- function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) { bytes memory trustedSource = trustedRemoteLookup[_srcChainId]; return keccak256(trustedSource) == keccak256(_srcAddress); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./LzApp.sol"; library ExcessivelySafeCall { uint256 constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeCall( address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata ) internal returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := call( _gas, // gas _target, // recipient 0, // ether value add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeStaticCall( address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata ) internal view returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := staticcall( _gas, // gas _target, // recipient add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /** * @notice Swaps function selectors in encoded contract calls * @dev Allows reuse of encoded calldata for functions with identical * argument types but different names. It simply swaps out the first 4 bytes * for the new selector. This function modifies memory in place, and should * only be used with caution. * @param _newSelector The new 4-byte selector * @param _buf The encoded contract args */ function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure { require(_buf.length >= 4); uint256 _mask = LOW_28_MASK; assembly { // load the first word of let _word := mload(add(_buf, 0x20)) // mask out the top 4 bytes // /x _word := and(_word, _mask) _word := or(_newSelector, _word) mstore(add(_buf, 0x20), _word) } } } /* * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress) */ abstract contract NonblockingLzApp is LzApp { using ExcessivelySafeCall for address; constructor(address _endpoint) LzApp(_endpoint) {} mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages; event MessageFailed( uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason ); event RetryMessageSuccess( uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash ); // overriding the virtual function in LzReceiver function _blockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload ) internal virtual override { (bool success, bytes memory reason) = address(this).excessivelySafeCall( gasleft(), 150, abi.encodeWithSelector( this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload ) ); // try-catch all errors/exceptions if (!success) { _storeFailedMessage( _srcChainId, _srcAddress, _nonce, _payload, reason ); } } function _storeFailedMessage( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload, bytes memory _reason ) internal virtual { failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload); emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason); } function nonblockingLzReceive( uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload ) public virtual { // only internal transaction require( _msgSender() == address(this), "NonblockingLzApp: caller must be LzApp" ); _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); } //@notice override this function function _nonblockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload ) internal virtual; function retryMessage( uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload ) public payable virtual { // assert there is message to retry bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce]; require( payloadHash != bytes32(0), "NonblockingLzApp: no stored message" ); require( keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload" ); // clear the stored message failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0); // execute the message. revert if it fails again _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require( newOwner != address(0), "Ownable: new owner is the zero address" ); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; import "./ILayerZeroUserApplicationConfig.sol"; interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig { // @notice send a LayerZero message to the specified address at a LayerZero endpoint. // @param _dstChainId - the destination chain identifier // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains // @param _payload - a custom bytes payload to send to the destination contract // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination function send( uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams ) external payable; // @notice used by the messaging library to publish verified payload // @param _srcChainId - the source chain identifier // @param _srcAddress - the source contract (as bytes) at the source chain // @param _dstAddress - the address on destination chain // @param _nonce - the unbound message ordering nonce // @param _gasLimit - the gas limit for external contract execution // @param _payload - verified payload to send to the destination contract function receivePayload( uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint256 _gasLimit, bytes calldata _payload ) external; // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64); // @notice get the outboundNonce from this source chain which, consequently, is always an EVM // @param _srcAddress - the source chain contract address function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery // @param _dstChainId - the destination chain identifier // @param _userApplication - the user app address on this EVM chain // @param _payload - the custom message to send over LayerZero // @param _payInZRO - if false, user app pays the protocol fee in native token // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain function estimateFees( uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam ) external view returns (uint256 nativeFee, uint256 zroFee); // @notice get this Endpoint's immutable source identifier function getChainId() external view returns (uint16); // @notice the interface to retry failed message on this Endpoint destination // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address // @param _payload - the payload to be retried function retryPayload( uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload ) external; // @notice query if any STORED payload (message blocking) at the endpoint. // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool); // @notice query if the _libraryAddress is valid for sending msgs. // @param _userApplication - the user app address on this EVM chain function getSendLibraryAddress(address _userApplication) external view returns (address); // @notice query if the _libraryAddress is valid for receiving msgs. // @param _userApplication - the user app address on this EVM chain function getReceiveLibraryAddress(address _userApplication) external view returns (address); // @notice query if the non-reentrancy guard for send() is on // @return true if the guard is on. false otherwise function isSendingPayload() external view returns (bool); // @notice query if the non-reentrancy guard for receive() is on // @return true if the guard is on. false otherwise function isReceivingPayload() external view returns (bool); // @notice get the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _userApplication - the contract address of the user application // @param _configType - type of configuration. every messaging library has its own convention. function getConfig( uint16 _version, uint16 _chainId, address _userApplication, uint256 _configType ) external view returns (bytes memory); // @notice get the send() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getSendVersion(address _userApplication) external view returns (uint16); // @notice get the lzReceive() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getReceiveVersion(address _userApplication) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface ILayerZeroReceiver { // @notice LayerZero endpoint will invoke this function to deliver the message on the destination // @param _srcChainId - the source endpoint identifier // @param _srcAddress - the source sending contract address from the source chain // @param _nonce - the ordered message nonce // @param _payload - the signed payload is the UA bytes has encoded to be sent function lzReceive( uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface ILayerZeroUserApplicationConfig { // @notice set the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _configType - type of configuration. every messaging library has its own convention. // @param _config - configuration in the bytes. can encode arbitrary content. function setConfig( uint16 _version, uint16 _chainId, uint256 _configType, bytes calldata _config ) external; // @notice set the send() LayerZero messaging library version to _version // @param _version - new messaging library version function setSendVersion(uint16 _version) external; // @notice set the lzReceive() LayerZero messaging library version to _version // @param _version - new messaging library version function setReceiveVersion(uint16 _version) external; // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload // @param _srcChainId - the chainId of the source chain // @param _srcAddress - the contract address of the source contract at the source chain function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external; }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "oz-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "solady/=lib/solady/src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IncorrectFunds","type":"error"},{"inputs":[],"name":"MintNotActive","type":"error"},{"inputs":[],"name":"NoContracts","type":"error"},{"inputs":[],"name":"NotEnoughSupply","type":"error"},{"inputs":[],"name":"NotTokenOwner","type":"error"},{"inputs":[],"name":"TooManyMints","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":false,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"_nonce","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"_payload","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"_reason","type":"bytes"}],"name":"MessageFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"_nonce","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"_payloadHash","type":"bytes32"}],"name":"RetryMessageSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_type","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_path","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_PAYLOAD_SIZE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"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":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"failedMessages","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"_configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"}],"name":"getTrustedRemoteAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"minDstGasLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"nonblockingLzReceive","outputs":[],"stateMutability":"nonpayable","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":"uint16","name":"","type":"uint16"}],"name":"payloadSizeLimitLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"retryMessage","outputs":[],"stateMutability":"payable","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":"uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"_configType","type":"uint256"},{"internalType":"bytes","name":"_config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_packetType","type":"uint16"},{"internalType":"uint256","name":"_minGas","type":"uint256"}],"name":"setMinDstGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_size","type":"uint256"}],"name":"setPayloadSizeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_precrime","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPrice","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"setTrustedRemoteAddress","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":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"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"},{"inputs":[{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"traverseChains","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620036a7380380620036a7833981016040819052620000349162000270565b80806040518060400160405280600e81526020016d436f696e626173652050756e6b7360901b8152506040518060400160405280600381526020016204342560ec1b81525081600090816200008a919062000347565b50600162000099828262000347565b505050620000b6620000b0620000d660201b60201c565b620000da565b6001600160a01b031660805250620000cf60646200012c565b5062000413565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600d5460005b82811015620001565760018201916200014d9033906200015d565b60010162000132565b50600d5550565b6001600160a01b038216620001ad5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b60448201526064015b60405180910390fd5b6000818152600260205260409020546001600160a01b031615620002055760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401620001a4565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000602082840312156200028357600080fd5b81516001600160a01b03811681146200029b57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002cd57607f821691505b602082108103620002ee57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200034257600081815260208120601f850160051c810160208610156200031d5750805b601f850160051c820191505b818110156200033e5782815560010162000329565b5050505b505050565b81516001600160401b03811115620003635762000363620002a2565b6200037b81620003748454620002b8565b84620002f4565b602080601f831160018114620003b357600084156200039a5750858301515b600019600386901b1c1916600185901b1785556200033e565b600085815260208120601f198616915b82811015620003e457888601518255948401946001909101908401620003c3565b5085821015620004035787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161324762000460600039600081816107890152818161093901528181610c6801528181610df2015281816111e7015281816118b701528181611db4015261230e01526132476000f3fe6080604052600436106102c85760003560e01c80638cfd8f5c11610175578063baf3292d116100dc578063d2ed5c5911610095578063e985e9c51161006f578063e985e9c51461089b578063eb8d72b7146108d6578063f2fde38b146108f6578063f5ecbdbc1461091657600080fd5b8063d2ed5c5914610851578063d40dc87014610866578063df2a5b3b1461087b57600080fd5b8063baf3292d146107cb578063c446183414610472578063c87b56dd146107eb578063cbed8b9c1461080b578063cf89fa031461082b578063d1deba1f1461083e57600080fd5b8063a035b1fe1161012e578063a035b1fe1461070e578063a0712d6814610724578063a22cb46514610737578063a6c3d16514610757578063b353aaa714610777578063b88d4fde146107ab57600080fd5b80638cfd8f5c146106435780638da5cb5b1461067b57806391b7f5ed14610699578063950c8a74146106b957806395d89b41146106d95780639f38369a146106ee57600080fd5b80633ccfd60b116102345780635b8c41e6116101ed5780636c0360eb116101c75780636c0360eb146105d957806370a08231146105ee578063715018a61461060e5780637533d7881461062357600080fd5b80635b8c41e61461054a5780636352211e1461059957806366ad5c8a146105b957600080fd5b80633ccfd60b146104885780633d8b38f61461049d5780633f1f4fa4146104bd57806342842e0e146104ea57806342d65a8d1461050a57806355f804b31461052a57600080fd5b80630df37483116102865780630df37483146103d457806310ddb137146103f457806318160ddd1461041457806323b872dd1461043857806325fd90f31461045857806332cb6b0c1461047257600080fd5b80621d3567146102cd57806301ffc9a7146102ef57806306fdde031461032457806307e0db1714610346578063081812fc14610366578063095ea7b3146103b4575b600080fd5b3480156102d957600080fd5b506102ed6102e836600461269e565b610936565b005b3480156102fb57600080fd5b5061030f61030a366004612747565b610b67565b60405190151581526020015b60405180910390f35b34801561033057600080fd5b50610339610bb9565b60405161031b91906127b4565b34801561035257600080fd5b506102ed6103613660046127c7565b610c47565b34801561037257600080fd5b5061039c6103813660046127e2565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161031b565b3480156103c057600080fd5b506102ed6103cf366004612810565b610cd0565b3480156103e057600080fd5b506102ed6103ef36600461283c565b610db2565b34801561040057600080fd5b506102ed61040f3660046127c7565b610dd1565b34801561042057600080fd5b5061042a600d5481565b60405190815260200161031b565b34801561044457600080fd5b506102ed610453366004612858565b610e29565b34801561046457600080fd5b50600e5461030f9060ff1681565b34801561047e57600080fd5b5061042a61271081565b34801561049457600080fd5b506102ed610ff0565b3480156104a957600080fd5b5061030f6104b8366004612899565b611004565b3480156104c957600080fd5b5061042a6104d83660046127c7565b60096020526000908152604090205481565b3480156104f657600080fd5b506102ed610505366004612858565b6110d0565b34801561051657600080fd5b506102ed610525366004612899565b6111c8565b34801561053657600080fd5b506102ed610545366004612996565b61124e565b34801561055657600080fd5b5061042a6105653660046129e6565b600b602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b3480156105a557600080fd5b5061039c6105b43660046127e2565b611266565b3480156105c557600080fd5b506102ed6105d436600461269e565b6112bd565b3480156105e557600080fd5b50610339611399565b3480156105fa57600080fd5b5061042a610609366004612a57565b6113a6565b34801561061a57600080fd5b506102ed611409565b34801561062f57600080fd5b5061033961063e3660046127c7565b61141b565b34801561064f57600080fd5b5061042a61065e366004612a74565b600860209081526000928352604080842090915290825290205481565b34801561068757600080fd5b506006546001600160a01b031661039c565b3480156106a557600080fd5b506102ed6106b43660046127e2565b611434565b3480156106c557600080fd5b50600a5461039c906001600160a01b031681565b3480156106e557600080fd5b50610339611441565b3480156106fa57600080fd5b506103396107093660046127c7565b61144e565b34801561071a57600080fd5b5061042a600c5481565b6102ed6107323660046127e2565b611564565b34801561074357600080fd5b506102ed610752366004612aa7565b611632565b34801561076357600080fd5b506102ed610772366004612899565b61169e565b34801561078357600080fd5b5061039c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107b757600080fd5b506102ed6107c6366004612ae5565b611727565b3480156107d757600080fd5b506102ed6107e6366004612a57565b611808565b3480156107f757600080fd5b506103396108063660046127e2565b611864565b34801561081757600080fd5b506102ed610826366004612b57565b611898565b6102ed61083936600461283c565b61192d565b6102ed61084c36600461269e565b6119cf565b34801561085d57600080fd5b506102ed611be5565b34801561087257600080fd5b5061042a600581565b34801561088757600080fd5b506102ed610896366004612b86565b611c01565b3480156108a757600080fd5b5061030f6108b6366004612bc2565b600560209081526000928352604080842090915290825290205460ff1681565b3480156108e257600080fd5b506102ed6108f1366004612899565b611cb3565b34801561090257600080fd5b506102ed610911366004612a57565b611d0d565b34801561092257600080fd5b50610339610931366004612bf0565b611d83565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146109b35760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff8616600090815260076020526040812080546109d190612c3d565b80601f01602080910402602001604051908101604052809291908181526020018280546109fd90612c3d565b8015610a4a5780601f10610a1f57610100808354040283529160200191610a4a565b820191906000526020600020905b815481529060010190602001808311610a2d57829003601f168201915b50505050509050805186869050148015610a65575060008151115b8015610a8d575080516020820120604051610a839088908890612c77565b6040518091039020145b610ae85760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b60648201526084016109aa565b610b5e8787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611e3492505050565b50505050505050565b60006301ffc9a760e01b6001600160e01b031983161480610b9857506380ac58cd60e01b6001600160e01b03198316145b80610bb35750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610bc690612c3d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bf290612c3d565b8015610c3f5780601f10610c1457610100808354040283529160200191610c3f565b820191906000526020600020905b815481529060010190602001808311610c2257829003601f168201915b505050505081565b610c4f611ead565b6040516307e0db1760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906307e0db17906024015b600060405180830381600087803b158015610cb557600080fd5b505af1158015610cc9573d6000803e3d6000fd5b5050505050565b6000818152600260205260409020546001600160a01b031633811480610d1957506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d565760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016109aa565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610dba611ead565b61ffff909116600090815260096020526040902055565b610dd9611ead565b6040516310ddb13760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906310ddb13790602401610c9b565b6000818152600260205260409020546001600160a01b03848116911614610e7f5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016109aa565b6001600160a01b038216610ec95760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b60448201526064016109aa565b336001600160a01b0384161480610f0357506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80610f2457506000818152600460205260409020546001600160a01b031633145b610f615760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016109aa565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610ff8611ead565b6110023347611f07565b565b61ffff83166000908152600760205260408120805482919061102590612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461105190612c3d565b801561109e5780601f106110735761010080835404028352916020019161109e565b820191906000526020600020905b81548152906001019060200180831161108157829003601f168201915b5050505050905083836040516110b5929190612c77565b60405180910390208180519060200120149150509392505050565b6110db838383610e29565b6001600160a01b0382163b15806111845750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611154573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111789190612c87565b6001600160e01b031916145b6111c35760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016109aa565b505050565b6111d0611ead565b6040516342d65a8d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906342d65a8d9061122090869086908690600401612ccd565b600060405180830381600087803b15801561123a57600080fd5b505af1158015610b5e573d6000803e3d6000fd5b611256611ead565b600f6112628282612d31565b5050565b6000818152600260205260409020546001600160a01b0316806112b85760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016109aa565b919050565b33301461131b5760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b60648201526084016109aa565b6113918686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f890181900481028201810190925287815289935091508790879081908401838280828437600092019190915250611f2392505050565b505050505050565b600f8054610bc690612c3d565b60006001600160a01b0382166113ed5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b60448201526064016109aa565b506001600160a01b031660009081526003602052604090205490565b611411611ead565b6110026000611f48565b60076020526000908152604090208054610bc690612c3d565b61143c611ead565b600c55565b60018054610bc690612c3d565b61ffff811660009081526007602052604081208054606092919061147190612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461149d90612c3d565b80156114ea5780601f106114bf576101008083540402835291602001916114ea565b820191906000526020600020905b8154815290600101906020018083116114cd57829003601f168201915b5050505050905080516000036115425760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f726400000060448201526064016109aa565b61155d6000601483516115559190612e06565b839190611f9a565b9392505050565b600e5460ff166115875760405163914edb0f60e01b815260040160405180910390fd5b3233146115a75760405163875fdad760e01b815260040160405180910390fd5b60058111156115c95760405163ed302ecd60e01b815260040160405180910390fd5b80600c546115d79190612e19565b34146115f657604051637832e81760e01b815260040160405180910390fd5b612710600d54826116079190612e30565b1115611626576040516374d9e0b960e01b815260040160405180910390fd5b61162f816120a7565b50565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6116a6611ead565b8181306040516020016116bb93929190612e43565b60408051601f1981840301815291815261ffff85166000908152600760205220906116e69082612d31565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce83838360405161171a93929190612ccd565b60405180910390a1505050565b611732858585610e29565b6001600160a01b0384163b15806117c95750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a029061177a9033908a90899089908990600401612e69565b6020604051808303816000875af1158015611799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190612c87565b6001600160e01b031916145b610cc95760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016109aa565b611810611ead565b600a80546001600160a01b0319166001600160a01b0383169081179091556040519081527f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9060200160405180910390a150565b6060600f611871836120d4565b604051602001611882929190612ea8565b6040516020818303038152906040529050919050565b6118a0611ead565b6040516332fb62e760e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbed8b9c906118f49088908890889088908890600401612f2f565b600060405180830381600087803b15801561190e57600080fd5b505af1158015611922573d6000803e3d6000fd5b505050505050505050565b61193681611266565b6001600160a01b0316330361195e576040516359dc379f60e01b815260040160405180910390fd5b61196781612118565b6040805133602082015290810182905260009060600160408051808303601f1901815290829052600160f01b602083015262055730602283018190529092506001916000906042016040516020818303038152906040529050611391868533600085346121e5565b61ffff86166000908152600b602052604080822090516119f29088908890612c77565b90815260408051602092819003830190206001600160401b03871660009081529252902054905080611a725760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b60648201526084016109aa565b808383604051611a83929190612c77565b604051809103902014611ae25760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b60648201526084016109aa565b61ffff87166000908152600b60205260408082209051611b059089908990612c77565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611b9d918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611f2392505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58787878785604051611bd4959493929190612f5d565b60405180910390a150505050505050565b611bed611ead565b600e805460ff19811660ff90911615179055565b611c09611ead565b60008111611c515760405162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b60448201526064016109aa565b61ffff83811660008181526008602090815260408083209487168084529482529182902085905581519283528201929092529081018290527f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac09060600161171a565b611cbb611ead565b61ffff83166000908152600760205260409020611cd9828483612f98565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab83838360405161171a93929190612ccd565b611d15611ead565b6001600160a01b038116611d7a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109aa565b61162f81611f48565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611e03573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e2b9190810190613057565b95945050505050565b600080611e975a60966366ad5c8a60e01b89898989604051602401611e5c94939291906130c4565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091523092919061238a565b9150915081611391576113918686868685612414565b6006546001600160a01b031633146110025760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109aa565b60008060008084865af16112625763b12d13eb6000526004601cfd5b60008082806020019051810190611f3a9190613102565b9150915061139182826124b1565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606081611fa881601f612e30565b1015611fe75760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016109aa565b611ff18284612e30565b845110156120355760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016109aa565b606082158015612054576040519150600082526020820160405261209e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561208d578051835260209283019201612075565b5050858452601f01601f1916604052505b50949350505050565b600d5460005b828110156120cd576120c533838060010194506124b1565b6001016120ad565b50600d5550565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a9004806120ef575050819003601f19909101908152919050565b6000818152600260205260409020546001600160a01b03168061216a5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016109aa565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b61ffff86166000908152600760205260408120805461220390612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461222f90612c3d565b801561227c5780601f106122515761010080835404028352916020019161227c565b820191906000526020600020905b81548152906001019060200180831161225f57829003601f168201915b5050505050905080516000036122ed5760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b60648201526084016109aa565b6122f88787516125bc565b60405162c5803160e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c580310090849061234f908b9086908c908c908c908c90600401613130565b6000604051808303818588803b15801561236857600080fd5b505af115801561237c573d6000803e3d6000fd5b505050505050505050505050565b6000606060008060008661ffff166001600160401b038111156123af576123af6128eb565b6040519080825280601f01601f1916602001820160405280156123d9576020820181803683370190505b50905060008087516020890160008d8df191503d9250868311156123fb578692505b828152826000602083013e909890975095505050505050565b8180519060200120600b60008761ffff1661ffff168152602001908152602001600020856040516124459190613197565b9081526040805191829003602090810183206001600160401b0388166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c906124a290879087908790879087906131b3565b60405180910390a15050505050565b6001600160a01b0382166124fb5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b60448201526064016109aa565b6000818152600260205260409020546001600160a01b0316156125515760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b60448201526064016109aa565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b61ffff8216600090815260096020526040812054908190036125dd57506127105b808211156111c35760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c6172676560448201526064016109aa565b803561ffff811681146112b857600080fd5b60008083601f84011261265157600080fd5b5081356001600160401b0381111561266857600080fd5b60208301915083602082850101111561268057600080fd5b9250929050565b80356001600160401b03811681146112b857600080fd5b600080600080600080608087890312156126b757600080fd5b6126c08761262d565b955060208701356001600160401b03808211156126dc57600080fd5b6126e88a838b0161263f565b90975095508591506126fc60408a01612687565b9450606089013591508082111561271257600080fd5b5061271f89828a0161263f565b979a9699509497509295939492505050565b6001600160e01b03198116811461162f57600080fd5b60006020828403121561275957600080fd5b813561155d81612731565b60005b8381101561277f578181015183820152602001612767565b50506000910152565b600081518084526127a0816020860160208601612764565b601f01601f19169290920160200192915050565b60208152600061155d6020830184612788565b6000602082840312156127d957600080fd5b61155d8261262d565b6000602082840312156127f457600080fd5b5035919050565b6001600160a01b038116811461162f57600080fd5b6000806040838503121561282357600080fd5b823561282e816127fb565b946020939093013593505050565b6000806040838503121561284f57600080fd5b61282e8361262d565b60008060006060848603121561286d57600080fd5b8335612878816127fb565b92506020840135612888816127fb565b929592945050506040919091013590565b6000806000604084860312156128ae57600080fd5b6128b78461262d565b925060208401356001600160401b038111156128d257600080fd5b6128de8682870161263f565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612929576129296128eb565b604052919050565b60006001600160401b0382111561294a5761294a6128eb565b50601f01601f191660200190565b600061296b61296684612931565b612901565b905082815283838301111561297f57600080fd5b828260208301376000602084830101529392505050565b6000602082840312156129a857600080fd5b81356001600160401b038111156129be57600080fd5b8201601f810184136129cf57600080fd5b6129de84823560208401612958565b949350505050565b6000806000606084860312156129fb57600080fd5b612a048461262d565b925060208401356001600160401b03811115612a1f57600080fd5b8401601f81018613612a3057600080fd5b612a3f86823560208401612958565b925050612a4e60408501612687565b90509250925092565b600060208284031215612a6957600080fd5b813561155d816127fb565b60008060408385031215612a8757600080fd5b612a908361262d565b9150612a9e6020840161262d565b90509250929050565b60008060408385031215612aba57600080fd5b8235612ac5816127fb565b915060208301358015158114612ada57600080fd5b809150509250929050565b600080600080600060808688031215612afd57600080fd5b8535612b08816127fb565b94506020860135612b18816127fb565b93506040860135925060608601356001600160401b03811115612b3a57600080fd5b612b468882890161263f565b969995985093965092949392505050565b600080600080600060808688031215612b6f57600080fd5b612b788661262d565b9450612b186020870161262d565b600080600060608486031215612b9b57600080fd5b612ba48461262d565b9250612bb26020850161262d565b9150604084013590509250925092565b60008060408385031215612bd557600080fd5b8235612be0816127fb565b91506020830135612ada816127fb565b60008060008060808587031215612c0657600080fd5b612c0f8561262d565b9350612c1d6020860161262d565b92506040850135612c2d816127fb565b9396929550929360600135925050565b600181811c90821680612c5157607f821691505b602082108103612c7157634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b600060208284031215612c9957600080fd5b815161155d81612731565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff84168152604060208201526000611e2b604083018486612ca4565b601f8211156111c357600081815260208120601f850160051c81016020861015612d125750805b601f850160051c820191505b8181101561139157828155600101612d1e565b81516001600160401b03811115612d4a57612d4a6128eb565b612d5e81612d588454612c3d565b84612ceb565b602080601f831160018114612d935760008415612d7b5750858301515b600019600386901b1c1916600185901b178555611391565b600085815260208120601f198616915b82811015612dc257888601518255948401946001909101908401612da3565b5085821015612de05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bb357610bb3612df0565b8082028115828204841417610bb357610bb3612df0565b80820180821115610bb357610bb3612df0565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6001600160a01b0386811682528516602082015260408101849052608060608201819052600090612e9d9083018486612ca4565b979650505050505050565b6000808454612eb681612c3d565b60018281168015612ece5760018114612ee357612f12565b60ff1984168752821515830287019450612f12565b8860005260208060002060005b85811015612f095781548a820152908401908201612ef0565b50505082870194505b505050508351612f26818360208801612764565b01949350505050565b600061ffff808816835280871660208401525084604083015260806060830152612e9d608083018486612ca4565b61ffff86168152608060208201526000612f7b608083018688612ca4565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b03831115612faf57612faf6128eb565b612fc383612fbd8354612c3d565b83612ceb565b6000601f841160018114612ff75760008515612fdf5750838201355b600019600387901b1c1916600186901b178355610cc9565b600083815260209020601f19861690835b828110156130285786850135825560209485019460019092019101613008565b50868210156130455760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006020828403121561306957600080fd5b81516001600160401b0381111561307f57600080fd5b8201601f8101841361309057600080fd5b805161309e61296682612931565b8181528560208385010111156130b357600080fd5b611e2b826020830160208601612764565b61ffff851681526080602082015260006130e16080830186612788565b6001600160401b03851660408401528281036060840152612e9d8185612788565b6000806040838503121561311557600080fd5b8251613120816127fb565b6020939093015192949293505050565b61ffff8716815260c06020820152600061314d60c0830188612788565b828103604084015261315f8188612788565b6001600160a01b0387811660608601528616608085015283810360a0850152905061318a8185612788565b9998505050505050505050565b600082516131a9818460208701612764565b9190910192915050565b61ffff8616815260a0602082015260006131d060a0830187612788565b6001600160401b038616604084015282810360608401526131f18186612788565b905082810360808401526132058185612788565b9897505050505050505056fea2646970667358221220284ddac49ba87582dca916738caace1ab7911dad129d493abd0bb94229fb2cb264736f6c6343000812003300000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
Deployed Bytecode
0x6080604052600436106102c85760003560e01c80638cfd8f5c11610175578063baf3292d116100dc578063d2ed5c5911610095578063e985e9c51161006f578063e985e9c51461089b578063eb8d72b7146108d6578063f2fde38b146108f6578063f5ecbdbc1461091657600080fd5b8063d2ed5c5914610851578063d40dc87014610866578063df2a5b3b1461087b57600080fd5b8063baf3292d146107cb578063c446183414610472578063c87b56dd146107eb578063cbed8b9c1461080b578063cf89fa031461082b578063d1deba1f1461083e57600080fd5b8063a035b1fe1161012e578063a035b1fe1461070e578063a0712d6814610724578063a22cb46514610737578063a6c3d16514610757578063b353aaa714610777578063b88d4fde146107ab57600080fd5b80638cfd8f5c146106435780638da5cb5b1461067b57806391b7f5ed14610699578063950c8a74146106b957806395d89b41146106d95780639f38369a146106ee57600080fd5b80633ccfd60b116102345780635b8c41e6116101ed5780636c0360eb116101c75780636c0360eb146105d957806370a08231146105ee578063715018a61461060e5780637533d7881461062357600080fd5b80635b8c41e61461054a5780636352211e1461059957806366ad5c8a146105b957600080fd5b80633ccfd60b146104885780633d8b38f61461049d5780633f1f4fa4146104bd57806342842e0e146104ea57806342d65a8d1461050a57806355f804b31461052a57600080fd5b80630df37483116102865780630df37483146103d457806310ddb137146103f457806318160ddd1461041457806323b872dd1461043857806325fd90f31461045857806332cb6b0c1461047257600080fd5b80621d3567146102cd57806301ffc9a7146102ef57806306fdde031461032457806307e0db1714610346578063081812fc14610366578063095ea7b3146103b4575b600080fd5b3480156102d957600080fd5b506102ed6102e836600461269e565b610936565b005b3480156102fb57600080fd5b5061030f61030a366004612747565b610b67565b60405190151581526020015b60405180910390f35b34801561033057600080fd5b50610339610bb9565b60405161031b91906127b4565b34801561035257600080fd5b506102ed6103613660046127c7565b610c47565b34801561037257600080fd5b5061039c6103813660046127e2565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161031b565b3480156103c057600080fd5b506102ed6103cf366004612810565b610cd0565b3480156103e057600080fd5b506102ed6103ef36600461283c565b610db2565b34801561040057600080fd5b506102ed61040f3660046127c7565b610dd1565b34801561042057600080fd5b5061042a600d5481565b60405190815260200161031b565b34801561044457600080fd5b506102ed610453366004612858565b610e29565b34801561046457600080fd5b50600e5461030f9060ff1681565b34801561047e57600080fd5b5061042a61271081565b34801561049457600080fd5b506102ed610ff0565b3480156104a957600080fd5b5061030f6104b8366004612899565b611004565b3480156104c957600080fd5b5061042a6104d83660046127c7565b60096020526000908152604090205481565b3480156104f657600080fd5b506102ed610505366004612858565b6110d0565b34801561051657600080fd5b506102ed610525366004612899565b6111c8565b34801561053657600080fd5b506102ed610545366004612996565b61124e565b34801561055657600080fd5b5061042a6105653660046129e6565b600b602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b3480156105a557600080fd5b5061039c6105b43660046127e2565b611266565b3480156105c557600080fd5b506102ed6105d436600461269e565b6112bd565b3480156105e557600080fd5b50610339611399565b3480156105fa57600080fd5b5061042a610609366004612a57565b6113a6565b34801561061a57600080fd5b506102ed611409565b34801561062f57600080fd5b5061033961063e3660046127c7565b61141b565b34801561064f57600080fd5b5061042a61065e366004612a74565b600860209081526000928352604080842090915290825290205481565b34801561068757600080fd5b506006546001600160a01b031661039c565b3480156106a557600080fd5b506102ed6106b43660046127e2565b611434565b3480156106c557600080fd5b50600a5461039c906001600160a01b031681565b3480156106e557600080fd5b50610339611441565b3480156106fa57600080fd5b506103396107093660046127c7565b61144e565b34801561071a57600080fd5b5061042a600c5481565b6102ed6107323660046127e2565b611564565b34801561074357600080fd5b506102ed610752366004612aa7565b611632565b34801561076357600080fd5b506102ed610772366004612899565b61169e565b34801561078357600080fd5b5061039c7f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67581565b3480156107b757600080fd5b506102ed6107c6366004612ae5565b611727565b3480156107d757600080fd5b506102ed6107e6366004612a57565b611808565b3480156107f757600080fd5b506103396108063660046127e2565b611864565b34801561081757600080fd5b506102ed610826366004612b57565b611898565b6102ed61083936600461283c565b61192d565b6102ed61084c36600461269e565b6119cf565b34801561085d57600080fd5b506102ed611be5565b34801561087257600080fd5b5061042a600581565b34801561088757600080fd5b506102ed610896366004612b86565b611c01565b3480156108a757600080fd5b5061030f6108b6366004612bc2565b600560209081526000928352604080842090915290825290205460ff1681565b3480156108e257600080fd5b506102ed6108f1366004612899565b611cb3565b34801561090257600080fd5b506102ed610911366004612a57565b611d0d565b34801561092257600080fd5b50610339610931366004612bf0565b611d83565b337f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b0316146109b35760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff8616600090815260076020526040812080546109d190612c3d565b80601f01602080910402602001604051908101604052809291908181526020018280546109fd90612c3d565b8015610a4a5780601f10610a1f57610100808354040283529160200191610a4a565b820191906000526020600020905b815481529060010190602001808311610a2d57829003601f168201915b50505050509050805186869050148015610a65575060008151115b8015610a8d575080516020820120604051610a839088908890612c77565b6040518091039020145b610ae85760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b60648201526084016109aa565b610b5e8787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611e3492505050565b50505050505050565b60006301ffc9a760e01b6001600160e01b031983161480610b9857506380ac58cd60e01b6001600160e01b03198316145b80610bb35750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610bc690612c3d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bf290612c3d565b8015610c3f5780601f10610c1457610100808354040283529160200191610c3f565b820191906000526020600020905b815481529060010190602001808311610c2257829003601f168201915b505050505081565b610c4f611ead565b6040516307e0db1760e01b815261ffff821660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b0316906307e0db17906024015b600060405180830381600087803b158015610cb557600080fd5b505af1158015610cc9573d6000803e3d6000fd5b5050505050565b6000818152600260205260409020546001600160a01b031633811480610d1957506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d565760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016109aa565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610dba611ead565b61ffff909116600090815260096020526040902055565b610dd9611ead565b6040516310ddb13760e01b815261ffff821660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b0316906310ddb13790602401610c9b565b6000818152600260205260409020546001600160a01b03848116911614610e7f5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016109aa565b6001600160a01b038216610ec95760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b60448201526064016109aa565b336001600160a01b0384161480610f0357506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80610f2457506000818152600460205260409020546001600160a01b031633145b610f615760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016109aa565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610ff8611ead565b6110023347611f07565b565b61ffff83166000908152600760205260408120805482919061102590612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461105190612c3d565b801561109e5780601f106110735761010080835404028352916020019161109e565b820191906000526020600020905b81548152906001019060200180831161108157829003601f168201915b5050505050905083836040516110b5929190612c77565b60405180910390208180519060200120149150509392505050565b6110db838383610e29565b6001600160a01b0382163b15806111845750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611154573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111789190612c87565b6001600160e01b031916145b6111c35760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016109aa565b505050565b6111d0611ead565b6040516342d65a8d60e01b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516906342d65a8d9061122090869086908690600401612ccd565b600060405180830381600087803b15801561123a57600080fd5b505af1158015610b5e573d6000803e3d6000fd5b611256611ead565b600f6112628282612d31565b5050565b6000818152600260205260409020546001600160a01b0316806112b85760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016109aa565b919050565b33301461131b5760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b60648201526084016109aa565b6113918686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f890181900481028201810190925287815289935091508790879081908401838280828437600092019190915250611f2392505050565b505050505050565b600f8054610bc690612c3d565b60006001600160a01b0382166113ed5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b60448201526064016109aa565b506001600160a01b031660009081526003602052604090205490565b611411611ead565b6110026000611f48565b60076020526000908152604090208054610bc690612c3d565b61143c611ead565b600c55565b60018054610bc690612c3d565b61ffff811660009081526007602052604081208054606092919061147190612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461149d90612c3d565b80156114ea5780601f106114bf576101008083540402835291602001916114ea565b820191906000526020600020905b8154815290600101906020018083116114cd57829003601f168201915b5050505050905080516000036115425760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f726400000060448201526064016109aa565b61155d6000601483516115559190612e06565b839190611f9a565b9392505050565b600e5460ff166115875760405163914edb0f60e01b815260040160405180910390fd5b3233146115a75760405163875fdad760e01b815260040160405180910390fd5b60058111156115c95760405163ed302ecd60e01b815260040160405180910390fd5b80600c546115d79190612e19565b34146115f657604051637832e81760e01b815260040160405180910390fd5b612710600d54826116079190612e30565b1115611626576040516374d9e0b960e01b815260040160405180910390fd5b61162f816120a7565b50565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6116a6611ead565b8181306040516020016116bb93929190612e43565b60408051601f1981840301815291815261ffff85166000908152600760205220906116e69082612d31565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce83838360405161171a93929190612ccd565b60405180910390a1505050565b611732858585610e29565b6001600160a01b0384163b15806117c95750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a029061177a9033908a90899089908990600401612e69565b6020604051808303816000875af1158015611799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190612c87565b6001600160e01b031916145b610cc95760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016109aa565b611810611ead565b600a80546001600160a01b0319166001600160a01b0383169081179091556040519081527f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9060200160405180910390a150565b6060600f611871836120d4565b604051602001611882929190612ea8565b6040516020818303038152906040529050919050565b6118a0611ead565b6040516332fb62e760e21b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675169063cbed8b9c906118f49088908890889088908890600401612f2f565b600060405180830381600087803b15801561190e57600080fd5b505af1158015611922573d6000803e3d6000fd5b505050505050505050565b61193681611266565b6001600160a01b0316330361195e576040516359dc379f60e01b815260040160405180910390fd5b61196781612118565b6040805133602082015290810182905260009060600160408051808303601f1901815290829052600160f01b602083015262055730602283018190529092506001916000906042016040516020818303038152906040529050611391868533600085346121e5565b61ffff86166000908152600b602052604080822090516119f29088908890612c77565b90815260408051602092819003830190206001600160401b03871660009081529252902054905080611a725760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b60648201526084016109aa565b808383604051611a83929190612c77565b604051809103902014611ae25760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b60648201526084016109aa565b61ffff87166000908152600b60205260408082209051611b059089908990612c77565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611b9d918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611f2392505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58787878785604051611bd4959493929190612f5d565b60405180910390a150505050505050565b611bed611ead565b600e805460ff19811660ff90911615179055565b611c09611ead565b60008111611c515760405162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b60448201526064016109aa565b61ffff83811660008181526008602090815260408083209487168084529482529182902085905581519283528201929092529081018290527f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac09060600161171a565b611cbb611ead565b61ffff83166000908152600760205260409020611cd9828483612f98565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab83838360405161171a93929190612ccd565b611d15611ead565b6001600160a01b038116611d7a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109aa565b61162f81611f48565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611e03573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e2b9190810190613057565b95945050505050565b600080611e975a60966366ad5c8a60e01b89898989604051602401611e5c94939291906130c4565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091523092919061238a565b9150915081611391576113918686868685612414565b6006546001600160a01b031633146110025760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109aa565b60008060008084865af16112625763b12d13eb6000526004601cfd5b60008082806020019051810190611f3a9190613102565b9150915061139182826124b1565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606081611fa881601f612e30565b1015611fe75760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016109aa565b611ff18284612e30565b845110156120355760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016109aa565b606082158015612054576040519150600082526020820160405261209e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561208d578051835260209283019201612075565b5050858452601f01601f1916604052505b50949350505050565b600d5460005b828110156120cd576120c533838060010194506124b1565b6001016120ad565b50600d5550565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a9004806120ef575050819003601f19909101908152919050565b6000818152600260205260409020546001600160a01b03168061216a5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016109aa565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b61ffff86166000908152600760205260408120805461220390612c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461222f90612c3d565b801561227c5780601f106122515761010080835404028352916020019161227c565b820191906000526020600020905b81548152906001019060200180831161225f57829003601f168201915b5050505050905080516000036122ed5760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b60648201526084016109aa565b6122f88787516125bc565b60405162c5803160e81b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675169063c580310090849061234f908b9086908c908c908c908c90600401613130565b6000604051808303818588803b15801561236857600080fd5b505af115801561237c573d6000803e3d6000fd5b505050505050505050505050565b6000606060008060008661ffff166001600160401b038111156123af576123af6128eb565b6040519080825280601f01601f1916602001820160405280156123d9576020820181803683370190505b50905060008087516020890160008d8df191503d9250868311156123fb578692505b828152826000602083013e909890975095505050505050565b8180519060200120600b60008761ffff1661ffff168152602001908152602001600020856040516124459190613197565b9081526040805191829003602090810183206001600160401b0388166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c906124a290879087908790879087906131b3565b60405180910390a15050505050565b6001600160a01b0382166124fb5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b60448201526064016109aa565b6000818152600260205260409020546001600160a01b0316156125515760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b60448201526064016109aa565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b61ffff8216600090815260096020526040812054908190036125dd57506127105b808211156111c35760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c6172676560448201526064016109aa565b803561ffff811681146112b857600080fd5b60008083601f84011261265157600080fd5b5081356001600160401b0381111561266857600080fd5b60208301915083602082850101111561268057600080fd5b9250929050565b80356001600160401b03811681146112b857600080fd5b600080600080600080608087890312156126b757600080fd5b6126c08761262d565b955060208701356001600160401b03808211156126dc57600080fd5b6126e88a838b0161263f565b90975095508591506126fc60408a01612687565b9450606089013591508082111561271257600080fd5b5061271f89828a0161263f565b979a9699509497509295939492505050565b6001600160e01b03198116811461162f57600080fd5b60006020828403121561275957600080fd5b813561155d81612731565b60005b8381101561277f578181015183820152602001612767565b50506000910152565b600081518084526127a0816020860160208601612764565b601f01601f19169290920160200192915050565b60208152600061155d6020830184612788565b6000602082840312156127d957600080fd5b61155d8261262d565b6000602082840312156127f457600080fd5b5035919050565b6001600160a01b038116811461162f57600080fd5b6000806040838503121561282357600080fd5b823561282e816127fb565b946020939093013593505050565b6000806040838503121561284f57600080fd5b61282e8361262d565b60008060006060848603121561286d57600080fd5b8335612878816127fb565b92506020840135612888816127fb565b929592945050506040919091013590565b6000806000604084860312156128ae57600080fd5b6128b78461262d565b925060208401356001600160401b038111156128d257600080fd5b6128de8682870161263f565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612929576129296128eb565b604052919050565b60006001600160401b0382111561294a5761294a6128eb565b50601f01601f191660200190565b600061296b61296684612931565b612901565b905082815283838301111561297f57600080fd5b828260208301376000602084830101529392505050565b6000602082840312156129a857600080fd5b81356001600160401b038111156129be57600080fd5b8201601f810184136129cf57600080fd5b6129de84823560208401612958565b949350505050565b6000806000606084860312156129fb57600080fd5b612a048461262d565b925060208401356001600160401b03811115612a1f57600080fd5b8401601f81018613612a3057600080fd5b612a3f86823560208401612958565b925050612a4e60408501612687565b90509250925092565b600060208284031215612a6957600080fd5b813561155d816127fb565b60008060408385031215612a8757600080fd5b612a908361262d565b9150612a9e6020840161262d565b90509250929050565b60008060408385031215612aba57600080fd5b8235612ac5816127fb565b915060208301358015158114612ada57600080fd5b809150509250929050565b600080600080600060808688031215612afd57600080fd5b8535612b08816127fb565b94506020860135612b18816127fb565b93506040860135925060608601356001600160401b03811115612b3a57600080fd5b612b468882890161263f565b969995985093965092949392505050565b600080600080600060808688031215612b6f57600080fd5b612b788661262d565b9450612b186020870161262d565b600080600060608486031215612b9b57600080fd5b612ba48461262d565b9250612bb26020850161262d565b9150604084013590509250925092565b60008060408385031215612bd557600080fd5b8235612be0816127fb565b91506020830135612ada816127fb565b60008060008060808587031215612c0657600080fd5b612c0f8561262d565b9350612c1d6020860161262d565b92506040850135612c2d816127fb565b9396929550929360600135925050565b600181811c90821680612c5157607f821691505b602082108103612c7157634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b600060208284031215612c9957600080fd5b815161155d81612731565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff84168152604060208201526000611e2b604083018486612ca4565b601f8211156111c357600081815260208120601f850160051c81016020861015612d125750805b601f850160051c820191505b8181101561139157828155600101612d1e565b81516001600160401b03811115612d4a57612d4a6128eb565b612d5e81612d588454612c3d565b84612ceb565b602080601f831160018114612d935760008415612d7b5750858301515b600019600386901b1c1916600185901b178555611391565b600085815260208120601f198616915b82811015612dc257888601518255948401946001909101908401612da3565b5085821015612de05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bb357610bb3612df0565b8082028115828204841417610bb357610bb3612df0565b80820180821115610bb357610bb3612df0565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6001600160a01b0386811682528516602082015260408101849052608060608201819052600090612e9d9083018486612ca4565b979650505050505050565b6000808454612eb681612c3d565b60018281168015612ece5760018114612ee357612f12565b60ff1984168752821515830287019450612f12565b8860005260208060002060005b85811015612f095781548a820152908401908201612ef0565b50505082870194505b505050508351612f26818360208801612764565b01949350505050565b600061ffff808816835280871660208401525084604083015260806060830152612e9d608083018486612ca4565b61ffff86168152608060208201526000612f7b608083018688612ca4565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b03831115612faf57612faf6128eb565b612fc383612fbd8354612c3d565b83612ceb565b6000601f841160018114612ff75760008515612fdf5750838201355b600019600387901b1c1916600186901b178355610cc9565b600083815260209020601f19861690835b828110156130285786850135825560209485019460019092019101613008565b50868210156130455760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006020828403121561306957600080fd5b81516001600160401b0381111561307f57600080fd5b8201601f8101841361309057600080fd5b805161309e61296682612931565b8181528560208385010111156130b357600080fd5b611e2b826020830160208601612764565b61ffff851681526080602082015260006130e16080830186612788565b6001600160401b03851660408401528281036060840152612e9d8185612788565b6000806040838503121561311557600080fd5b8251613120816127fb565b6020939093015192949293505050565b61ffff8716815260c06020820152600061314d60c0830188612788565b828103604084015261315f8188612788565b6001600160a01b0387811660608601528616608085015283810360a0850152905061318a8185612788565b9998505050505050505050565b600082516131a9818460208701612764565b9190910192915050565b61ffff8616815260a0602082015260006131d060a0830187612788565b6001600160401b038616604084015282810360608401526131f18186612788565b905082810360808401526132058185612788565b9897505050505050505056fea2646970667358221220284ddac49ba87582dca916738caace1ab7911dad129d493abd0bb94229fb2cb264736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
-----Decoded View---------------
Arg [0] : _endpoint (address): 0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
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.