More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 769 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 23227623 | 168 days ago | IN | 0 ETH | 0.00004114 | ||||
| Set Approval For... | 21891588 | 355 days ago | IN | 0 ETH | 0.00002416 | ||||
| Set Approval For... | 21891586 | 355 days ago | IN | 0 ETH | 0.00002414 | ||||
| Set Approval For... | 21527915 | 406 days ago | IN | 0 ETH | 0.00013833 | ||||
| Set Approval For... | 21468693 | 414 days ago | IN | 0 ETH | 0.00044214 | ||||
| Set Approval For... | 21468644 | 414 days ago | IN | 0 ETH | 0.00051205 | ||||
| Set Approval For... | 21102364 | 465 days ago | IN | 0 ETH | 0.0001042 | ||||
| Set Approval For... | 20610218 | 534 days ago | IN | 0 ETH | 0.00002039 | ||||
| Set Approval For... | 20574355 | 539 days ago | IN | 0 ETH | 0.00002499 | ||||
| Set Approval For... | 20547582 | 542 days ago | IN | 0 ETH | 0.00003468 | ||||
| Set Approval For... | 20159602 | 597 days ago | IN | 0 ETH | 0.00006515 | ||||
| Set Approval For... | 18910155 | 772 days ago | IN | 0 ETH | 0.00050617 | ||||
| Set Approval For... | 18910054 | 772 days ago | IN | 0 ETH | 0.00046077 | ||||
| Set Approval For... | 18630609 | 811 days ago | IN | 0 ETH | 0.00103643 | ||||
| Set Approval For... | 18335333 | 852 days ago | IN | 0 ETH | 0.00067195 | ||||
| Set Approval For... | 17705652 | 940 days ago | IN | 0 ETH | 0.00069646 | ||||
| Set Approval For... | 17694238 | 942 days ago | IN | 0 ETH | 0.00037238 | ||||
| Set Approval For... | 17106453 | 1025 days ago | IN | 0 ETH | 0.00145759 | ||||
| Set Approval For... | 17106453 | 1025 days ago | IN | 0 ETH | 0.0014557 | ||||
| Transfer From | 17055642 | 1032 days ago | IN | 0 ETH | 0.00134918 | ||||
| Set Approval For... | 17010102 | 1038 days ago | IN | 0 ETH | 0.00092124 | ||||
| Set Approval For... | 16908557 | 1053 days ago | IN | 0 ETH | 0.00040672 | ||||
| Set Approval For... | 16908557 | 1053 days ago | IN | 0 ETH | 0.00040672 | ||||
| Set Approval For... | 16908557 | 1053 days ago | IN | 0 ETH | 0.00040672 | ||||
| Set Approval For... | 16886985 | 1056 days ago | IN | 0 ETH | 0.00056458 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 16793145 | 1069 days ago | 18.03 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
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
Contract ABI
API[{"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
OVERVIEW
Based omnichain punks.Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.