Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 14 from a total of 14 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Mint | 37764145 | 158 days ago | IN | 0.0032 ETH | 0.00000041 | ||||
| Safe Transfer Fr... | 34136696 | 242 days ago | IN | 0 ETH | 0.00000063 | ||||
| Mint | 34136685 | 242 days ago | IN | 0.0032 ETH | 0.00000042 | ||||
| Mint | 33826969 | 249 days ago | IN | 0.0032 ETH | 0.0000004 | ||||
| Mint | 24996504 | 453 days ago | IN | 0.0032 ETH | 0.00001838 | ||||
| Mint | 20280825 | 562 days ago | IN | 0.0032 ETH | 0.00000038 | ||||
| Mint | 15189032 | 680 days ago | IN | 0.0032 ETH | 0.00000017 | ||||
| Mint | 15188949 | 680 days ago | IN | 0.0064 ETH | 0.00000019 | ||||
| Safe Transfer Fr... | 14930562 | 686 days ago | IN | 0 ETH | 0.00000496 | ||||
| Set Approval For... | 14930538 | 686 days ago | IN | 0 ETH | 0.00000364 | ||||
| Mint | 14930522 | 686 days ago | IN | 0.0032 ETH | 0.00000469 | ||||
| Mint | 14930515 | 686 days ago | IN | 0.0096 ETH | 0.00000502 | ||||
| Mint | 14930212 | 686 days ago | IN | 0.0032 ETH | 0.00000665 | ||||
| Mint | 14929890 | 686 days ago | IN | 0.0032 ETH | 0.00000744 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
basepaths
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
/*
██████ █████ ███████ ███████
██ ██ ██ ██ ██ ██
██████ ███████ ███████ █████
██ ██ ██ ██ ██ ██
██████ ██ ██ ███████ ███████
██████ █████ ████████ ██ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██
██████ ███████ ██ ███████ ███████
██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ███████
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {ERC721A} from "erc721a/contracts/ERC721A.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
/// @title basepaths - an ERC721A smart contract
/// @author parker thompson
/// @notice nfts with art fully generated on-chain
contract basepaths is ERC721A, Ownable {
/// @notice deploys the basepaths contract
constructor() ERC721A("basepaths", "BP") Ownable(msg.sender) {}
/// @notice price to mint a token in wei
/// @dev 3200000000000000 wei is 0.0032 eth
uint256 public constant _mintPrice = 3200000000000000;
/// @notice number of tokens that can be minted before the timer starts
uint256 private constant _tokensBeforeTimer = 640;
/// @notice timestamp when minting closes
/// @return mintCloseTimestamp
/// @dev will be updated if tokens minted is greater than _tokensBeforeTimer
uint256 public _mintCloseTimestamp = 0;
/// @notice number of seconds to add to mintCloseTimestamp
/// @dev 57600 seconds == 16 hours
uint256 private constant _mintSecondsTimer = 57600;
/// @notice mint basepaths nfts
/// @param quantity of tokens to mint (up to 8)
function mint(uint8 quantity) public payable {
require(quantity <= 8, "can only mint 8 at a time");
require(msg.value >= quantity * _mintPrice, "not enough eth");
if (totalSupply() < _tokensBeforeTimer) {
if (totalSupply() + quantity >= _tokensBeforeTimer) {
setMintCloseTimestamp();
}
_mint(msg.sender, quantity);
} else {
require(block.timestamp <= _mintCloseTimestamp, "mint closed");
_mint(msg.sender, quantity);
}
}
/// @notice set the final mint close timestamp
/// @dev ensures the mint close timestamp can only be set once
function setMintCloseTimestamp() internal {
if (_mintCloseTimestamp == 0) {
_mintCloseTimestamp = block.timestamp + _mintSecondsTimer;
}
}
/// @notice get the base64 encoded token URI
/// @param tokenId of the token
/// @return base64 encoded token URI
function tokenURI(
uint256 tokenId
) public view virtual override(ERC721A) returns (string memory) {
return getTokenURI(tokenId);
}
/// @notice get the svg art for a token
/// @param tokenId of the token
/// @return svg art
function getSvg(uint256 tokenId) public pure returns (string memory) {
return renderSvg(tokenId);
}
/// @notice determine if the colors should be grayscale
/// @param tokenId for which to determine if the colors should be grayscale
/// @return isGrayscale
function isGrayscale(uint256 tokenId) internal pure returns (bool) {
return random(tokenId, 0, 100) > 97;
}
/// @notice get basepath hue
/// @param tokenId being rendered
/// @return basepathHue
function basepathHue(uint256 tokenId) internal pure returns (uint256) {
return random(tokenId, 0, 360);
}
/// @notice get base lightness
/// @param tokenId being rendered
/// @return baseLightness
function baseLightness(uint256 tokenId) internal pure returns (uint256) {
uint8[3] memory variations = [16, 24, 32];
return variations[random(tokenId * 4, 0, 2)];
}
/// @notice get token background hue
/// @param tokenId being rendered
/// @return backgroundHue
function backgroundHue(uint256 tokenId) internal pure returns (uint256) {
return
random(tokenId, 0, 1) == 0
? basepathHue(tokenId)
: (basepathHue(tokenId) + 180) % 360;
}
/// @notice get token background lightness
/// @param tokenId being rendered
/// @return backgroundLightness
function backgroundLightness(
uint256 tokenId
) internal pure returns (uint256) {
if (isGrayscale(tokenId)) {
return random(tokenId, 0, 10);
} else if (backgroundHue(tokenId) == basepathHue(tokenId)) {
return
random(tokenId, 0, 1) == 0
? random(tokenId, 80, 100)
: random(tokenId, 0, 20);
} else {
return random(tokenId, 40, 60);
}
}
/// @notice get a background color based on the token ID
/// @param tokenId being rendered
/// @return backgroundColor
function backgroundColor(
uint256 tokenId
) internal pure returns (string memory) {
return
string(
abi.encodePacked(
"hsl(",
uint2string(backgroundHue(tokenId)),
"deg ",
isGrayscale(tokenId) ? "0% " : "100% ",
uint2string(backgroundLightness(tokenId)),
"%)"
)
);
}
/// @notice get the stroke width
/// @param tokenId being rendered
/// @return strokeWidth
function strokeWidth(
uint256 tokenId
) internal pure returns (string memory) {
return random(tokenId * 2, 0, 100) > 99 ? "0.5" : "1";
}
/// @notice get the line join rule to use
/// @param tokenId being rendered
/// @return cornerShape
function cornerShape(
uint256 tokenId
) internal pure returns (string memory) {
return random(tokenId * 3, 0, 100) > 99 ? "round" : "square";
}
/// @notice get baseline path
/// @param tokenId being rendered
/// @return baselinePath
function baselinePath(
uint256 tokenId
) internal pure returns (string memory) {
uint256 verticalStartingPoint = random(tokenId, 14, 20);
uint8[5] memory horizontalPathOptions = [8, 16, 16, 16, 16];
uint8 horizontalPaths = horizontalPathOptions[
random(tokenId * 5, 0, 4)
];
string memory pathData = "";
uint256 currentV = verticalStartingPoint;
for (uint256 i = 0; i < horizontalPaths - 1; i++) {
uint256 v;
bool isNegative;
if (currentV >= 28) {
v = random(tokenId + i * 2, 1, 3);
isNegative = true;
} else if (currentV <= 8) {
v = random(tokenId + i * 3, 1, 3);
isNegative = false;
} else {
v = random(tokenId + i, 0, 3);
isNegative = random(tokenId * i, 0, 1) == 0;
}
pathData = string(
abi.encodePacked(
pathData,
" h",
uint2string(32 / horizontalPaths),
" v",
isNegative ? "-" : "",
uint2string(v)
)
);
isNegative ? currentV -= v : currentV += v;
}
return
string(
abi.encodePacked(
'<path id="basepath" d="M0 ',
uint2string(verticalStartingPoint),
pathData,
' H32"/>'
)
);
}
/// @notice get the number of additional paths
/// @param tokenId being rendered
/// @return additionalPathsCount
function additionalPathsCount(
uint256 tokenId
) internal pure returns (uint256) {
uint8[8] memory pathOptions = [1, 2, 2, 2, 3, 3, 3, 4];
return pathOptions[random(tokenId, 0, 7)];
}
/// @notice get the contrast for additional paths
/// @param tokenId being rendered
/// @return pathContrast
/// @dev higher contrast will result in more vibrant colors
function pathContrast(uint256 tokenId) internal pure returns (uint256) {
uint8[4] memory variations = [5, 10, 15, 20];
return variations[random(tokenId, 0, 3)];
}
/// @notice get additional paths from the baseline
/// @param tokenId being rendered
/// @return paths
function additionalPaths(
uint256 tokenId
) internal pure returns (string memory paths) {
uint256 currentLightness = baseLightness(tokenId) +
pathContrast(tokenId);
(tokenId);
for (uint256 i = 1; i < additionalPathsCount(tokenId) + 1; i++) {
paths = string(
abi.encodePacked(
paths,
'<use href="#basepath" stroke="hsl(',
uint2string(basepathHue(tokenId)),
"deg ",
isGrayscale(tokenId) ? "0% " : "100% ",
uint2string(currentLightness),
'%)" ',
'transform="translate(0 -',
uint2string(i),
')"/>'
)
);
currentLightness += pathContrast(tokenId);
}
}
/// @notice render svg code for a given token
/// @param tokenId of the token to render
/// @return svg code
function renderSvg(uint256 tokenId) internal pure returns (string memory) {
return
string(
abi.encodePacked(
'<svg width="1200" height="1200" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges"><rect width="32" height="32" fill="',
backgroundColor(tokenId),
'"/>',
'<g stroke-linecap="none" stroke-linejoin="',
cornerShape(tokenId),
'" stroke-width="',
strokeWidth(tokenId),
'"><g stroke="hsl(',
uint2string(basepathHue(tokenId)),
"deg ",
isGrayscale(tokenId) ? "0% " : "100% ",
uint2string(baseLightness(tokenId)),
'%)">',
baselinePath(tokenId),
"</g>",
additionalPaths(tokenId),
"</g>",
"</svg>"
)
);
}
/// @notice generate metadata for a given token
/// @param tokenId of the given token
/// @return metadata as a json string
function _generateMetadata(
uint256 tokenId
) internal pure returns (string memory) {
return
string(
abi.encodePacked(
'{"name": "basepaths #',
uint2string(tokenId),
'", "description": "based generative on-chain art", "attributes": [',
_generateAttributes(tokenId),
'], "image": "data:image/svg+xml;base64,',
Base64.encode(bytes(renderSvg(tokenId))),
'"}'
)
);
}
/// @notice generate attributes for a given token
/// @param tokenId of the given token
/// @return attributes for a given token
function _generateAttributes(
uint256 tokenId
) internal pure returns (bytes memory) {
return
abi.encodePacked(
_attribute(
"saturation",
isGrayscale(tokenId) ? "grayscale" : "colorful",
true,
true
),
_attribute(
"path hue",
uint2string(basepathHue(tokenId)),
false,
true
),
_attribute(
"background",
backgroundHue(tokenId) == basepathHue(tokenId) ||
isGrayscale(tokenId)
? "monochromatic"
: "complimentary",
true,
true
),
_attribute("corner shape", cornerShape(tokenId), true, true),
_attribute("path width", strokeWidth(tokenId), true, true),
_attribute(
"path count",
uint2string(additionalPathsCount(tokenId) + 1),
true,
true
),
_attribute(
"path starting lightness",
uint2string(baseLightness(tokenId)),
true,
true
),
_attribute(
"path contrast",
pathContrast(tokenId) == 5
? "low"
: pathContrast(tokenId) == 10
? "medium"
: pathContrast(tokenId) == 15
? "high"
: "extra high",
true,
false
)
);
}
/// @notice generate a formatted attribute
/// @param attType type of attribute
/// @param attValue value of attribute
/// @param trailingComma whether or not to include a trailing comma
function _attribute(
string memory attType,
string memory attValue,
bool includeQuotes,
bool trailingComma
) internal pure returns (string memory) {
return
string(
abi.encodePacked(
"{",
'"trait_type": "',
attType,
'", '
'"value": ',
includeQuotes ? '"' : "",
attValue,
includeQuotes ? '"' : "",
"}",
trailingComma ? "," : ""
)
);
}
/// @notice get the base64 encoded token URI
/// @param tokenId of the token being rendered
/// @return base64 encoded token URI
function getTokenURI(
uint256 tokenId
) internal pure returns (string memory) {
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(bytes(_generateMetadata(tokenId)))
)
);
}
/// @notice get a pseudo random number
/// @param input to use as a randomness seed
/// @param min value that can be returned
/// @param max value that can be returned
/// @return number that is randomized based on the params
/// @dev the same input will always return the same output
/// @dev min and max are inclusive values and can be returned
/// @dev adding "art+tech" to the input so results are different from testnets
function random(
uint256 input,
uint256 min,
uint256 max
) internal pure returns (uint256) {
uint256 randRange = max - min + 1;
return
min +
(uint256(keccak256(abi.encodePacked(input, "art+tech"))) %
randRange);
}
/// @notice convert a number to a string
/// @param number number to convert
/// @return result string from the converted number
function uint2string(
uint256 number
) internal pure returns (string memory result) {
if (number == 0) {
return "0";
}
uint256 x = number;
uint256 length;
while (x != 0) {
length++;
x /= 10;
}
bytes memory conversion = new bytes(length);
uint256 y = length;
while (number != 0) {
y = y - 1;
uint8 temp = (48 + uint8(number - (number / 10) * 10));
bytes1 b1 = bytes1(temp);
conversion[y] = b1;
number /= 10;
}
return string(conversion);
}
/// @notice starts the token ID at 1 instead of 0
function _startTokenId() internal view virtual override returns (uint256) {
return 1;
}
/// @notice withdraw contract funds
function withdraw() external onlyOwner {
uint256 bal = address(this).balance;
require(bal != 0, "no eth");
payable(msg.sender).transfer(bal);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 0x20)
let dataPtr := data
let endPtr := add(data, mload(data))
// In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
// set it to zero to make sure no dirty bytes are read in that section.
let afterPtr := add(endPtr, 0x20)
let afterCache := mload(afterPtr)
mstore(afterPtr, 0x00)
// Run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 byte (24 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F to bitmask the least significant 6 bits.
// Use this as an index into the lookup table, mload an entire word
// so the desired character is in the least significant byte, and
// mstore8 this least significant byte into the result and continue.
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// Reset the value that was cached
mstore(afterPtr, afterCache)
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721A.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* The `_sequentialUpTo()` function can be overriden to enable spot mints
* (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is IERC721A {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 private _currentIndex;
// The number of tokens burned.
uint256 private _burnCounter;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) private _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) private _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// The amount of tokens minted above `_sequentialUpTo()`.
// We call these spot mints (i.e. non-sequential mints).
uint256 private _spotMinted;
// =============================================================
// CONSTRUCTOR
// =============================================================
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector);
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID for sequential mints.
*
* Override this function to change the starting token ID for sequential mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the maximum token ID (inclusive) for sequential mints.
*
* Override this function to return a value less than 2**256 - 1,
* but greater than `_startTokenId()`, to enable spot (non-sequential) mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _sequentialUpTo() internal view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256 result) {
// Counter underflow is impossible as `_burnCounter` cannot be incremented
// more than `_currentIndex + _spotMinted - _startTokenId()` times.
unchecked {
// With spot minting, the intermediate `result` can be temporarily negative,
// and the computation must be unchecked.
result = _currentIndex - _burnCounter - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256 result) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
result = _currentIndex - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
/**
* @dev Returns the total number of tokens that are spot-minted.
*/
function _totalSpotMinted() internal view virtual returns (uint256) {
return _spotMinted;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
/**
* @dev Returns whether the ownership slot at `index` is initialized.
* An uninitialized slot does not necessarily mean that the slot has no owner.
*/
function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {
return _packedOwnerships[index] != 0;
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* @dev Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
if (_startTokenId() <= tokenId) {
packed = _packedOwnerships[tokenId];
if (tokenId > _sequentialUpTo()) {
if (_packedOwnershipExists(packed)) return packed;
_revert(OwnerQueryForNonexistentToken.selector);
}
// If the data at the starting slot does not exist, start the scan.
if (packed == 0) {
if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector);
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `tokenId` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
for (;;) {
unchecked {
packed = _packedOwnerships[--tokenId];
}
if (packed == 0) continue;
if (packed & _BITMASK_BURNED == 0) return packed;
// Otherwise, the token is burned, and we must revert.
// This handles the case of batch burned tokens, where only the burned bit
// of the starting slot is set, and remaining slots are left uninitialized.
_revert(OwnerQueryForNonexistentToken.selector);
}
}
// Otherwise, the data exists and we can skip the scan.
// This is possible because we have already achieved the target condition.
// This saves 2143 gas on transfers of initialized tokens.
// If the token is not burned, return `packed`. Otherwise, revert.
if (packed & _BITMASK_BURNED == 0) return packed;
}
_revert(OwnerQueryForNonexistentToken.selector);
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
*/
function approve(address to, uint256 tokenId) public payable virtual override {
_approve(to, tokenId, true);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);
return _tokenApprovals[tokenId].value;
}
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool result) {
if (_startTokenId() <= tokenId) {
if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]);
if (tokenId < _currentIndex) {
uint256 packed;
while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId;
result = packed & _BITMASK_BURNED == 0;
}
}
}
/**
* @dev Returns whether `packed` represents a token that exists.
*/
function _packedOwnershipExists(uint256 packed) private pure returns (bool result) {
assembly {
// The following is equivalent to `owner != address(0) && burned == false`.
// Symbolically tested.
result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED))
}
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
// Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.
from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));
if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--_packedAddressData[from]; // Updates: `balance -= 1`.
++_packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
from, // `from`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
if (toMasked == 0) _revert(TransferToZeroAddress.selector);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
assembly {
revert(add(32, reason), mload(reason))
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) _revert(MintZeroQuantity.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
uint256 end = startTokenId + quantity;
uint256 tokenId = startTokenId;
if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
do {
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
// The `!=` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
} while (++tokenId != end);
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) _revert(MintToZeroAddress.selector);
if (quantity == 0) _revert(MintZeroQuantity.selector);
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
} while (index < end);
// This prevents reentrancy to `_safeMint`.
// It does not prevent reentrancy to `_safeMintSpot`.
if (_currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
/**
* @dev Mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* Emits a {Transfer} event for each mint.
*/
function _mintSpot(address to, uint256 tokenId) internal virtual {
if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector);
uint256 prevOwnershipPacked = _packedOwnerships[tokenId];
if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector);
_beforeTokenTransfers(address(0), to, tokenId, 1);
// Overflows are incredibly unrealistic.
// The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1.
// `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `true` (as `quantity == 1`).
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked)
);
// Updates:
// - `balance += 1`.
// - `numberMinted += 1`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1;
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
++_spotMinted;
}
_afterTokenTransfers(address(0), to, tokenId, 1);
}
/**
* @dev Safely mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* See {_mintSpot}.
*
* Emits a {Transfer} event.
*/
function _safeMintSpot(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mintSpot(to, tokenId);
unchecked {
if (to.code.length != 0) {
uint256 currentSpotMinted = _spotMinted;
if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
// This prevents reentrancy to `_safeMintSpot`.
// It does not prevent reentrancy to `_safeMint`.
if (_spotMinted != currentSpotMinted) revert();
}
}
}
/**
* @dev Equivalent to `_safeMintSpot(to, tokenId, '')`.
*/
function _safeMintSpot(address to, uint256 tokenId) internal virtual {
_safeMintSpot(to, tokenId, '');
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_approve(to, tokenId, false)`.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_approve(to, tokenId, false);
}
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
bool approvalCheck
) internal virtual {
address owner = ownerOf(tokenId);
if (approvalCheck && _msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
_revert(ApprovalCallerNotOwnerNorApproved.selector);
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times.
unchecked {
_burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
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. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := 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)
// prettier-ignore
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 For more efficient reverts.
*/
function _revert(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721A {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
/**
* `_sequentialUpTo()` must be greater than `_startTokenId()`.
*/
error SequentialUpToTooSmall();
/**
* The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`.
*/
error SequentialMintExceedsLimit();
/**
* Spot minting requires a `tokenId` greater than `_sequentialUpTo()`.
*/
error SpotMintTokenIdTooSmall();
/**
* Cannot mint over a token that already exists.
*/
error TokenAlreadyExists();
/**
* The feature is not compatible with spot mints.
*/
error NotCompatibleWithSpotMints();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}{
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","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":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"_mintCloseTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"quantity","type":"uint8"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","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":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040525f600a55348015610013575f80fd5b50336040518060400160405280600981526020017f62617365706174687300000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f4250000000000000000000000000000000000000000000000000000000000000815250816002908161009091906104a8565b5080600390816100a091906104a8565b506100af61017460201b60201c565b5f819055506100c261017460201b60201c565b6100d061017c60201b60201c565b10156100ed576100ec63fed8210f60e01b6101a360201b60201c565b5b50505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361015f575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161015691906105b6565b60405180910390fd5b61016e816101ab60201b60201c565b506105cf565b5f6001905090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905090565b805f5260045ffd5b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806102e957607f821691505b6020821081036102fc576102fb6102a5565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f6008830261035e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610323565b6103688683610323565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6103ac6103a76103a284610380565b610389565b610380565b9050919050565b5f819050919050565b6103c583610392565b6103d96103d1826103b3565b84845461032f565b825550505050565b5f90565b6103ed6103e1565b6103f88184846103bc565b505050565b5b8181101561041b576104105f826103e5565b6001810190506103fe565b5050565b601f8211156104605761043181610302565b61043a84610314565b81016020851015610449578190505b61045d61045585610314565b8301826103fd565b50505b505050565b5f82821c905092915050565b5f6104805f1984600802610465565b1980831691505092915050565b5f6104988383610471565b9150826002028217905092915050565b6104b18261026e565b67ffffffffffffffff8111156104ca576104c9610278565b5b6104d482546102d2565b6104df82828561041f565b5f60209050601f831160018114610510575f84156104fe578287015190505b610508858261048d565b86555061056f565b601f19841661051e86610302565b5f5b8281101561054557848901518255600182019150602085019450602081019050610520565b86831015610562578489015161055e601f891682610471565b8355505b6001600288020188555050505b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6105a082610577565b9050919050565b6105b081610596565b82525050565b5f6020820190506105c95f8301846105a7565b92915050565b614415806105dc5f395ff3fe608060405260043610610134575f3560e01c80636ecd2306116100aa578063a22cb4651161006e578063a22cb465146103c0578063b0dc78fa146103e8578063b88d4fde14610424578063c87b56dd14610440578063e985e9c51461047c578063f2fde38b146104b857610134565b80636ecd2306146102fe57806370a082311461031a578063715018a6146103565780638da5cb5b1461036c57806395d89b411461039657610134565b806318160ddd116100fc57806318160ddd1461022057806323b872dd1461024a5780633ccfd60b1461026657806342842e0e1461027c5780636352211e1461029857806364632795146102d457610134565b806301ffc9a7146101385780630387da421461017457806306fdde031461019e578063081812fc146101c8578063095ea7b314610204575b5f80fd5b348015610143575f80fd5b5061015e60048036038101906101599190612a99565b6104e0565b60405161016b9190612ade565b60405180910390f35b34801561017f575f80fd5b50610188610571565b6040516101959190612b0f565b60405180910390f35b3480156101a9575f80fd5b506101b261057c565b6040516101bf9190612b98565b60405180910390f35b3480156101d3575f80fd5b506101ee60048036038101906101e99190612be2565b61060c565b6040516101fb9190612c4c565b60405180910390f35b61021e60048036038101906102199190612c8f565b610665565b005b34801561022b575f80fd5b50610234610675565b6040516102419190612b0f565b60405180910390f35b610264600480360381019061025f9190612ccd565b6106c0565b005b348015610271575f80fd5b5061027a61096b565b005b61029660048036038101906102919190612ccd565b610a00565b005b3480156102a3575f80fd5b506102be60048036038101906102b99190612be2565b610a1f565b6040516102cb9190612c4c565b60405180910390f35b3480156102df575f80fd5b506102e8610a30565b6040516102f59190612b0f565b60405180910390f35b61031860048036038101906103139190612d53565b610a36565b005b348015610325575f80fd5b50610340600480360381019061033b9190612d7e565b610b75565b60405161034d9190612b0f565b60405180910390f35b348015610361575f80fd5b5061036a610c09565b005b348015610377575f80fd5b50610380610c1c565b60405161038d9190612c4c565b60405180910390f35b3480156103a1575f80fd5b506103aa610c44565b6040516103b79190612b98565b60405180910390f35b3480156103cb575f80fd5b506103e660048036038101906103e19190612dd3565b610cd4565b005b3480156103f3575f80fd5b5061040e60048036038101906104099190612be2565b610dda565b60405161041b9190612b98565b60405180910390f35b61043e60048036038101906104399190612f3d565b610dec565b005b34801561044b575f80fd5b5061046660048036038101906104619190612be2565b610e3d565b6040516104739190612b98565b60405180910390f35b348015610487575f80fd5b506104a2600480360381019061049d9190612fbd565b610e4f565b6040516104af9190612ade565b60405180910390f35b3480156104c3575f80fd5b506104de60048036038101906104d99190612d7e565b610edd565b005b5f6301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061053a57506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061056a5750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b660b5e620f48000081565b60606002805461058b90613028565b80601f01602080910402602001604051908101604052809291908181526020018280546105b790613028565b80156106025780601f106105d957610100808354040283529160200191610602565b820191905f5260205f20905b8154815290600101906020018083116105e557829003601f168201915b5050505050905090565b5f61061682610f61565b61062b5761062a63cf4700e460e01b611004565b5b60065f8381526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6106718282600161100c565b5050565b5f61067e611136565b6001545f54030390507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6106b061113e565b146106bd57600854810190505b90565b5f6106ca82611165565b905073ffffffffffffffffffffffffffffffffffffffff8473ffffffffffffffffffffffffffffffffffffffff161693508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461073f5761073e63a114810060e01b611004565b5b5f8061074a84611274565b91509150610760818761075b611297565b61129e565b61078b5761077586610770611297565b610e4f565b61078a576107896359c896be60e01b611004565b5b5b61079886868660016112e1565b80156107a2575f82555b60055f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8154600190039190508190555060055f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f81546001019190508190555061086a856108468888876112e7565b7c02000000000000000000000000000000000000000000000000000000001761130e565b60045f8681526020019081526020015f20819055505f7c02000000000000000000000000000000000000000000000000000000008416036108e6575f6001850190505f60045f8381526020019081526020015f2054036108e4575f5481146108e3578360045f8381526020019081526020015f20819055505b5b505b5f73ffffffffffffffffffffffffffffffffffffffff8673ffffffffffffffffffffffffffffffffffffffff161690508481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a45f81036109555761095463ea553b3460e01b611004565b5b6109628787876001611338565b50505050505050565b61097361133e565b5f4790505f81036109b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109b0906130a2565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156109fc573d5f803e3d5ffd5b5050565b610a1a83838360405180602001604052805f815250610dec565b505050565b5f610a2982611165565b9050919050565b600a5481565b60088160ff161115610a7d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a749061310a565b60405180910390fd5b660b5e620f4800008160ff16610a939190613155565b341015610ad5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acc906131e0565b60405180910390fd5b610280610ae0610675565b1015610b1f576102808160ff16610af5610675565b610aff91906131fe565b10610b0d57610b0c6113c5565b5b610b1a338260ff166113e5565b610b72565b600a54421115610b64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5b9061327b565b60405180910390fd5b610b71338260ff166113e5565b5b50565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bba57610bb9638f4eb60460e01b611004565b5b67ffffffffffffffff60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054169050919050565b610c1161133e565b610c1a5f611559565b565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060038054610c5390613028565b80601f0160208091040260200160405190810160405280929190818152602001828054610c7f90613028565b8015610cca5780601f10610ca157610100808354040283529160200191610cca565b820191905f5260205f20905b815481529060010190602001808311610cad57829003601f168201915b5050505050905090565b8060075f610ce0611297565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16610d89611297565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dce9190612ade565b60405180910390a35050565b6060610de58261161c565b9050919050565b610df78484846106c0565b5f8373ffffffffffffffffffffffffffffffffffffffff163b14610e3757610e2184848484611719565b610e3657610e3563d1a57ed660e01b611004565b5b5b50505050565b6060610e4882611843565b9050919050565b5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b610ee561133e565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f55575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610f4c9190612c4c565b60405180910390fd5b610f5e81611559565b50565b5f81610f6b611136565b11610ffe57610f7861113e565b821115610fa057610f9960045f8481526020019081526020015f205461187c565b9050610fff565b5f54821015610ffd575f5b5f60045f8581526020019081526020015f205491508103610fd75782610fd090613299565b9250610fab565b5f7c01000000000000000000000000000000000000000000000000000000008216149150505b5b5b919050565b805f5260045ffd5b5f61101683610a1f565b905081801561105857508073ffffffffffffffffffffffffffffffffffffffff1661103f611297565b73ffffffffffffffffffffffffffffffffffffffff1614155b156110845761106e81611069611297565b610e4f565b6110835761108263cfb3b94260e01b611004565b5b5b8360065f8581526020019081526020015f205f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550828473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a450505050565b5f6001905090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905090565b5f8161116f611136565b1161125e5760045f8381526020019081526020015f2054905061119061113e565b8211156111b5576111a08161187c565b61126f576111b463df2d9b4260e01b611004565b5b5f8103611236575f5482106111d5576111d463df2d9b4260e01b611004565b5b5b60045f836001900393508381526020019081526020015f205490505f810315611231575f7c01000000000000000000000000000000000000000000000000000000008216031561126f5761123063df2d9b4260e01b611004565b5b6111d6565b5f7c01000000000000000000000000000000000000000000000000000000008216031561126f575b61126e63df2d9b4260e01b611004565b5b919050565b5f805f60065f8581526020019081526020015f2090508092508254915050915091565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b50505050565b5f8060e883901c905060e86112fd8686846118bc565b62ffffff16901b9150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b6113466118c4565b73ffffffffffffffffffffffffffffffffffffffff16611364610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146113c3576113876118c4565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113ba9190612c4c565b60405180910390fd5b565b5f600a54036113e35761e100426113dc91906131fe565b600a819055505b565b5f805490505f82036114025761140163b562e8dd60e01b611004565b5b61140e5f8483856112e1565b61142c8361141d5f865f6112e7565b611426856118cb565b1761130e565b60045f8381526020019081526020015f2081905550600160406001901b17820260055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505f73ffffffffffffffffffffffffffffffffffffffff8473ffffffffffffffffffffffffffffffffffffffff161690505f81036114dd576114dc632e07630060e01b611004565b5b5f83830190505f8390506114ef61113e565b60018303111561150a576115096381647e3a60e01b611004565b5b5b80835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a481816001019150810361150b57815f819055505050506115545f848385611338565b505050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060611627826118da565b611630836119a5565b61163984611a3f565b61164a61164586611ad9565b611aee565b61165386611c6c565b611692576040518060400160405280600581526020017f31303025200000000000000000000000000000000000000000000000000000008152506116c9565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b6116da6116d588611c83565b611aee565b6116e388611ce8565b6116ec89611f44565b604051602001611703989796959493929190613678565b6040516020818303038152906040529050919050565b5f8373ffffffffffffffffffffffffffffffffffffffff1663150b7a0261173e611297565b8786866040518563ffffffff1660e01b815260040161176094939291906137a9565b6020604051808303815f875af192505050801561179b57506040513d601f19601f820116820180604052508101906117989190613807565b60015b6117f0573d805f81146117c9576040519150601f19603f3d011682016040523d82523d5f602084013e6117ce565b606091505b505f8151036117e8576117e763d1a57ed660e01b611004565b5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b606061185661185183612079565b6120c6565b604051602001611866919061387c565b6040516020818303038152906040529050919050565b5f7c0100000000000000000000000000000000000000000000000000000000821673ffffffffffffffffffffffffffffffffffffffff8316119050919050565b5f9392505050565b5f33905090565b5f6001821460e11b9050919050565b60606118ed6118e883612233565b611aee565b6118f683611c6c565b611935576040518060400160405280600581526020017f313030252000000000000000000000000000000000000000000000000000000081525061196c565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b61197d6119788561227e565b611aee565b60405160200161198f93929190613931565b6040516020818303038152906040529050919050565b606060636119c16003846119b99190613155565b5f6064612304565b11611a01576040518060400160405280600681526020017f7371756172650000000000000000000000000000000000000000000000000000815250611a38565b6040518060400160405280600581526020017f726f756e640000000000000000000000000000000000000000000000000000008152505b9050919050565b60606063611a5b600284611a539190613155565b5f6064612304565b11611a9b576040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250611ad2565b6040518060400160405280600381526020017f302e3500000000000000000000000000000000000000000000000000000000008152505b9050919050565b5f611ae7825f610168612304565b9050919050565b60605f8203611b34576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611c67565b5f8290505f5b5f8214611b63578080611b4c90613982565b915050600a82611b5c91906139f6565b9150611b3a565b5f8167ffffffffffffffff811115611b7e57611b7d612e19565b5b6040519080825280601f01601f191660200182016040528015611bb05781602001600182028036833780820191505090505b5090505f8290505b5f8614611c5f57600181611bcc9190613a26565b90505f600a8088611bdd91906139f6565b611be79190613155565b87611bf29190613a26565b6030611bfe9190613a59565b90505f8160f81b905080848481518110611c1b57611c1a613a8d565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600a88611c5691906139f6565b97505050611bb8565b819450505050505b919050565b5f6061611c7b835f6064612304565b119050919050565b5f806040518060600160405280601060ff168152602001601860ff168152602001602060ff16815250905080611cc7600485611cbf9190613155565b5f6002612304565b60038110611cd857611cd7613a8d565b5b602002015160ff16915050919050565b60605f611cf883600e6014612304565b90505f6040518060a00160405280600860ff168152602001601060ff168152602001601060ff168152602001601060ff168152602001601060ff1681525090505f81611d52600587611d4a9190613155565b5f6004612304565b60058110611d6357611d62613a8d565b5b602002015190505f60405180602001604052805f81525090505f8490505f5b600184611d8f9190613aba565b60ff16811015611f0d575f80601c8410611dd257611dc7600284611db39190613155565b8b611dbe91906131fe565b60016003612304565b915060019050611e3e565b60088411611e0857611dfe600384611dea9190613155565b8b611df591906131fe565b60016003612304565b91505f9050611e3d565b611e1f838b611e1791906131fe565b5f6003612304565b91505f611e39848c611e319190613155565b5f6001612304565b1490505b5b84611e57876020611e4f9190613aee565b60ff16611aee565b82611e705760405180602001604052805f815250611ea7565b6040518060400160405280600181526020017f2d000000000000000000000000000000000000000000000000000000000000008152505b611eb085611aee565b604051602001611ec39493929190613bb2565b604051602081830303815290604052945080611eed578184611ee591906131fe565b935083611efd565b8184611ef99190613a26565b9350835b5050508080600101915050611d82565b50611f1785611aee565b82604051602001611f29929190613c99565b60405160208183030381529060405295505050505050919050565b60605f611f5083612369565b611f5984611c83565b611f6391906131fe565b90505f600190505b6001611f76856123cc565b611f8091906131fe565b8110156120725782611f99611f9486611ad9565b611aee565b611fa286611c6c565b611fe1576040518060400160405280600581526020017f3130302520000000000000000000000000000000000000000000000000000000815250612018565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b61202185611aee565b61202a85611aee565b60405160200161203e959493929190613e20565b604051602081830303815290604052925061205884612369565b8261206391906131fe565b91508080600101915050611f6b565b5050919050565b606061208482611aee565b61208d83612458565b61209e6120998561161c565b6120c6565b6040516020016120b093929190614075565b6040516020818303038152906040529050919050565b60605f8251036120e65760405180602001604052805f815250905061222e565b5f6040518060600160405280604081526020016143a06040913990505f60036002855161211391906131fe565b61211d91906139f6565b60046121299190613155565b67ffffffffffffffff81111561214257612141612e19565b5b6040519080825280601f01601f1916602001820160405280156121745781602001600182028036833780820191505090505b509050600182016020820185865187016020810180515f82525b828410156121e9576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f811687015186536001860195505061218e565b80825260038a510660018114612206576002811461221957612221565b603d6001870353603d6002870353612221565b603d60018703535b5050505050505080925050505b919050565b5f80612241835f6001612304565b1461226d5761016860b461225484611ad9565b61225e91906131fe565b61226891906140d1565b612277565b61227682611ad9565b5b9050919050565b5f61228882611c6c565b156122a057612299825f600a612304565b90506122ff565b6122a982611ad9565b6122b283612233565b036122ef575f6122c4835f6001612304565b146122da576122d5825f6014612304565b6122e8565b6122e78260506064612304565b5b90506122ff565b6122fc826028603c612304565b90505b919050565b5f80600184846123149190613a26565b61231e91906131fe565b90508085604051602001612332919061416b565b604051602081830303815290604052805190602001205f1c61235491906140d1565b8461235f91906131fe565b9150509392505050565b5f806040518060800160405280600560ff168152602001600a60ff168152602001600f60ff168152602001601460ff168152509050806123ab845f6003612304565b600481106123bc576123bb613a8d565b5b602002015160ff16915050919050565b5f80604051806101000160405280600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff16815250905080612437845f6007612304565b6008811061244857612447613a8d565b5b602002015160ff16915050919050565b606061251a6040518060400160405280600a81526020017f73617475726174696f6e0000000000000000000000000000000000000000000081525061249c84611c6c565b6124db576040518060400160405280600881526020017f636f6c6f7266756c000000000000000000000000000000000000000000000000815250612512565b6040518060400160405280600981526020017f677261797363616c6500000000000000000000000000000000000000000000008152505b600180612912565b61256c6040518060400160405280600881526020017f706174682068756500000000000000000000000000000000000000000000000081525061256461255f86611ad9565b611aee565b5f6001612912565b6126466040518060400160405280600a81526020017f6261636b67726f756e64000000000000000000000000000000000000000000008152506125ae86611ad9565b6125b787612233565b14806125c857506125c786611c6c565b5b612607576040518060400160405280600d81526020017f636f6d706c696d656e746172790000000000000000000000000000000000000081525061263e565b6040518060400160405280600d81526020017f6d6f6e6f6368726f6d61746963000000000000000000000000000000000000008152505b600180612912565b6126906040518060400160405280600c81526020017f636f726e65722073686170650000000000000000000000000000000000000000815250612688876119a5565b600180612912565b6126da6040518060400160405280600a81526020017f70617468207769647468000000000000000000000000000000000000000000008152506126d288611a3f565b600180612912565b6127386040518060400160405280600a81526020017f7061746820636f756e740000000000000000000000000000000000000000000081525061273060016127218b6123cc565b61272b91906131fe565b611aee565b600180612912565b61278a6040518060400160405280601781526020017f70617468207374617274696e67206c696768746e65737300000000000000000081525061278261277d8b611c83565b611aee565b600180612912565b6128e56040518060400160405280600d81526020017f7061746820636f6e74726173740000000000000000000000000000000000000081525060056127ce8c612369565b146128a657600a6127de8c612369565b1461286a57600f6127ee8c612369565b1461282e576040518060400160405280600a81526020017f6578747261206869676800000000000000000000000000000000000000000000815250612865565b6040518060400160405280600481526020017f68696768000000000000000000000000000000000000000000000000000000008152505b6128a1565b6040518060400160405280600681526020017f6d656469756d00000000000000000000000000000000000000000000000000008152505b6128dd565b6040518060400160405280600381526020017f6c6f7700000000000000000000000000000000000000000000000000000000008152505b60015f612912565b6040516020016128fc989796959493929190614190565b6040516020818303038152906040529050919050565b6060848361292e5760405180602001604052805f815250612965565b6040518060400160405280600181526020017f22000000000000000000000000000000000000000000000000000000000000008152505b858561297f5760405180602001604052805f8152506129b6565b6040518060400160405280600181526020017f22000000000000000000000000000000000000000000000000000000000000008152505b856129cf5760405180602001604052805f815250612a06565b6040518060400160405280600181526020017f2c000000000000000000000000000000000000000000000000000000000000008152505b604051602001612a1a959493929190614329565b6040516020818303038152906040529050949350505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612a7881612a44565b8114612a82575f80fd5b50565b5f81359050612a9381612a6f565b92915050565b5f60208284031215612aae57612aad612a3c565b5b5f612abb84828501612a85565b91505092915050565b5f8115159050919050565b612ad881612ac4565b82525050565b5f602082019050612af15f830184612acf565b92915050565b5f819050919050565b612b0981612af7565b82525050565b5f602082019050612b225f830184612b00565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f612b6a82612b28565b612b748185612b32565b9350612b84818560208601612b42565b612b8d81612b50565b840191505092915050565b5f6020820190508181035f830152612bb08184612b60565b905092915050565b612bc181612af7565b8114612bcb575f80fd5b50565b5f81359050612bdc81612bb8565b92915050565b5f60208284031215612bf757612bf6612a3c565b5b5f612c0484828501612bce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612c3682612c0d565b9050919050565b612c4681612c2c565b82525050565b5f602082019050612c5f5f830184612c3d565b92915050565b612c6e81612c2c565b8114612c78575f80fd5b50565b5f81359050612c8981612c65565b92915050565b5f8060408385031215612ca557612ca4612a3c565b5b5f612cb285828601612c7b565b9250506020612cc385828601612bce565b9150509250929050565b5f805f60608486031215612ce457612ce3612a3c565b5b5f612cf186828701612c7b565b9350506020612d0286828701612c7b565b9250506040612d1386828701612bce565b9150509250925092565b5f60ff82169050919050565b612d3281612d1d565b8114612d3c575f80fd5b50565b5f81359050612d4d81612d29565b92915050565b5f60208284031215612d6857612d67612a3c565b5b5f612d7584828501612d3f565b91505092915050565b5f60208284031215612d9357612d92612a3c565b5b5f612da084828501612c7b565b91505092915050565b612db281612ac4565b8114612dbc575f80fd5b50565b5f81359050612dcd81612da9565b92915050565b5f8060408385031215612de957612de8612a3c565b5b5f612df685828601612c7b565b9250506020612e0785828601612dbf565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612e4f82612b50565b810181811067ffffffffffffffff82111715612e6e57612e6d612e19565b5b80604052505050565b5f612e80612a33565b9050612e8c8282612e46565b919050565b5f67ffffffffffffffff821115612eab57612eaa612e19565b5b612eb482612b50565b9050602081019050919050565b828183375f83830152505050565b5f612ee1612edc84612e91565b612e77565b905082815260208101848484011115612efd57612efc612e15565b5b612f08848285612ec1565b509392505050565b5f82601f830112612f2457612f23612e11565b5b8135612f34848260208601612ecf565b91505092915050565b5f805f8060808587031215612f5557612f54612a3c565b5b5f612f6287828801612c7b565b9450506020612f7387828801612c7b565b9350506040612f8487828801612bce565b925050606085013567ffffffffffffffff811115612fa557612fa4612a40565b5b612fb187828801612f10565b91505092959194509250565b5f8060408385031215612fd357612fd2612a3c565b5b5f612fe085828601612c7b565b9250506020612ff185828601612c7b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061303f57607f821691505b60208210810361305257613051612ffb565b5b50919050565b7f6e6f2065746800000000000000000000000000000000000000000000000000005f82015250565b5f61308c600683612b32565b915061309782613058565b602082019050919050565b5f6020820190508181035f8301526130b981613080565b9050919050565b7f63616e206f6e6c79206d696e74203820617420612074696d65000000000000005f82015250565b5f6130f4601983612b32565b91506130ff826130c0565b602082019050919050565b5f6020820190508181035f830152613121816130e8565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61315f82612af7565b915061316a83612af7565b925082820261317881612af7565b9150828204841483151761318f5761318e613128565b5b5092915050565b7f6e6f7420656e6f756768206574680000000000000000000000000000000000005f82015250565b5f6131ca600e83612b32565b91506131d582613196565b602082019050919050565b5f6020820190508181035f8301526131f7816131be565b9050919050565b5f61320882612af7565b915061321383612af7565b925082820190508082111561322b5761322a613128565b5b92915050565b7f6d696e7420636c6f7365640000000000000000000000000000000000000000005f82015250565b5f613265600b83612b32565b915061327082613231565b602082019050919050565b5f6020820190508181035f83015261329281613259565b9050919050565b5f6132a382612af7565b91505f82036132b5576132b4613128565b5b600182039050919050565b5f81905092915050565b7f3c7376672077696474683d223132303022206865696768743d223132303022205f8201527f76696577426f783d22302030203332203332222066696c6c3d226e6f6e65222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f67222073686170652d72656e646572696e673d2263726973704564676573223e60608201527f3c726563742077696474683d22333222206865696768743d223332222066696c60808201527f6c3d22000000000000000000000000000000000000000000000000000000000060a082015250565b5f6133bc60a3836132c0565b91506133c7826132ca565b60a382019050919050565b5f6133dc82612b28565b6133e681856132c0565b93506133f6818560208601612b42565b80840191505092915050565b7f222f3e00000000000000000000000000000000000000000000000000000000005f82015250565b5f6134366003836132c0565b915061344182613402565b600382019050919050565b7f3c67207374726f6b652d6c696e656361703d226e6f6e6522207374726f6b652d5f8201527f6c696e656a6f696e3d2200000000000000000000000000000000000000000000602082015250565b5f6134a6602a836132c0565b91506134b18261344c565b602a82019050919050565b7f22207374726f6b652d77696474683d22000000000000000000000000000000005f82015250565b5f6134f06010836132c0565b91506134fb826134bc565b601082019050919050565b7f223e3c67207374726f6b653d2268736c280000000000000000000000000000005f82015250565b5f61353a6011836132c0565b915061354582613506565b601182019050919050565b7f64656720000000000000000000000000000000000000000000000000000000005f82015250565b5f6135846004836132c0565b915061358f82613550565b600482019050919050565b7f2529223e000000000000000000000000000000000000000000000000000000005f82015250565b5f6135ce6004836132c0565b91506135d98261359a565b600482019050919050565b7f3c2f673e000000000000000000000000000000000000000000000000000000005f82015250565b5f6136186004836132c0565b9150613623826135e4565b600482019050919050565b7f3c2f7376673e00000000000000000000000000000000000000000000000000005f82015250565b5f6136626006836132c0565b915061366d8261362e565b600682019050919050565b5f613682826133b0565b915061368e828b6133d2565b91506136998261342a565b91506136a48261349a565b91506136b0828a6133d2565b91506136bb826134e4565b91506136c782896133d2565b91506136d28261352e565b91506136de82886133d2565b91506136e982613578565b91506136f582876133d2565b915061370182866133d2565b915061370c826135c2565b915061371882856133d2565b91506137238261360c565b915061372f82846133d2565b915061373a8261360c565b915061374582613656565b91508190509998505050505050505050565b5f81519050919050565b5f82825260208201905092915050565b5f61377b82613757565b6137858185613761565b9350613795818560208601612b42565b61379e81612b50565b840191505092915050565b5f6080820190506137bc5f830187612c3d565b6137c96020830186612c3d565b6137d66040830185612b00565b81810360608301526137e88184613771565b905095945050505050565b5f8151905061380181612a6f565b92915050565b5f6020828403121561381c5761381b612a3c565b5b5f613829848285016137f3565b91505092915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000005f82015250565b5f613866601d836132c0565b915061387182613832565b601d82019050919050565b5f6138868261385a565b915061389282846133d2565b915081905092915050565b7f68736c28000000000000000000000000000000000000000000000000000000005f82015250565b5f6138d16004836132c0565b91506138dc8261389d565b600482019050919050565b7f25290000000000000000000000000000000000000000000000000000000000005f82015250565b5f61391b6002836132c0565b9150613926826138e7565b600282019050919050565b5f61393b826138c5565b915061394782866133d2565b915061395282613578565b915061395e82856133d2565b915061396a82846133d2565b91506139758261390f565b9150819050949350505050565b5f61398c82612af7565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139be576139bd613128565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613a0082612af7565b9150613a0b83612af7565b925082613a1b57613a1a6139c9565b5b828204905092915050565b5f613a3082612af7565b9150613a3b83612af7565b9250828203905081811115613a5357613a52613128565b5b92915050565b5f613a6382612d1d565b9150613a6e83612d1d565b9250828201905060ff811115613a8757613a86613128565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613ac482612d1d565b9150613acf83612d1d565b9250828203905060ff811115613ae857613ae7613128565b5b92915050565b5f613af882612d1d565b9150613b0383612d1d565b925082613b1357613b126139c9565b5b828204905092915050565b7f20680000000000000000000000000000000000000000000000000000000000005f82015250565b5f613b526002836132c0565b9150613b5d82613b1e565b600282019050919050565b7f20760000000000000000000000000000000000000000000000000000000000005f82015250565b5f613b9c6002836132c0565b9150613ba782613b68565b600282019050919050565b5f613bbd82876133d2565b9150613bc882613b46565b9150613bd482866133d2565b9150613bdf82613b90565b9150613beb82856133d2565b9150613bf782846133d2565b915081905095945050505050565b7f3c706174682069643d2262617365706174682220643d224d30200000000000005f82015250565b5f613c39601a836132c0565b9150613c4482613c05565b601a82019050919050565b7f20483332222f3e000000000000000000000000000000000000000000000000005f82015250565b5f613c836007836132c0565b9150613c8e82613c4f565b600782019050919050565b5f613ca382613c2d565b9150613caf82856133d2565b9150613cbb82846133d2565b9150613cc682613c77565b91508190509392505050565b7f3c75736520687265663d2223626173657061746822207374726f6b653d2268735f8201527f6c28000000000000000000000000000000000000000000000000000000000000602082015250565b5f613d2c6022836132c0565b9150613d3782613cd2565b602282019050919050565b7f25292220000000000000000000000000000000000000000000000000000000005f82015250565b5f613d766004836132c0565b9150613d8182613d42565b600482019050919050565b7f7472616e73666f726d3d227472616e736c6174652830202d00000000000000005f82015250565b5f613dc06018836132c0565b9150613dcb82613d8c565b601882019050919050565b7f29222f3e000000000000000000000000000000000000000000000000000000005f82015250565b5f613e0a6004836132c0565b9150613e1582613dd6565b600482019050919050565b5f613e2b82886133d2565b9150613e3682613d20565b9150613e4282876133d2565b9150613e4d82613578565b9150613e5982866133d2565b9150613e6582856133d2565b9150613e7082613d6a565b9150613e7b82613db4565b9150613e8782846133d2565b9150613e9282613dfe565b91508190509695505050505050565b7f7b226e616d65223a2022626173657061746873202300000000000000000000005f82015250565b5f613ed56015836132c0565b9150613ee082613ea1565b601582019050919050565b7f222c20226465736372697074696f6e223a202262617365642067656e657261745f8201527f697665206f6e2d636861696e20617274222c202261747472696275746573223a60208201527f205b000000000000000000000000000000000000000000000000000000000000604082015250565b5f613f6b6042836132c0565b9150613f7682613eeb565b604282019050919050565b5f81905092915050565b5f613f9582613757565b613f9f8185613f81565b9350613faf818560208601612b42565b80840191505092915050565b7f5d2c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b5f8201527f6261736536342c00000000000000000000000000000000000000000000000000602082015250565b5f6140156027836132c0565b915061402082613fbb565b602782019050919050565b7f227d0000000000000000000000000000000000000000000000000000000000005f82015250565b5f61405f6002836132c0565b915061406a8261402b565b600282019050919050565b5f61407f82613ec9565b915061408b82866133d2565b915061409682613f5f565b91506140a28285613f8b565b91506140ad82614009565b91506140b982846133d2565b91506140c482614053565b9150819050949350505050565b5f6140db82612af7565b91506140e683612af7565b9250826140f6576140f56139c9565b5b828206905092915050565b5f819050919050565b61411b61411682612af7565b614101565b82525050565b7f6172742b746563680000000000000000000000000000000000000000000000005f82015250565b5f6141556008836132c0565b915061416082614121565b600882019050919050565b5f614176828461410a565b60208201915061418582614149565b915081905092915050565b5f61419b828b6133d2565b91506141a7828a6133d2565b91506141b382896133d2565b91506141bf82886133d2565b91506141cb82876133d2565b91506141d782866133d2565b91506141e382856133d2565b91506141ef82846133d2565b91508190509998505050505050505050565b7f7b000000000000000000000000000000000000000000000000000000000000005f82015250565b5f6142356001836132c0565b915061424082614201565b600182019050919050565b7f2274726169745f74797065223a202200000000000000000000000000000000005f82015250565b5f61427f600f836132c0565b915061428a8261424b565b600f82019050919050565b7f222c202276616c7565223a2000000000000000000000000000000000000000005f82015250565b5f6142c9600c836132c0565b91506142d482614295565b600c82019050919050565b7f7d000000000000000000000000000000000000000000000000000000000000005f82015250565b5f6143136001836132c0565b915061431e826142df565b600182019050919050565b5f61433382614229565b915061433e82614273565b915061434a82886133d2565b9150614355826142bd565b915061436182876133d2565b915061436d82866133d2565b915061437982856133d2565b915061438482614307565b915061439082846133d2565b9150819050969550505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220de26e4344ab2a6691a915265e54ac044730e73d38844d3eda057e0f70b6549f364736f6c63430008190033
Deployed Bytecode
0x608060405260043610610134575f3560e01c80636ecd2306116100aa578063a22cb4651161006e578063a22cb465146103c0578063b0dc78fa146103e8578063b88d4fde14610424578063c87b56dd14610440578063e985e9c51461047c578063f2fde38b146104b857610134565b80636ecd2306146102fe57806370a082311461031a578063715018a6146103565780638da5cb5b1461036c57806395d89b411461039657610134565b806318160ddd116100fc57806318160ddd1461022057806323b872dd1461024a5780633ccfd60b1461026657806342842e0e1461027c5780636352211e1461029857806364632795146102d457610134565b806301ffc9a7146101385780630387da421461017457806306fdde031461019e578063081812fc146101c8578063095ea7b314610204575b5f80fd5b348015610143575f80fd5b5061015e60048036038101906101599190612a99565b6104e0565b60405161016b9190612ade565b60405180910390f35b34801561017f575f80fd5b50610188610571565b6040516101959190612b0f565b60405180910390f35b3480156101a9575f80fd5b506101b261057c565b6040516101bf9190612b98565b60405180910390f35b3480156101d3575f80fd5b506101ee60048036038101906101e99190612be2565b61060c565b6040516101fb9190612c4c565b60405180910390f35b61021e60048036038101906102199190612c8f565b610665565b005b34801561022b575f80fd5b50610234610675565b6040516102419190612b0f565b60405180910390f35b610264600480360381019061025f9190612ccd565b6106c0565b005b348015610271575f80fd5b5061027a61096b565b005b61029660048036038101906102919190612ccd565b610a00565b005b3480156102a3575f80fd5b506102be60048036038101906102b99190612be2565b610a1f565b6040516102cb9190612c4c565b60405180910390f35b3480156102df575f80fd5b506102e8610a30565b6040516102f59190612b0f565b60405180910390f35b61031860048036038101906103139190612d53565b610a36565b005b348015610325575f80fd5b50610340600480360381019061033b9190612d7e565b610b75565b60405161034d9190612b0f565b60405180910390f35b348015610361575f80fd5b5061036a610c09565b005b348015610377575f80fd5b50610380610c1c565b60405161038d9190612c4c565b60405180910390f35b3480156103a1575f80fd5b506103aa610c44565b6040516103b79190612b98565b60405180910390f35b3480156103cb575f80fd5b506103e660048036038101906103e19190612dd3565b610cd4565b005b3480156103f3575f80fd5b5061040e60048036038101906104099190612be2565b610dda565b60405161041b9190612b98565b60405180910390f35b61043e60048036038101906104399190612f3d565b610dec565b005b34801561044b575f80fd5b5061046660048036038101906104619190612be2565b610e3d565b6040516104739190612b98565b60405180910390f35b348015610487575f80fd5b506104a2600480360381019061049d9190612fbd565b610e4f565b6040516104af9190612ade565b60405180910390f35b3480156104c3575f80fd5b506104de60048036038101906104d99190612d7e565b610edd565b005b5f6301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061053a57506380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061056a5750635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b660b5e620f48000081565b60606002805461058b90613028565b80601f01602080910402602001604051908101604052809291908181526020018280546105b790613028565b80156106025780601f106105d957610100808354040283529160200191610602565b820191905f5260205f20905b8154815290600101906020018083116105e557829003601f168201915b5050505050905090565b5f61061682610f61565b61062b5761062a63cf4700e460e01b611004565b5b60065f8381526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6106718282600161100c565b5050565b5f61067e611136565b6001545f54030390507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6106b061113e565b146106bd57600854810190505b90565b5f6106ca82611165565b905073ffffffffffffffffffffffffffffffffffffffff8473ffffffffffffffffffffffffffffffffffffffff161693508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461073f5761073e63a114810060e01b611004565b5b5f8061074a84611274565b91509150610760818761075b611297565b61129e565b61078b5761077586610770611297565b610e4f565b61078a576107896359c896be60e01b611004565b5b5b61079886868660016112e1565b80156107a2575f82555b60055f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8154600190039190508190555060055f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f81546001019190508190555061086a856108468888876112e7565b7c02000000000000000000000000000000000000000000000000000000001761130e565b60045f8681526020019081526020015f20819055505f7c02000000000000000000000000000000000000000000000000000000008416036108e6575f6001850190505f60045f8381526020019081526020015f2054036108e4575f5481146108e3578360045f8381526020019081526020015f20819055505b5b505b5f73ffffffffffffffffffffffffffffffffffffffff8673ffffffffffffffffffffffffffffffffffffffff161690508481887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a45f81036109555761095463ea553b3460e01b611004565b5b6109628787876001611338565b50505050505050565b61097361133e565b5f4790505f81036109b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109b0906130a2565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156109fc573d5f803e3d5ffd5b5050565b610a1a83838360405180602001604052805f815250610dec565b505050565b5f610a2982611165565b9050919050565b600a5481565b60088160ff161115610a7d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a749061310a565b60405180910390fd5b660b5e620f4800008160ff16610a939190613155565b341015610ad5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acc906131e0565b60405180910390fd5b610280610ae0610675565b1015610b1f576102808160ff16610af5610675565b610aff91906131fe565b10610b0d57610b0c6113c5565b5b610b1a338260ff166113e5565b610b72565b600a54421115610b64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5b9061327b565b60405180910390fd5b610b71338260ff166113e5565b5b50565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bba57610bb9638f4eb60460e01b611004565b5b67ffffffffffffffff60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054169050919050565b610c1161133e565b610c1a5f611559565b565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060038054610c5390613028565b80601f0160208091040260200160405190810160405280929190818152602001828054610c7f90613028565b8015610cca5780601f10610ca157610100808354040283529160200191610cca565b820191905f5260205f20905b815481529060010190602001808311610cad57829003601f168201915b5050505050905090565b8060075f610ce0611297565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16610d89611297565b73ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dce9190612ade565b60405180910390a35050565b6060610de58261161c565b9050919050565b610df78484846106c0565b5f8373ffffffffffffffffffffffffffffffffffffffff163b14610e3757610e2184848484611719565b610e3657610e3563d1a57ed660e01b611004565b5b5b50505050565b6060610e4882611843565b9050919050565b5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b610ee561133e565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f55575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610f4c9190612c4c565b60405180910390fd5b610f5e81611559565b50565b5f81610f6b611136565b11610ffe57610f7861113e565b821115610fa057610f9960045f8481526020019081526020015f205461187c565b9050610fff565b5f54821015610ffd575f5b5f60045f8581526020019081526020015f205491508103610fd75782610fd090613299565b9250610fab565b5f7c01000000000000000000000000000000000000000000000000000000008216149150505b5b5b919050565b805f5260045ffd5b5f61101683610a1f565b905081801561105857508073ffffffffffffffffffffffffffffffffffffffff1661103f611297565b73ffffffffffffffffffffffffffffffffffffffff1614155b156110845761106e81611069611297565b610e4f565b6110835761108263cfb3b94260e01b611004565b5b5b8360065f8581526020019081526020015f205f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550828473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a450505050565b5f6001905090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905090565b5f8161116f611136565b1161125e5760045f8381526020019081526020015f2054905061119061113e565b8211156111b5576111a08161187c565b61126f576111b463df2d9b4260e01b611004565b5b5f8103611236575f5482106111d5576111d463df2d9b4260e01b611004565b5b5b60045f836001900393508381526020019081526020015f205490505f810315611231575f7c01000000000000000000000000000000000000000000000000000000008216031561126f5761123063df2d9b4260e01b611004565b5b6111d6565b5f7c01000000000000000000000000000000000000000000000000000000008216031561126f575b61126e63df2d9b4260e01b611004565b5b919050565b5f805f60065f8581526020019081526020015f2090508092508254915050915091565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff8316925073ffffffffffffffffffffffffffffffffffffffff821691508382148383141790509392505050565b50505050565b5f8060e883901c905060e86112fd8686846118bc565b62ffffff16901b9150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff83169250814260a01b178317905092915050565b50505050565b6113466118c4565b73ffffffffffffffffffffffffffffffffffffffff16611364610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146113c3576113876118c4565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113ba9190612c4c565b60405180910390fd5b565b5f600a54036113e35761e100426113dc91906131fe565b600a819055505b565b5f805490505f82036114025761140163b562e8dd60e01b611004565b5b61140e5f8483856112e1565b61142c8361141d5f865f6112e7565b611426856118cb565b1761130e565b60045f8381526020019081526020015f2081905550600160406001901b17820260055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505f73ffffffffffffffffffffffffffffffffffffffff8473ffffffffffffffffffffffffffffffffffffffff161690505f81036114dd576114dc632e07630060e01b611004565b5b5f83830190505f8390506114ef61113e565b60018303111561150a576115096381647e3a60e01b611004565b5b5b80835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a481816001019150810361150b57815f819055505050506115545f848385611338565b505050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060611627826118da565b611630836119a5565b61163984611a3f565b61164a61164586611ad9565b611aee565b61165386611c6c565b611692576040518060400160405280600581526020017f31303025200000000000000000000000000000000000000000000000000000008152506116c9565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b6116da6116d588611c83565b611aee565b6116e388611ce8565b6116ec89611f44565b604051602001611703989796959493929190613678565b6040516020818303038152906040529050919050565b5f8373ffffffffffffffffffffffffffffffffffffffff1663150b7a0261173e611297565b8786866040518563ffffffff1660e01b815260040161176094939291906137a9565b6020604051808303815f875af192505050801561179b57506040513d601f19601f820116820180604052508101906117989190613807565b60015b6117f0573d805f81146117c9576040519150601f19603f3d011682016040523d82523d5f602084013e6117ce565b606091505b505f8151036117e8576117e763d1a57ed660e01b611004565b5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050949350505050565b606061185661185183612079565b6120c6565b604051602001611866919061387c565b6040516020818303038152906040529050919050565b5f7c0100000000000000000000000000000000000000000000000000000000821673ffffffffffffffffffffffffffffffffffffffff8316119050919050565b5f9392505050565b5f33905090565b5f6001821460e11b9050919050565b60606118ed6118e883612233565b611aee565b6118f683611c6c565b611935576040518060400160405280600581526020017f313030252000000000000000000000000000000000000000000000000000000081525061196c565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b61197d6119788561227e565b611aee565b60405160200161198f93929190613931565b6040516020818303038152906040529050919050565b606060636119c16003846119b99190613155565b5f6064612304565b11611a01576040518060400160405280600681526020017f7371756172650000000000000000000000000000000000000000000000000000815250611a38565b6040518060400160405280600581526020017f726f756e640000000000000000000000000000000000000000000000000000008152505b9050919050565b60606063611a5b600284611a539190613155565b5f6064612304565b11611a9b576040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250611ad2565b6040518060400160405280600381526020017f302e3500000000000000000000000000000000000000000000000000000000008152505b9050919050565b5f611ae7825f610168612304565b9050919050565b60605f8203611b34576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611c67565b5f8290505f5b5f8214611b63578080611b4c90613982565b915050600a82611b5c91906139f6565b9150611b3a565b5f8167ffffffffffffffff811115611b7e57611b7d612e19565b5b6040519080825280601f01601f191660200182016040528015611bb05781602001600182028036833780820191505090505b5090505f8290505b5f8614611c5f57600181611bcc9190613a26565b90505f600a8088611bdd91906139f6565b611be79190613155565b87611bf29190613a26565b6030611bfe9190613a59565b90505f8160f81b905080848481518110611c1b57611c1a613a8d565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600a88611c5691906139f6565b97505050611bb8565b819450505050505b919050565b5f6061611c7b835f6064612304565b119050919050565b5f806040518060600160405280601060ff168152602001601860ff168152602001602060ff16815250905080611cc7600485611cbf9190613155565b5f6002612304565b60038110611cd857611cd7613a8d565b5b602002015160ff16915050919050565b60605f611cf883600e6014612304565b90505f6040518060a00160405280600860ff168152602001601060ff168152602001601060ff168152602001601060ff168152602001601060ff1681525090505f81611d52600587611d4a9190613155565b5f6004612304565b60058110611d6357611d62613a8d565b5b602002015190505f60405180602001604052805f81525090505f8490505f5b600184611d8f9190613aba565b60ff16811015611f0d575f80601c8410611dd257611dc7600284611db39190613155565b8b611dbe91906131fe565b60016003612304565b915060019050611e3e565b60088411611e0857611dfe600384611dea9190613155565b8b611df591906131fe565b60016003612304565b91505f9050611e3d565b611e1f838b611e1791906131fe565b5f6003612304565b91505f611e39848c611e319190613155565b5f6001612304565b1490505b5b84611e57876020611e4f9190613aee565b60ff16611aee565b82611e705760405180602001604052805f815250611ea7565b6040518060400160405280600181526020017f2d000000000000000000000000000000000000000000000000000000000000008152505b611eb085611aee565b604051602001611ec39493929190613bb2565b604051602081830303815290604052945080611eed578184611ee591906131fe565b935083611efd565b8184611ef99190613a26565b9350835b5050508080600101915050611d82565b50611f1785611aee565b82604051602001611f29929190613c99565b60405160208183030381529060405295505050505050919050565b60605f611f5083612369565b611f5984611c83565b611f6391906131fe565b90505f600190505b6001611f76856123cc565b611f8091906131fe565b8110156120725782611f99611f9486611ad9565b611aee565b611fa286611c6c565b611fe1576040518060400160405280600581526020017f3130302520000000000000000000000000000000000000000000000000000000815250612018565b6040518060400160405280600381526020017f30252000000000000000000000000000000000000000000000000000000000008152505b61202185611aee565b61202a85611aee565b60405160200161203e959493929190613e20565b604051602081830303815290604052925061205884612369565b8261206391906131fe565b91508080600101915050611f6b565b5050919050565b606061208482611aee565b61208d83612458565b61209e6120998561161c565b6120c6565b6040516020016120b093929190614075565b6040516020818303038152906040529050919050565b60605f8251036120e65760405180602001604052805f815250905061222e565b5f6040518060600160405280604081526020016143a06040913990505f60036002855161211391906131fe565b61211d91906139f6565b60046121299190613155565b67ffffffffffffffff81111561214257612141612e19565b5b6040519080825280601f01601f1916602001820160405280156121745781602001600182028036833780820191505090505b509050600182016020820185865187016020810180515f82525b828410156121e9576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f811687015186536001860195505061218e565b80825260038a510660018114612206576002811461221957612221565b603d6001870353603d6002870353612221565b603d60018703535b5050505050505080925050505b919050565b5f80612241835f6001612304565b1461226d5761016860b461225484611ad9565b61225e91906131fe565b61226891906140d1565b612277565b61227682611ad9565b5b9050919050565b5f61228882611c6c565b156122a057612299825f600a612304565b90506122ff565b6122a982611ad9565b6122b283612233565b036122ef575f6122c4835f6001612304565b146122da576122d5825f6014612304565b6122e8565b6122e78260506064612304565b5b90506122ff565b6122fc826028603c612304565b90505b919050565b5f80600184846123149190613a26565b61231e91906131fe565b90508085604051602001612332919061416b565b604051602081830303815290604052805190602001205f1c61235491906140d1565b8461235f91906131fe565b9150509392505050565b5f806040518060800160405280600560ff168152602001600a60ff168152602001600f60ff168152602001601460ff168152509050806123ab845f6003612304565b600481106123bc576123bb613a8d565b5b602002015160ff16915050919050565b5f80604051806101000160405280600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff16815250905080612437845f6007612304565b6008811061244857612447613a8d565b5b602002015160ff16915050919050565b606061251a6040518060400160405280600a81526020017f73617475726174696f6e0000000000000000000000000000000000000000000081525061249c84611c6c565b6124db576040518060400160405280600881526020017f636f6c6f7266756c000000000000000000000000000000000000000000000000815250612512565b6040518060400160405280600981526020017f677261797363616c6500000000000000000000000000000000000000000000008152505b600180612912565b61256c6040518060400160405280600881526020017f706174682068756500000000000000000000000000000000000000000000000081525061256461255f86611ad9565b611aee565b5f6001612912565b6126466040518060400160405280600a81526020017f6261636b67726f756e64000000000000000000000000000000000000000000008152506125ae86611ad9565b6125b787612233565b14806125c857506125c786611c6c565b5b612607576040518060400160405280600d81526020017f636f6d706c696d656e746172790000000000000000000000000000000000000081525061263e565b6040518060400160405280600d81526020017f6d6f6e6f6368726f6d61746963000000000000000000000000000000000000008152505b600180612912565b6126906040518060400160405280600c81526020017f636f726e65722073686170650000000000000000000000000000000000000000815250612688876119a5565b600180612912565b6126da6040518060400160405280600a81526020017f70617468207769647468000000000000000000000000000000000000000000008152506126d288611a3f565b600180612912565b6127386040518060400160405280600a81526020017f7061746820636f756e740000000000000000000000000000000000000000000081525061273060016127218b6123cc565b61272b91906131fe565b611aee565b600180612912565b61278a6040518060400160405280601781526020017f70617468207374617274696e67206c696768746e65737300000000000000000081525061278261277d8b611c83565b611aee565b600180612912565b6128e56040518060400160405280600d81526020017f7061746820636f6e74726173740000000000000000000000000000000000000081525060056127ce8c612369565b146128a657600a6127de8c612369565b1461286a57600f6127ee8c612369565b1461282e576040518060400160405280600a81526020017f6578747261206869676800000000000000000000000000000000000000000000815250612865565b6040518060400160405280600481526020017f68696768000000000000000000000000000000000000000000000000000000008152505b6128a1565b6040518060400160405280600681526020017f6d656469756d00000000000000000000000000000000000000000000000000008152505b6128dd565b6040518060400160405280600381526020017f6c6f7700000000000000000000000000000000000000000000000000000000008152505b60015f612912565b6040516020016128fc989796959493929190614190565b6040516020818303038152906040529050919050565b6060848361292e5760405180602001604052805f815250612965565b6040518060400160405280600181526020017f22000000000000000000000000000000000000000000000000000000000000008152505b858561297f5760405180602001604052805f8152506129b6565b6040518060400160405280600181526020017f22000000000000000000000000000000000000000000000000000000000000008152505b856129cf5760405180602001604052805f815250612a06565b6040518060400160405280600181526020017f2c000000000000000000000000000000000000000000000000000000000000008152505b604051602001612a1a959493929190614329565b6040516020818303038152906040529050949350505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612a7881612a44565b8114612a82575f80fd5b50565b5f81359050612a9381612a6f565b92915050565b5f60208284031215612aae57612aad612a3c565b5b5f612abb84828501612a85565b91505092915050565b5f8115159050919050565b612ad881612ac4565b82525050565b5f602082019050612af15f830184612acf565b92915050565b5f819050919050565b612b0981612af7565b82525050565b5f602082019050612b225f830184612b00565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f612b6a82612b28565b612b748185612b32565b9350612b84818560208601612b42565b612b8d81612b50565b840191505092915050565b5f6020820190508181035f830152612bb08184612b60565b905092915050565b612bc181612af7565b8114612bcb575f80fd5b50565b5f81359050612bdc81612bb8565b92915050565b5f60208284031215612bf757612bf6612a3c565b5b5f612c0484828501612bce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612c3682612c0d565b9050919050565b612c4681612c2c565b82525050565b5f602082019050612c5f5f830184612c3d565b92915050565b612c6e81612c2c565b8114612c78575f80fd5b50565b5f81359050612c8981612c65565b92915050565b5f8060408385031215612ca557612ca4612a3c565b5b5f612cb285828601612c7b565b9250506020612cc385828601612bce565b9150509250929050565b5f805f60608486031215612ce457612ce3612a3c565b5b5f612cf186828701612c7b565b9350506020612d0286828701612c7b565b9250506040612d1386828701612bce565b9150509250925092565b5f60ff82169050919050565b612d3281612d1d565b8114612d3c575f80fd5b50565b5f81359050612d4d81612d29565b92915050565b5f60208284031215612d6857612d67612a3c565b5b5f612d7584828501612d3f565b91505092915050565b5f60208284031215612d9357612d92612a3c565b5b5f612da084828501612c7b565b91505092915050565b612db281612ac4565b8114612dbc575f80fd5b50565b5f81359050612dcd81612da9565b92915050565b5f8060408385031215612de957612de8612a3c565b5b5f612df685828601612c7b565b9250506020612e0785828601612dbf565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612e4f82612b50565b810181811067ffffffffffffffff82111715612e6e57612e6d612e19565b5b80604052505050565b5f612e80612a33565b9050612e8c8282612e46565b919050565b5f67ffffffffffffffff821115612eab57612eaa612e19565b5b612eb482612b50565b9050602081019050919050565b828183375f83830152505050565b5f612ee1612edc84612e91565b612e77565b905082815260208101848484011115612efd57612efc612e15565b5b612f08848285612ec1565b509392505050565b5f82601f830112612f2457612f23612e11565b5b8135612f34848260208601612ecf565b91505092915050565b5f805f8060808587031215612f5557612f54612a3c565b5b5f612f6287828801612c7b565b9450506020612f7387828801612c7b565b9350506040612f8487828801612bce565b925050606085013567ffffffffffffffff811115612fa557612fa4612a40565b5b612fb187828801612f10565b91505092959194509250565b5f8060408385031215612fd357612fd2612a3c565b5b5f612fe085828601612c7b565b9250506020612ff185828601612c7b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061303f57607f821691505b60208210810361305257613051612ffb565b5b50919050565b7f6e6f2065746800000000000000000000000000000000000000000000000000005f82015250565b5f61308c600683612b32565b915061309782613058565b602082019050919050565b5f6020820190508181035f8301526130b981613080565b9050919050565b7f63616e206f6e6c79206d696e74203820617420612074696d65000000000000005f82015250565b5f6130f4601983612b32565b91506130ff826130c0565b602082019050919050565b5f6020820190508181035f830152613121816130e8565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61315f82612af7565b915061316a83612af7565b925082820261317881612af7565b9150828204841483151761318f5761318e613128565b5b5092915050565b7f6e6f7420656e6f756768206574680000000000000000000000000000000000005f82015250565b5f6131ca600e83612b32565b91506131d582613196565b602082019050919050565b5f6020820190508181035f8301526131f7816131be565b9050919050565b5f61320882612af7565b915061321383612af7565b925082820190508082111561322b5761322a613128565b5b92915050565b7f6d696e7420636c6f7365640000000000000000000000000000000000000000005f82015250565b5f613265600b83612b32565b915061327082613231565b602082019050919050565b5f6020820190508181035f83015261329281613259565b9050919050565b5f6132a382612af7565b91505f82036132b5576132b4613128565b5b600182039050919050565b5f81905092915050565b7f3c7376672077696474683d223132303022206865696768743d223132303022205f8201527f76696577426f783d22302030203332203332222066696c6c3d226e6f6e65222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f67222073686170652d72656e646572696e673d2263726973704564676573223e60608201527f3c726563742077696474683d22333222206865696768743d223332222066696c60808201527f6c3d22000000000000000000000000000000000000000000000000000000000060a082015250565b5f6133bc60a3836132c0565b91506133c7826132ca565b60a382019050919050565b5f6133dc82612b28565b6133e681856132c0565b93506133f6818560208601612b42565b80840191505092915050565b7f222f3e00000000000000000000000000000000000000000000000000000000005f82015250565b5f6134366003836132c0565b915061344182613402565b600382019050919050565b7f3c67207374726f6b652d6c696e656361703d226e6f6e6522207374726f6b652d5f8201527f6c696e656a6f696e3d2200000000000000000000000000000000000000000000602082015250565b5f6134a6602a836132c0565b91506134b18261344c565b602a82019050919050565b7f22207374726f6b652d77696474683d22000000000000000000000000000000005f82015250565b5f6134f06010836132c0565b91506134fb826134bc565b601082019050919050565b7f223e3c67207374726f6b653d2268736c280000000000000000000000000000005f82015250565b5f61353a6011836132c0565b915061354582613506565b601182019050919050565b7f64656720000000000000000000000000000000000000000000000000000000005f82015250565b5f6135846004836132c0565b915061358f82613550565b600482019050919050565b7f2529223e000000000000000000000000000000000000000000000000000000005f82015250565b5f6135ce6004836132c0565b91506135d98261359a565b600482019050919050565b7f3c2f673e000000000000000000000000000000000000000000000000000000005f82015250565b5f6136186004836132c0565b9150613623826135e4565b600482019050919050565b7f3c2f7376673e00000000000000000000000000000000000000000000000000005f82015250565b5f6136626006836132c0565b915061366d8261362e565b600682019050919050565b5f613682826133b0565b915061368e828b6133d2565b91506136998261342a565b91506136a48261349a565b91506136b0828a6133d2565b91506136bb826134e4565b91506136c782896133d2565b91506136d28261352e565b91506136de82886133d2565b91506136e982613578565b91506136f582876133d2565b915061370182866133d2565b915061370c826135c2565b915061371882856133d2565b91506137238261360c565b915061372f82846133d2565b915061373a8261360c565b915061374582613656565b91508190509998505050505050505050565b5f81519050919050565b5f82825260208201905092915050565b5f61377b82613757565b6137858185613761565b9350613795818560208601612b42565b61379e81612b50565b840191505092915050565b5f6080820190506137bc5f830187612c3d565b6137c96020830186612c3d565b6137d66040830185612b00565b81810360608301526137e88184613771565b905095945050505050565b5f8151905061380181612a6f565b92915050565b5f6020828403121561381c5761381b612a3c565b5b5f613829848285016137f3565b91505092915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000005f82015250565b5f613866601d836132c0565b915061387182613832565b601d82019050919050565b5f6138868261385a565b915061389282846133d2565b915081905092915050565b7f68736c28000000000000000000000000000000000000000000000000000000005f82015250565b5f6138d16004836132c0565b91506138dc8261389d565b600482019050919050565b7f25290000000000000000000000000000000000000000000000000000000000005f82015250565b5f61391b6002836132c0565b9150613926826138e7565b600282019050919050565b5f61393b826138c5565b915061394782866133d2565b915061395282613578565b915061395e82856133d2565b915061396a82846133d2565b91506139758261390f565b9150819050949350505050565b5f61398c82612af7565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139be576139bd613128565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613a0082612af7565b9150613a0b83612af7565b925082613a1b57613a1a6139c9565b5b828204905092915050565b5f613a3082612af7565b9150613a3b83612af7565b9250828203905081811115613a5357613a52613128565b5b92915050565b5f613a6382612d1d565b9150613a6e83612d1d565b9250828201905060ff811115613a8757613a86613128565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613ac482612d1d565b9150613acf83612d1d565b9250828203905060ff811115613ae857613ae7613128565b5b92915050565b5f613af882612d1d565b9150613b0383612d1d565b925082613b1357613b126139c9565b5b828204905092915050565b7f20680000000000000000000000000000000000000000000000000000000000005f82015250565b5f613b526002836132c0565b9150613b5d82613b1e565b600282019050919050565b7f20760000000000000000000000000000000000000000000000000000000000005f82015250565b5f613b9c6002836132c0565b9150613ba782613b68565b600282019050919050565b5f613bbd82876133d2565b9150613bc882613b46565b9150613bd482866133d2565b9150613bdf82613b90565b9150613beb82856133d2565b9150613bf782846133d2565b915081905095945050505050565b7f3c706174682069643d2262617365706174682220643d224d30200000000000005f82015250565b5f613c39601a836132c0565b9150613c4482613c05565b601a82019050919050565b7f20483332222f3e000000000000000000000000000000000000000000000000005f82015250565b5f613c836007836132c0565b9150613c8e82613c4f565b600782019050919050565b5f613ca382613c2d565b9150613caf82856133d2565b9150613cbb82846133d2565b9150613cc682613c77565b91508190509392505050565b7f3c75736520687265663d2223626173657061746822207374726f6b653d2268735f8201527f6c28000000000000000000000000000000000000000000000000000000000000602082015250565b5f613d2c6022836132c0565b9150613d3782613cd2565b602282019050919050565b7f25292220000000000000000000000000000000000000000000000000000000005f82015250565b5f613d766004836132c0565b9150613d8182613d42565b600482019050919050565b7f7472616e73666f726d3d227472616e736c6174652830202d00000000000000005f82015250565b5f613dc06018836132c0565b9150613dcb82613d8c565b601882019050919050565b7f29222f3e000000000000000000000000000000000000000000000000000000005f82015250565b5f613e0a6004836132c0565b9150613e1582613dd6565b600482019050919050565b5f613e2b82886133d2565b9150613e3682613d20565b9150613e4282876133d2565b9150613e4d82613578565b9150613e5982866133d2565b9150613e6582856133d2565b9150613e7082613d6a565b9150613e7b82613db4565b9150613e8782846133d2565b9150613e9282613dfe565b91508190509695505050505050565b7f7b226e616d65223a2022626173657061746873202300000000000000000000005f82015250565b5f613ed56015836132c0565b9150613ee082613ea1565b601582019050919050565b7f222c20226465736372697074696f6e223a202262617365642067656e657261745f8201527f697665206f6e2d636861696e20617274222c202261747472696275746573223a60208201527f205b000000000000000000000000000000000000000000000000000000000000604082015250565b5f613f6b6042836132c0565b9150613f7682613eeb565b604282019050919050565b5f81905092915050565b5f613f9582613757565b613f9f8185613f81565b9350613faf818560208601612b42565b80840191505092915050565b7f5d2c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b5f8201527f6261736536342c00000000000000000000000000000000000000000000000000602082015250565b5f6140156027836132c0565b915061402082613fbb565b602782019050919050565b7f227d0000000000000000000000000000000000000000000000000000000000005f82015250565b5f61405f6002836132c0565b915061406a8261402b565b600282019050919050565b5f61407f82613ec9565b915061408b82866133d2565b915061409682613f5f565b91506140a28285613f8b565b91506140ad82614009565b91506140b982846133d2565b91506140c482614053565b9150819050949350505050565b5f6140db82612af7565b91506140e683612af7565b9250826140f6576140f56139c9565b5b828206905092915050565b5f819050919050565b61411b61411682612af7565b614101565b82525050565b7f6172742b746563680000000000000000000000000000000000000000000000005f82015250565b5f6141556008836132c0565b915061416082614121565b600882019050919050565b5f614176828461410a565b60208201915061418582614149565b915081905092915050565b5f61419b828b6133d2565b91506141a7828a6133d2565b91506141b382896133d2565b91506141bf82886133d2565b91506141cb82876133d2565b91506141d782866133d2565b91506141e382856133d2565b91506141ef82846133d2565b91508190509998505050505050505050565b7f7b000000000000000000000000000000000000000000000000000000000000005f82015250565b5f6142356001836132c0565b915061424082614201565b600182019050919050565b7f2274726169745f74797065223a202200000000000000000000000000000000005f82015250565b5f61427f600f836132c0565b915061428a8261424b565b600f82019050919050565b7f222c202276616c7565223a2000000000000000000000000000000000000000005f82015250565b5f6142c9600c836132c0565b91506142d482614295565b600c82019050919050565b7f7d000000000000000000000000000000000000000000000000000000000000005f82015250565b5f6143136001836132c0565b915061431e826142df565b600182019050919050565b5f61433382614229565b915061433e82614273565b915061434a82886133d2565b9150614355826142bd565b915061436182876133d2565b915061436d82866133d2565b915061437982856133d2565b915061438482614307565b915061439082846133d2565b9150819050969550505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220de26e4344ab2a6691a915265e54ac044730e73d38844d3eda057e0f70b6549f364736f6c63430008190033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$99.34
Net Worth in ETH
0.044793
Token Allocations
ETH
100.00%
Multichain Portfolio | 32 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BASE | 100.00% | $2,217.31 | 0.0448 | $99.34 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.