Source Code
Overview
MON Balance
MON Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 93 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Mint With Signat... | 42925999 | 41 days ago | IN | 0 MON | 0.5097 | ||||
| Safe Transfer Fr... | 42731968 | 42 days ago | IN | 0 MON | 0.02059137 | ||||
| Airdrop | 42721005 | 42 days ago | IN | 0 MON | 0.14946972 | ||||
| Safe Transfer Fr... | 42676789 | 42 days ago | IN | 0 MON | 0.01689991 | ||||
| Safe Transfer Fr... | 42634624 | 43 days ago | IN | 0 MON | 0.0318632 | ||||
| Safe Transfer Fr... | 42634250 | 43 days ago | IN | 0 MON | 0.01871946 | ||||
| Mint With Signat... | 42576285 | 43 days ago | IN | 0 MON | 0.59085686 | ||||
| Mint With Signat... | 42522980 | 43 days ago | IN | 0 MON | 0.5 | ||||
| Set Approval For... | 42506524 | 43 days ago | IN | 0 MON | 0.00681968 | ||||
| Set Approval For... | 42506111 | 43 days ago | IN | 0 MON | 0.0054491 | ||||
| Mint With Signat... | 42505261 | 43 days ago | IN | 0 MON | 0.68086109 | ||||
| Mint With Signat... | 42479253 | 43 days ago | IN | 0 MON | 0.53395 | ||||
| Mint With Signat... | 41757760 | 47 days ago | IN | 0 MON | 0.515 | ||||
| Safe Transfer Fr... | 41697593 | 47 days ago | IN | 0 MON | 0.04552823 | ||||
| Airdrop | 41671020 | 47 days ago | IN | 0 MON | 0.38445922 | ||||
| Airdrop | 41611989 | 47 days ago | IN | 0 MON | 1.52383034 | ||||
| Withdraw | 41593851 | 48 days ago | IN | 0 MON | 0.01191666 | ||||
| Set Payees | 41593805 | 48 days ago | IN | 0 MON | 0.02098688 | ||||
| Set Approval For... | 39071967 | 59 days ago | IN | 0 MON | 0.00817167 | ||||
| Mint With Signat... | 38815160 | 60 days ago | IN | 0 MON | 0.514647 | ||||
| Set Approval For... | 38755472 | 61 days ago | IN | 0 MON | 0.00571444 | ||||
| Mint With Signat... | 38549980 | 62 days ago | IN | 0 MON | 0.51455 | ||||
| Mint With Signat... | 38377744 | 62 days ago | IN | 0 MON | 0.62664388 | ||||
| Mint With Signat... | 38291425 | 63 days ago | IN | 0 MON | 0.51 | ||||
| Mint With Signat... | 38291300 | 63 days ago | IN | 0 MON | 0.51 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 42925999 | 41 days ago | 0 MON | |||||
| 42925999 | 41 days ago | 0 MON | |||||
| 42925999 | 41 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42721005 | 42 days ago | 0 MON | |||||
| 42576285 | 43 days ago | 0 MON | |||||
| 42576285 | 43 days ago | 0 MON |
Loading...
Loading
Contract Name:
OnChainFunGuys
Compiler Version
v0.8.20+commit.a1b79de6
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
███████╗██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗███████╗
██╔════╝██║ ██║████╗ ██║██╔════╝ ██║ ██║╚██╗ ██╔╝██╔════╝
█████╗ ██║ ██║██╔██╗ ██║██║ ███╗██║ ██║ ╚████╔╝ ███████╗
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║ ╚██╔╝ ╚════██║
██║ ╚██████╔╝██║ ╚████║╚██████╔╝╚██████╔╝ ██║ ███████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
*/
import "erc721a/contracts/ERC721A.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import "./IFunGuyRenderer.sol";
/// @title On-Chain FunGuys
/// @author Shawn Cleta (art)
/// @author 612crypto (dev)
/// @author OffGridGecko (technical advisor)
/// @notice 2,222 On-Chain FunGuys with tiered minting system and honorary custom tokens
contract OnChainFunGuys is ERC721A, Ownable, ReentrancyGuard {
using Strings for uint256;
using ECDSA for bytes32;
using MessageHashUtils for bytes32;
uint256 public constant maxSupply = 2222;
uint256 public constant regularMintPrice = 200 ether;
uint256 public constant customNftRange = 20;
uint256 public constant firstRegularTokenId = customNftRange + 1;
bool public mintingOpen = false;
address public signerAddress;
IFunGuyRenderer public renderer;
mapping(uint256 => uint256) public seeds;
mapping(bytes32 => bool) public usedCombinations;
mapping(address => uint256) public ogAllocationUsed;
mapping(address => uint256) public pfpAllocationUsed;
mapping(address => bool) public pfpPromiseMade;
mapping(uint256 => string) public customMetadata;
mapping(uint256 => bool) public isCustomToken;
string private _contractURI;
address[] public payees;
uint256[] public shares;
event OGMint(address indexed to, uint256 quantity, uint256 remainingAllocation);
event PFPBonusMint(address indexed to, uint256 quantity, uint256 remainingAllocation);
event PFPPromiseMade(address indexed user);
event CustomMetadataSet(uint256 indexed tokenId, string metadata);
event CustomTokenMinted(uint256 indexed tokenId, address indexed to);
event RendererUpdated(address indexed oldRenderer, address indexed newRenderer);
event Airdrop(address indexed to, uint256 quantity, uint256 startTokenId);
constructor(address _renderer) ERC721A("On-Chain FunGuys", "FUNGUY") Ownable(msg.sender) {
signerAddress = msg.sender;
renderer = IFunGuyRenderer(_renderer);
}
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
function mintWithSignature(
bytes calldata signature,
uint256 quantity,
uint256 maxOGAllocation,
bool hasPFPPromise
) external payable nonReentrant {
require(mintingOpen, "Minting is not open");
require(quantity > 0 && quantity <= 10, "Invalid quantity");
require(_totalMinted() + quantity <= maxSupply, "Would exceed max supply");
require(totalSupply() >= customNftRange, "Custom tokens must be minted before regular minting begins");
bytes32 messageHash = keccak256(abi.encodePacked(
msg.sender,
quantity,
maxOGAllocation,
hasPFPPromise
));
bytes32 ethSignedMessageHash = messageHash.toEthSignedMessageHash();
require(ECDSA.recover(ethSignedMessageHash, signature) == signerAddress, "Invalid signature");
(uint256 ogMints, uint256 pfpMints, uint256 regularMints) = _calculateMintBreakdown(
quantity, maxOGAllocation, hasPFPPromise
);
uint256 totalCost = regularMints * regularMintPrice;
require(msg.value >= totalCost, "Insufficient payment");
if (ogMints > 0) {
ogAllocationUsed[msg.sender] += ogMints;
}
if (pfpMints > 0) {
pfpAllocationUsed[msg.sender] += pfpMints;
}
if (hasPFPPromise && !pfpPromiseMade[msg.sender]) {
pfpPromiseMade[msg.sender] = true;
emit PFPPromiseMade(msg.sender);
}
uint256 startTokenId = totalSupply() + 1;
for (uint256 i = 0; i < quantity; i++) {
uint256 tokenId = startTokenId + i;
seeds[tokenId] = _generateUniqueSeed(tokenId, msg.sender);
}
_mint(msg.sender, quantity);
if (ogMints > 0) {
emit OGMint(msg.sender, ogMints, maxOGAllocation - ogAllocationUsed[msg.sender]);
}
if (pfpMints > 0) {
emit PFPBonusMint(msg.sender, pfpMints, 1 - pfpAllocationUsed[msg.sender]);
}
if (msg.value > totalCost) {
payable(msg.sender).transfer(msg.value - totalCost);
}
}
function _calculateMintBreakdown(
uint256 quantity,
uint256 maxOGAllocation,
bool hasPFPPromise
) private view returns (uint256 ogMints, uint256 pfpMints, uint256 regularMints) {
uint256 remainingQuantity = quantity;
uint256 availableOG = maxOGAllocation - ogAllocationUsed[msg.sender];
ogMints = remainingQuantity < availableOG ? remainingQuantity : availableOG;
remainingQuantity -= ogMints;
if (hasPFPPromise && remainingQuantity > 0) {
uint256 availablePFP = 1 - pfpAllocationUsed[msg.sender];
pfpMints = remainingQuantity < availablePFP ? remainingQuantity : availablePFP;
remainingQuantity -= pfpMints;
}
regularMints = remainingQuantity;
}
function _generateUniqueSeed(uint256 tokenId, address minter) private returns (uint256) {
uint256 attempts = 0;
uint256 maxAttempts = 50;
while (attempts < maxAttempts) {
uint256 seed = uint256(keccak256(abi.encodePacked(
block.timestamp,
block.prevrandao,
minter,
tokenId,
attempts
)));
(, uint256 baseIndex, uint256 eyesIndex, uint256 mouthIndex) = renderer.getTraitIndicesFromSeed(seed);
bytes32 combinationHash = keccak256(abi.encodePacked(baseIndex, eyesIndex, mouthIndex));
if (!usedCombinations[combinationHash]) {
usedCombinations[combinationHash] = true;
return seed;
}
attempts++;
}
revert("Unable to generate unique combination");
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "Token does not exist");
if (tokenId <= customNftRange) {
if (_exists(tokenId) && bytes(customMetadata[tokenId]).length > 0) {
return customMetadata[tokenId];
} else {
return "";
}
}
uint256 seed = seeds[tokenId];
(
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) = renderer.getTraitIndicesFromSeed(seed);
return renderer.getTokenURI(tokenId, seed, backgroundIndex, baseIndex, eyesIndex, mouthIndex);
}
function contractURI() public view returns (string memory) {
return _contractURI;
}
function getTraitIndices(uint256[] calldata tokenIds) external view returns (uint256[] memory) {
uint256[] memory results = new uint256[](tokenIds.length * 4);
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
require(_exists(tokenId), "Token does not exist");
uint256 seed = seeds[tokenId];
(
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) = renderer.getTraitIndicesFromSeed(seed);
results[i * 4] = backgroundIndex;
results[i * 4 + 1] = baseIndex;
results[i * 4 + 2] = eyesIndex;
results[i * 4 + 3] = mouthIndex;
}
return results;
}
function mintCustomToken(uint256 tokenId, address recipient, string calldata metadata) external onlyOwner {
require(tokenId >= 1 && tokenId <= customNftRange, "Invalid custom token ID");
require(!_exists(tokenId), "Custom token already minted");
require(bytes(metadata).length > 0, "Metadata required");
require(totalSupply() < customNftRange, "Custom token range exceeded - regular minting has begun");
uint256 tokensToMint = tokenId - totalSupply();
if (tokensToMint > 1) {
_mint(owner(), tokensToMint - 1);
_mint(recipient, 1);
} else {
_mint(recipient, 1);
}
uint256 actualTokenId = totalSupply();
require(actualTokenId == tokenId, "Token ID mismatch during minting");
isCustomToken[tokenId] = true;
customMetadata[tokenId] = metadata;
emit CustomTokenMinted(tokenId, recipient);
}
function setCustomMetadata(uint256 tokenId, string calldata metadata) external onlyOwner {
require(tokenId <= customNftRange && bytes(metadata).length > 0, "Invalid input");
require(_exists(tokenId), "Token does not exist");
customMetadata[tokenId] = metadata;
emit CustomMetadataSet(tokenId, metadata);
}
function transferCustomToken(uint256 tokenId, address to) external onlyOwner {
require(tokenId <= customNftRange && to != address(0), "Invalid input");
require(_exists(tokenId), "Token does not exist");
require(isCustomToken[tokenId], "Not a custom token");
address currentOwner = ownerOf(tokenId);
require(currentOwner != address(0), "Token not owned");
if (currentOwner != to) {
safeTransferFrom(currentOwner, to, tokenId);
}
emit CustomTokenMinted(tokenId, to);
}
function setMintingOpen(bool open) external onlyOwner {
mintingOpen = open;
}
function setSignerAddress(address signer) external onlyOwner {
signerAddress = signer;
}
function setRenderer(address newRenderer) external onlyOwner {
address oldRenderer = address(renderer);
renderer = IFunGuyRenderer(newRenderer);
emit RendererUpdated(oldRenderer, newRenderer);
}
function setContractURI(string calldata uri) external onlyOwner {
_contractURI = uri;
}
function setPayees(address[] memory newPayees, uint256[] memory newShares) external onlyOwner {
require(newPayees.length == newShares.length, "Mismatched lengths");
uint256 totalShares;
for (uint256 i = 0; i < newShares.length; i++) {
totalShares += newShares[i];
}
require(totalShares == 10000, "Total shares must be 10000 (100%)");
payees = newPayees;
shares = newShares;
}
function airdrop(address[] calldata recipients, uint256[] calldata quantities) external onlyOwner {
require(recipients.length == quantities.length, "Mismatched array lengths");
require(recipients.length > 0, "No recipients specified");
uint256 totalQuantity = 0;
for (uint256 i = 0; i < quantities.length; i++) {
require(quantities[i] > 0, "Quantity must be greater than 0");
require(recipients[i] != address(0), "Invalid recipient address");
totalQuantity += quantities[i];
}
require(_totalMinted() + totalQuantity <= maxSupply, "Would exceed max supply");
for (uint256 i = 0; i < recipients.length; i++) {
address recipient = recipients[i];
uint256 quantity = quantities[i];
uint256 startTokenId = totalSupply() + 1;
for (uint256 j = 0; j < quantity; j++) {
uint256 tokenId = startTokenId + j;
seeds[tokenId] = _generateUniqueSeed(tokenId, recipient);
}
_mint(recipient, quantity);
emit Airdrop(recipient, quantity, startTokenId);
}
}
function getOwnedTokens(address owner) external view returns (uint256[] memory tokenIds) {
uint256 balance = balanceOf(owner);
if (balance == 0) {
return new uint256[](0);
}
tokenIds = new uint256[](balance);
uint256 currentSupply = totalSupply();
uint256 index = 0;
for (uint256 tokenId = 1; tokenId <= currentSupply; tokenId++) {
if (ownerOf(tokenId) == owner) {
tokenIds[index] = tokenId;
index++;
if (index == balance) {
break;
}
}
}
return tokenIds;
}
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "No funds to withdraw");
for (uint256 i = 0; i < payees.length; i++) {
uint256 payment = (balance * shares[i]) / 10000;
(bool success, ) = payable(payees[i]).call{value: payment}("");
require(success, "Transfer failed");
}
}
}// 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
// OpenZeppelin Contracts (last updated v5.4.0) (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
* See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE, true);
}
/**
* @dev Converts a `bytes` to its Bytes64Url `string` representation.
* Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648].
*/
function encodeURL(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE_URL, false);
}
/**
* @dev Internal table-agnostic conversion
*/
function _encode(bytes memory data, string memory table, bool withPadding) private 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 "";
// If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
// multiplied by 4 so that it leaves room for padding the last chunk
// - `data.length + 2` -> Prepare for division rounding up
// - `/ 3` -> Number of 3-bytes chunks (rounded up)
// - `4 *` -> 4 characters for each chunk
// This is equivalent to: 4 * Math.ceil(data.length / 3)
//
// If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
// opposed to when padding is required to fill the last chunk.
// - `4 * data.length` -> 4 characters for each chunk
// - ` + 2` -> Prepare for division rounding up
// - `/ 3` -> Number of 3-bytes chunks (rounded up)
// This is equivalent to: Math.ceil((4 * data.length) / 3)
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
string memory result = new string(resultLength);
assembly ("memory-safe") {
// 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)
if withPadding {
// 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.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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.
*/
function toDataWithIntendedValidatorHash(
address validator,
bytes32 messageHash
) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, hex"19_00")
mstore(0x02, shl(96, validator))
mstore(0x16, messageHash)
digest := keccak256(0x00, 0x36)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
using SafeCast for *;
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
uint256 private constant SPECIAL_CHARS_LOOKUP =
(1 << 0x08) | // backspace
(1 << 0x09) | // tab
(1 << 0x0a) | // newline
(1 << 0x0c) | // form feed
(1 << 0x0d) | // carriage return
(1 << 0x22) | // double quote
(1 << 0x5c); // backslash
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev The string being parsed contains characters that are not in scope of the given base.
*/
error StringsInvalidChar();
/**
* @dev The string being parsed is not a properly formatted address.
*/
error StringsInvalidAddressFormat();
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly ("memory-safe") {
ptr := add(add(buffer, 0x20), length)
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
/**
* @dev Parse a decimal string and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input) internal pure returns (uint256) {
return parseUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
uint256 result = 0;
for (uint256 i = begin; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 9) return (false, 0);
result *= 10;
result += chr;
}
return (true, result);
}
/**
* @dev Parse a decimal string and returns the value as a `int256`.
*
* Requirements:
* - The string must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input) internal pure returns (int256) {
return parseInt(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
(bool success, int256 value) = tryParseInt(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
* the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
}
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
/**
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character or if the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, int256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseIntUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseIntUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, int256 value) {
bytes memory buffer = bytes(input);
// Check presence of a negative sign.
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
bool positiveSign = sign == bytes1("+");
bool negativeSign = sign == bytes1("-");
uint256 offset = (positiveSign || negativeSign).toUint();
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
if (absSuccess && absValue < ABS_MIN_INT256) {
return (true, negativeSign ? -int256(absValue) : int256(absValue));
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
return (true, type(int256).min);
} else return (false, 0);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input) internal pure returns (uint256) {
return parseHexUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
* invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseHexUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseHexUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
// skip 0x prefix if present
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 offset = hasPrefix.toUint() * 2;
uint256 result = 0;
for (uint256 i = begin + offset; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 15) return (false, 0);
result *= 16;
unchecked {
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
// This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.
result += chr;
}
}
return (true, result);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input) internal pure returns (address) {
return parseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
(bool success, address value) = tryParseAddress(input, begin, end);
if (!success) revert StringsInvalidAddressFormat();
return value;
}
/**
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
* formatted address. See {parseAddress-string} requirements.
*/
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
return tryParseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
* formatted address. See {parseAddress-string-uint256-uint256} requirements.
*/
function tryParseAddress(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, address value) {
if (end > bytes(input).length || begin > end) return (false, address(0));
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
// check that input is the correct length
if (end - begin == expectedLength) {
// length guarantees that this does not overflow, and value is at most type(uint160).max
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
return (s, address(uint160(v)));
} else {
return (false, address(0));
}
}
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
uint8 value = uint8(chr);
// Try to parse `chr`:
// - Case 1: [0-9]
// - Case 2: [a-f]
// - Case 3: [A-F]
// - otherwise not supported
unchecked {
if (value > 47 && value < 58) value -= 48;
else if (value > 96 && value < 103) value -= 87;
else if (value > 64 && value < 71) value -= 55;
else return type(uint8).max;
}
return value;
}
/**
* @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
*
* WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
*
* NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of
* RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode
* characters that are not in this range, but other tooling may provide different results.
*/
function escapeJSON(string memory input) internal pure returns (string memory) {
bytes memory buffer = bytes(input);
bytes memory output = new bytes(2 * buffer.length); // worst case scenario
uint256 outputLength = 0;
for (uint256 i; i < buffer.length; ++i) {
bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));
if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {
output[outputLength++] = "\\";
if (char == 0x08) output[outputLength++] = "b";
else if (char == 0x09) output[outputLength++] = "t";
else if (char == 0x0a) output[outputLength++] = "n";
else if (char == 0x0c) output[outputLength++] = "f";
else if (char == 0x0d) output[outputLength++] = "r";
else if (char == 0x5c) output[outputLength++] = "\\";
else if (char == 0x22) {
// solhint-disable-next-line quotes
output[outputLength++] = '"';
}
} else {
output[outputLength++] = char;
}
}
// write the actual length and deallocate unused memory
assembly ("memory-safe") {
mstore(output, outputLength)
mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))
}
return string(output);
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(add(buffer, 0x20), offset))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
███████╗██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗███████╗
██╔════╝██║ ██║████╗ ██║██╔════╝ ██║ ██║╚██╗ ██╔╝██╔════╝
█████╗ ██║ ██║██╔██╗ ██║██║ ███╗██║ ██║ ╚████╔╝ ███████╗
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║ ╚██╔╝ ╚════██║
██║ ╚██████╔╝██║ ╚████║╚██████╔╝╚██████╔╝ ██║ ███████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
*/
import "@openzeppelin/contracts/access/Ownable.sol";
contract FunGuyData is Ownable {
bytes4[] public colors;
bytes3[] public backgroundColors;
bytes[] public baseData;
bytes[] public eyesData;
bytes[] public mouthData;
string[] public backgroundTraits;
string[] public baseTraits;
string[] public eyesTraits;
string[] public mouthTraits;
string[] public baseDescriptions;
constructor() Ownable(msg.sender) {}
function getColors() external view returns (bytes4[] memory) {
return colors;
}
function getBackgroundColors() external view returns (bytes3[] memory) {
return backgroundColors;
}
function getBaseData() external view returns (bytes[] memory, string[] memory) {
return (baseData, baseTraits);
}
function getEyesData() external view returns (bytes[] memory, string[] memory) {
return (eyesData, eyesTraits);
}
function getMouthData() external view returns (bytes[] memory, string[] memory) {
return (mouthData, mouthTraits);
}
function getTraitCounts() external view returns (
uint256 backgroundCount,
uint256 baseCount,
uint256 eyesCount,
uint256 mouthCount
) {
return (
backgroundColors.length,
baseData.length,
eyesData.length,
mouthData.length
);
}
function getTraitNames(
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view returns (
string memory background,
string memory base,
string memory eyes,
string memory mouth
) {
require(backgroundIndex < backgroundTraits.length, "Invalid background index");
require(baseIndex < baseTraits.length, "Invalid base index");
require(eyesIndex < eyesTraits.length, "Invalid eyes index");
require(mouthIndex < mouthTraits.length, "Invalid mouth index");
return (
backgroundTraits[backgroundIndex],
baseTraits[baseIndex],
eyesTraits[eyesIndex],
mouthTraits[mouthIndex]
);
}
function getBaseDescription(uint256 baseIndex) external view returns (string memory description) {
require(baseIndex < baseDescriptions.length, "Invalid base index");
return baseDescriptions[baseIndex];
}
function appendColors(bytes4[] calldata _colors) external onlyOwner {
for (uint256 i = 0; i < _colors.length; i++) {
colors.push(_colors[i]);
}
}
function appendBackgroundColors(bytes3[] calldata _colors) external onlyOwner {
for (uint256 i = 0; i < _colors.length; i++) {
backgroundColors.push(_colors[i]);
}
}
function appendBackgroundTraits(string[] calldata _traits) external onlyOwner {
for (uint256 i = 0; i < _traits.length; i++) {
backgroundTraits.push(_traits[i]);
}
}
function appendBaseData(bytes[] calldata _data, string[] calldata _traits) external onlyOwner {
require(_data.length == _traits.length, "Mismatched lengths");
for (uint256 i = 0; i < _data.length; i++) {
baseData.push(_data[i]);
baseTraits.push(_traits[i]);
}
}
function appendBaseDescriptions(string[] calldata _descriptions) external onlyOwner {
for (uint256 i = 0; i < _descriptions.length; i++) {
baseDescriptions.push(_descriptions[i]);
}
}
function appendEyesData(bytes[] calldata _data, string[] calldata _traits) external onlyOwner {
require(_data.length == _traits.length, "Mismatched lengths");
for (uint256 i = 0; i < _data.length; i++) {
eyesData.push(_data[i]);
eyesTraits.push(_traits[i]);
}
}
function appendMouthData(bytes[] calldata _data, string[] calldata _traits) external onlyOwner {
require(_data.length == _traits.length, "Mismatched lengths");
for (uint256 i = 0; i < _data.length; i++) {
mouthData.push(_data[i]);
mouthTraits.push(_traits[i]);
}
}
function clearAllData() external onlyOwner {
delete colors;
delete backgroundColors;
delete backgroundTraits;
delete baseData;
delete baseTraits;
delete baseDescriptions;
delete eyesData;
delete eyesTraits;
delete mouthData;
delete mouthTraits;
colors.push(bytes4(0x00000000));
}
function clearColors() external onlyOwner {
delete colors;
colors.push(bytes4(0x00000000));
}
function clearBackgrounds() external onlyOwner {
delete backgroundColors;
delete backgroundTraits;
}
function clearBaseData() external onlyOwner {
delete baseData;
delete baseTraits;
delete baseDescriptions;
}
function clearEyesData() external onlyOwner {
delete eyesData;
delete eyesTraits;
}
function clearMouthData() external onlyOwner {
delete mouthData;
delete mouthTraits;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
███████╗██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗███████╗
██╔════╝██║ ██║████╗ ██║██╔════╝ ██║ ██║╚██╗ ██╔╝██╔════╝
█████╗ ██║ ██║██╔██╗ ██║██║ ███╗██║ ██║ ╚████╔╝ ███████╗
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║ ╚██╔╝ ╚════██║
██║ ╚██████╔╝██║ ╚████║╚██████╔╝╚██████╔╝ ██║ ███████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
*/
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./IFunGuyRenderer.sol";
import "./FunGuyData.sol";
contract FunGuyRenderer is IFunGuyRenderer, Ownable {
using Strings for uint256;
FunGuyData public immutable dataContract;
constructor(address _dataContract) Ownable(msg.sender) {
dataContract = FunGuyData(_dataContract);
}
function _getTraitCounts() private view returns (
uint256 backgroundCount,
uint256 baseCount,
uint256 eyesCount,
uint256 mouthCount
) {
return dataContract.getTraitCounts();
}
function _validateTraitCounts() private view {
(uint256 backgroundCount, uint256 baseCount, uint256 eyesCount, uint256 mouthCount) = _getTraitCounts();
require(backgroundCount > 0, "Background data not set");
require(baseCount > 0, "Base data not set");
require(eyesCount > 0, "Eyes data not set");
require(mouthCount > 0, "Mouth data not set");
}
function getTraitIndicesFromSeed(uint256 seed) external view override returns (
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) {
_validateTraitCounts();
(uint256 backgroundCount, uint256 baseCount, uint256 eyesCount, uint256 mouthCount) = _getTraitCounts();
backgroundIndex = seed % backgroundCount;
baseIndex = (seed >> 1) % baseCount;
eyesIndex = uint256(keccak256(abi.encode(seed, "eyes"))) % eyesCount;
mouthIndex = uint256(keccak256(abi.encode(seed, "mouth"))) % mouthCount;
}
function getSVG(
uint256, /* seed */
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view override returns (string memory) {
(uint256 backgroundCount, uint256 baseCount, uint256 eyesCount, uint256 mouthCount) = _getTraitCounts();
require(backgroundIndex < backgroundCount && baseIndex < baseCount &&
eyesIndex < eyesCount && mouthIndex < mouthCount, "Invalid trait indices");
bytes3[] memory backgroundColors = dataContract.getBackgroundColors();
string memory backgroundHex = _bytes3ToHexString(backgroundColors[backgroundIndex]);
(bytes[] memory baseDataArray, ) = dataContract.getBaseData();
(bytes[] memory eyesDataArray, ) = dataContract.getEyesData();
(bytes[] memory mouthDataArray, ) = dataContract.getMouthData();
return string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="480" height="480" shape-rendering="crispEdges">',
'<rect width="24" height="24" fill="', backgroundHex, '"/>',
_renderLayer(baseDataArray[baseIndex]),
_renderLayer(mouthDataArray[mouthIndex]),
_renderLayer(eyesDataArray[eyesIndex]),
'</svg>'
));
}
function getTokenURI(
uint256 tokenId,
uint256 seed,
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view override returns (string memory) {
string memory svg = this.getSVG(seed, backgroundIndex, baseIndex, eyesIndex, mouthIndex);
string memory imageDataURI = string(abi.encodePacked(
"data:image/svg+xml;base64,",
Base64.encode(bytes(svg))
));
string memory attributes = this.getTraitsMetadata(backgroundIndex, baseIndex, eyesIndex, mouthIndex);
string memory nftDescription = dataContract.getBaseDescription(baseIndex);
string memory escapedDescription = _escapeJSON(nftDescription);
string memory json = Base64.encode(bytes(string(abi.encodePacked(
'{"name": "FunGuy #', tokenId.toString(), '",',
'"description": "', escapedDescription, '",',
'"image": "', imageDataURI, '",',
'"attributes": [', attributes, ']}'
))));
return string(abi.encodePacked("data:application/json;base64,", json));
}
function getTraitsMetadata(
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view override returns (string memory) {
(
string memory backgroundName,
string memory baseName,
string memory eyesName,
string memory mouthName
) = dataContract.getTraitNames(backgroundIndex, baseIndex, eyesIndex, mouthIndex);
return string(abi.encodePacked(
'{"trait_type": "Background", "value": "', backgroundName, '"},',
'{"trait_type": "Base", "value": "', baseName, '"},',
'{"trait_type": "Eyes", "value": "', eyesName, '"},',
'{"trait_type": "Mouth", "value": "', mouthName, '"}'
));
}
function _renderLayer(bytes memory data) private view returns (string memory) {
if (data.length == 0 || data.length % 4 != 0) return "";
return _processRLEData(data);
}
function _getCoordString(uint256 coord) private pure returns (string memory) {
if (coord == 0) return "0";
if (coord == 1) return "1";
if (coord == 2) return "2";
if (coord == 3) return "3";
if (coord == 4) return "4";
if (coord == 5) return "5";
if (coord == 6) return "6";
if (coord == 7) return "7";
if (coord == 8) return "8";
if (coord == 9) return "9";
if (coord == 10) return "10";
if (coord == 11) return "11";
if (coord == 12) return "12";
if (coord == 13) return "13";
if (coord == 14) return "14";
if (coord == 15) return "15";
if (coord == 16) return "16";
if (coord == 17) return "17";
if (coord == 18) return "18";
if (coord == 19) return "19";
if (coord == 20) return "20";
if (coord == 21) return "21";
if (coord == 22) return "22";
if (coord == 23) return "23";
return coord.toString();
}
function _processRLEData(bytes memory data) private view returns (string memory) {
if (data.length == 0 || data.length % 4 != 0) return "";
bytes4[] memory colors = dataContract.getColors();
string memory rects;
uint256 drawIndex = 0;
for (uint256 i = 0; i + 3 < data.length; i += 4) {
uint256 runLength = uint256(uint8(data[i])) | (uint256(uint8(data[i + 1])) << 8);
uint256 colorIndex = uint256(uint8(data[i + 2])) | (uint256(uint8(data[i + 3])) << 8);
if (colorIndex != 0 && colorIndex < colors.length && runLength > 0) {
(string memory colorHex, string memory opacityAttr) = _bytes4ToHexWithOpacity(colors[colorIndex]);
uint256 remaining = runLength;
uint256 currentPos = drawIndex;
while (remaining > 0 && currentPos < 576) {
uint256 y = currentPos / 24;
if (y >= 24) break;
uint256 x = currentPos % 24;
uint256 pixelsInRow = 24 - x;
uint256 pixelsToDraw = remaining < pixelsInRow ? remaining : pixelsInRow;
rects = string(abi.encodePacked(
rects,
'<rect width="', _getCoordString(pixelsToDraw),
'" height="1" x="', _getCoordString(x),
'" y="', _getCoordString(y),
'" fill="', colorHex, '"', opacityAttr,
'/>'
));
remaining -= pixelsToDraw;
currentPos += pixelsToDraw;
}
}
drawIndex += runLength;
}
return rects;
}
function _bytes4ToHexWithOpacity(bytes4 color) private pure returns (string memory colorHex, string memory opacityAttr) {
bytes memory hexChars = "0123456789abcdef";
bytes memory result = new bytes(7);
result[0] = '#';
for (uint256 i = 0; i < 3; i++) {
uint8 value = uint8(color[i]);
result[1 + i * 2] = hexChars[value >> 4];
result[2 + i * 2] = hexChars[value & 0x0f];
}
colorHex = string(result);
uint8 alpha = uint8(color[3]);
if (alpha < 255) {
uint256 alphaDecimal = (uint256(alpha) * 1000) / 255;
opacityAttr = string(abi.encodePacked(
' fill-opacity="0.',
_uint256ToFixedString(alphaDecimal, 3),
'"'
));
} else {
opacityAttr = "";
}
}
function _uint256ToFixedString(uint256 value, uint256 width) private pure returns (string memory) {
bytes memory result = new bytes(width);
for (uint256 i = width; i > 0; i--) {
result[i - 1] = bytes1(uint8(48 + (value % 10)));
value /= 10;
}
return string(result);
}
function _bytes3ToHexString(bytes3 color) private pure returns (string memory) {
bytes memory hexChars = "0123456789abcdef";
bytes memory result = new bytes(7);
result[0] = '#';
for (uint256 i = 0; i < 3; i++) {
uint8 value = uint8(color[i]);
result[1 + i * 2] = hexChars[value >> 4];
result[2 + i * 2] = hexChars[value & 0x0f];
}
return string(result);
}
function _escapeJSON(string memory str) private pure returns (string memory) {
bytes memory strBytes = bytes(str);
uint256 escapeCount = 0;
for (uint256 i = 0; i < strBytes.length; i++) {
bytes1 char = strBytes[i];
if (char == 0x0a || char == 0x0d || char == 0x09 || char == 0x22 || char == 0x5c) {
escapeCount++;
}
}
if (escapeCount == 0) {
return str;
}
bytes memory result = new bytes(strBytes.length + escapeCount);
uint256 resultIndex = 0;
for (uint256 i = 0; i < strBytes.length; i++) {
bytes1 char = strBytes[i];
if (char == 0x0a) {
result[resultIndex++] = 0x5c;
result[resultIndex++] = 0x6e;
} else if (char == 0x0d) {
result[resultIndex++] = 0x5c;
result[resultIndex++] = 0x72;
} else if (char == 0x09) {
result[resultIndex++] = 0x5c;
result[resultIndex++] = 0x74;
} else if (char == 0x22) {
result[resultIndex++] = 0x5c;
result[resultIndex++] = 0x22;
} else if (char == 0x5c) {
result[resultIndex++] = 0x5c;
result[resultIndex++] = 0x5c;
} else {
result[resultIndex++] = char;
}
}
return string(result);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
███████╗██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗███████╗
██╔════╝██║ ██║████╗ ██║██╔════╝ ██║ ██║╚██╗ ██╔╝██╔════╝
█████╗ ██║ ██║██╔██╗ ██║██║ ███╗██║ ██║ ╚████╔╝ ███████╗
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║ ╚██╔╝ ╚════██║
██║ ╚██████╔╝██║ ╚████║╚██████╔╝╚██████╔╝ ██║ ███████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
*/
interface IFunGuyRenderer {
function getSVG(
uint256 seed,
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view returns (string memory);
function getTokenURI(
uint256 tokenId,
uint256 seed,
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view returns (string memory);
function getTraitsMetadata(
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
) external view returns (string memory);
function getTraitIndicesFromSeed(uint256 seed) external view returns (
uint256 backgroundIndex,
uint256 baseIndex,
uint256 eyesIndex,
uint256 mouthIndex
);
}// 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);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_renderer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","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":"ReentrancyGuardReentrantCall","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":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTokenId","type":"uint256"}],"name":"Airdrop","type":"event"},{"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":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"metadata","type":"string"}],"name":"CustomMetadataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"CustomTokenMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingAllocation","type":"uint256"}],"name":"OGMint","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":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingAllocation","type":"uint256"}],"name":"PFPBonusMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"PFPPromiseMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRenderer","type":"address"},{"indexed":true,"internalType":"address","name":"newRenderer","type":"address"}],"name":"RendererUpdated","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":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"quantities","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","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":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"customMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"customNftRange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstRegularTokenId","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":"address","name":"owner","type":"address"}],"name":"getOwnedTokens","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"getTraitIndices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","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":"uint256","name":"","type":"uint256"}],"name":"isCustomToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"string","name":"metadata","type":"string"}],"name":"mintCustomToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"maxOGAllocation","type":"uint256"},{"internalType":"bool","name":"hasPFPPromise","type":"bool"}],"name":"mintWithSignature","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintingOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ogAllocationUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pfpAllocationUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pfpPromiseMade","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"regularMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"contract IFunGuyRenderer","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":"uint256","name":"","type":"uint256"}],"name":"seeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"metadata","type":"string"}],"name":"setCustomMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"open","type":"bool"}],"name":"setMintingOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"newPayees","type":"address[]"},{"internalType":"uint256[]","name":"newShares","type":"uint256[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRenderer","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"setSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"transferCustomToken","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":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"usedCombinations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234620002345762003c1180380390816200001e816200026f565b92839283396020928391810103126200023457516001600160a01b038116919082900362000234576200005062000295565b906f4f6e2d436861696e2046756e4775797360801b8183015262000073620002a6565b6546554e47555960d01b82820152825190916001600160401b0382116200022e57620000ac82620000a6600254620002b7565b620002f4565b80601f83116001146200019957508190620000e5946000926200018d575b50508160011b916000199060031b1c191617600255620003a6565b620000f06001600055565b331562000174576200016490620001073362000499565b620001126001600a55565b6200012260ff19600b5416600b55565b600b8054610100600160a81b0319163360081b610100600160a81b0316179055600c80546001600160a01b0319166001600160a01b0392909216919091179055565b60405161372e9081620004e38239f35b604051631e4fbdf760e01b815260006004820152602490fd5b015190503880620000ca565b60026000529293919291601f1984167f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace936000905b82821062000215575050916001939185620000e597969410620001fb575b505050811b01600255620003a6565b015160001960f88460031b161c19169055388080620001ec565b80600186978294978701518155019601940190620001ce565b62000239565b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b038111838210176200022e57604052565b6040519190601f01601f191682016001600160401b038111838210176200022e57604052565b6200029f6200024f565b9060108252565b620002b06200024f565b9060068252565b90600182811c92168015620002e9575b6020831014620002d357565b634e487b7160e01b600052602260045260246000fd5b91607f1691620002c7565b601f811162000301575050565b6000906002825260208220906020601f850160051c8301941062000342575b601f0160051c01915b8281106200033657505050565b81815560010162000329565b909250829062000320565b601f81116200035a575050565b6000906003825260208220906020601f850160051c830194106200039b575b601f0160051c01915b8281106200038f57505050565b81815560010162000382565b909250829062000379565b80519091906001600160401b0381116200022e57620003d281620003cc600354620002b7565b6200034d565b602080601f831160011462000411575081929360009262000405575b50508160011b916000199060031b1c191617600355565b015190503880620003ee565b6003600052601f198316949091907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b926000905b8782106200048057505083600195961062000466575b505050811b01600355565b015160001960f88460031b161c191690553880806200045b565b8060018596829496860151815501950193019062000445565b600980546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a356fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610307578063046dc1661461030257806304e05008146102fd57806306fdde03146102f8578063081812fc146102f3578063095ea7b3146102ee5780631199d298146102e957806318160ddd146102e457806323b872dd146102df57806324de93c3146102da578063296f303a146102d55780633ccfd60b146102d057806342842e0e146102cb57806349bc4aed146102c657806356d3163d146102c157806357a858fc146102bc5780635b7633d0146102b757806363037b0c146102b25780636352211e146102ad57806367243482146102a85780636aa1b09e146102a357806370a082311461029e578063715018a61461029957806371e2e87f14610294578063726d45291461028f578063814249181461028a5780638954409e146102855780638ada6b0f146102805780638da5cb5b1461027b5780638e046f88146102765780638f4bb4971461027157806392f649741461026c578063938e3d7b1461026757806395d89b4114610262578063a22cb4651461025d578063a29d4cc914610258578063b033caf114610253578063b88d4fde1461024e578063bcc7445f14610249578063c87b56dd14610244578063d5abeb011461023f578063d9d616551461023a578063e8a3d48514610235578063e985e9c514610230578063ebdffcd11461022b578063f0503e80146102265763f2fde38b1461022157600080fd5b611f3e565b611f12565b611d91565b611d29565b611c82565b611c4e565b611bf6565b611bd7565b611b2c565b611a55565b6119ca565b61198d565b6118fb565b611854565b61173a565b611709565b6116e6565b6116ca565b61164f565b611626565b611496565b611324565b610f79565b610f21565b610ec3565b610e9c565b610e78565b610cab565b610c4c565b610c03565b610bd6565b610b97565b610ac4565b610a93565b610a70565b61098d565b610950565b61090e565b6108fa565b6108a6565b610866565b610675565b610622565b61053d565b6103ee565b6103a2565b610323565b6001600160e01b031981160361031e57565b600080fd5b3461031e57602036600319011261031e5760206004356103428161030c565b63ffffffff60e01b166301ffc9a760e01b8114908115610380575b811561036f575b506040519015158152f35b635b5e139f60e01b14905038610364565b6380ac58cd60e01b8114915061035d565b6001600160a01b0381160361031e57565b3461031e57602036600319011261031e576004356103bf81610391565b6103c7611fd0565b600b8054610100600160a81b03191660089290921b610100600160a81b0316919091179055005b3461031e57604036600319011261031e5760043560243561040e81610391565b610416611fd0565b6014821115806104cf575b61042a90612bcb565b61043b610436836131dd565b612631565b600091808352601360205261045660ff604085205416612c2f565b61047161046561046583613145565b6001600160a01b031690565b6001600160a01b0381811693839161048a861515612c70565b81168095036104be575b5050507f4343032d0e158cfdf15c64bd447a9509447b9509e93b2c68a6d422fc2deebdb18380a380f35b6104c7926133ca565b388181610494565b506001600160a01b0381161515610421565b60005b8381106104f45750506000910152565b81810151838201526020016104e4565b9060209161051d815180928185528580860191016104e1565b601f01601f1916010190565b90602061053a928181520190610504565b90565b3461031e5760008060031936011261061f5760405190806002546105608161072f565b808552916001918083169081156105f5575060011461059a575b6105968561058a8187038261079f565b60405191829182610529565b0390f35b9250600283527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8284106105dd57505050810160200161058a8261059661057a565b805460208587018101919091529093019281016105c2565b8695506105969693506020925061058a94915060ff191682840152151560051b820101929361057a565b80fd5b3461031e57602036600319011261031e5760043561063f816131dd565b15610664576000526006602052602060018060a01b0360406000205416604051908152f35b6333d1c03960e21b60005260046000fd5b604036600319011261031e5760043561068d81610391565b6024356001600160a01b03806106a283613145565b16908133036106fd575b600083815260066020526040812080546001600160a01b0319166001600160a01b0387161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b600082815260076020908152604080832033845290915290205460ff166106ac576367d9dca160e11b60005260046000fd5b90600182811c9216801561075f575b602083101461074957565b634e487b7160e01b600052602260045260246000fd5b91607f169161073e565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b0382111761079a57604052565b610769565b90601f801991011681019081106001600160401b0382111761079a57604052565b90604051918260008254926107d48461072f565b9081845260019485811690816000146108435750600114610800575b50506107fe9250038361079f565b565b9093915060005260209081600020936000915b81831061082b5750506107fe935082010138806107f0565b85548884018501529485019487945091830191610813565b9150506107fe94506020925060ff191682840152151560051b82010138806107f0565b3461031e57602036600319011261031e57600435600052601260205261059661089260406000206107c0565b604051918291602083526020830190610504565b3461031e57600036600319011261031e5760005460015460209103600019015b604051908152f35b606090600319011261031e576004356108e681610391565b906024356108f381610391565b9060443590565b61090c610906366108ce565b91613245565b005b3461031e57602036600319011261031e5760043561092b81610391565b60018060a01b03166000526011602052602060ff604060002054166040519015158152f35b3461031e57602036600319011261031e5760043561096d81610391565b60018060a01b0316600052600f6020526020604060002054604051908152f35b3461031e5760008060031936011261061f576109a7611fd0565b478015610a3457815b601554811015610a305780610a26848080806109ef6109e76109e16109d7610a2b9a610b48565b90549060031b1c90565b8a6121af565b612710900490565b610a16610465610465610a018a610b72565b905460039190911b1c6001600160a01b031690565b5af1610a2061309d565b506130cd565b612205565b6109b0565b8280f35b60405162461bcd60e51b81526020600482015260146024820152734e6f2066756e647320746f20776974686472617760601b6044820152606490fd5b61090c610a7c366108ce565b9060405192610a8a8461077f565b600084526133dd565b3461031e57602036600319011261031e57600435600052600e602052602060ff604060002054166040519015158152f35b3461031e57602036600319011261031e57600435610ae181610391565b610ae9611fd0565b600c80546001600160a01b039283166001600160a01b0319821681179092559091167f10e9b6d73105db46c6a41a698f35efb8e1688178fe274b7b21f0bdc792de3ea5600080a3005b634e487b7160e01b600052603260045260246000fd5b601654811015610b6d5760166000526000805160206136d98339815191520190600090565b610b32565b601554811015610b6d5760156000526000805160206136b98339815191520190600090565b3461031e57602036600319011261031e5760043560165481101561031e5760209060166000526000805160206136d98339815191520154604051908152f35b3461031e57600036600319011261031e57600b5460405160089190911c6001600160a01b03168152602090f35b3461031e57602036600319011261031e5760043560155481101561031e5760156000526000805160206136b983398151915201546040516001600160a01b039091168152602090f35b3461031e57602036600319011261031e5760206001600160a01b03610c72600435613145565b16604051908152f35b9181601f8401121561031e578235916001600160401b03831161031e576020808501948460051b01011161031e57565b3461031e5760408060031936011261031e576001600160401b0360043581811161031e57610cdd903690600401610c7b565b909160243590811161031e57610cf7903690600401610c7b565b929091610d02611fd0565b610d0d848214612ec2565b610d18811515612f0e565b6000805b858110610e2257506108ae610d3a610d4192600019600054016116bd565b111561207d565b60005b818110610d4d57005b610d60610d5b828486612899565b612fa6565b610d6b828787612899565b60005460015491359291610d8891036000190161168e565b61168e565b9060005b838110610deb5750829181610dc6610de696957fada993ad066837289fe186cd37227aa338d27519a8a1547472ecb9831486d272946135bd565b8a5193845260208401919091526001600160a01b031691604090a2612205565b610d44565b80610df9610e1d92856116bd565b610e17610e068583612482565b91600052600d602052604060002090565b55612205565b610d8c565b90610e6d610e7391610e40610e38858a8a612899565b351515612f5a565b610e5b610e54610465610d5b87898b612899565b1515612fb0565b610e66848989612899565b35906116bd565b91612205565b610d1c565b3461031e57600036600319011261031e576020604051680ad78ebc5ac62000008152f35b3461031e57602036600319011261031e5760206108c6600435610ebe81610391565b61310b565b3461031e5760008060031936011261061f57610edd611fd0565b600980546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b3461031e57600036600319011261031e57602060405160148152f35b9181601f8401121561031e578235916001600160401b03831161031e576020838186019501011161031e57565b60643590811515820361031e57565b608036600319011261031e576004356001600160401b03811161031e57610fa4903690600401610f3d565b906024359160443590610fb5610f6a565b6002600a5414611312576110c76110da926002600a556110af600b5491610fde60ff8416611ffc565b88151580611307575b610ff09061203e565b6110a960009861100c6108ae610d3a8d8d6000199054016116bd565b6000546001546110269160149190036000190110156120c9565b6040516bffffffffffffffffffffffff193360601b1660208201908152603482018d9052605482018b905288151560f81b6074830152605582526110a19161106f60758261079f565b5190207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c60002090565b923691611a1e565b9061224a565b6001600160a01b0390811660089290921c161461213b565b6110d28184876123cd565b93909361217b565b936110e7853410156121c2565b811515806112e6575b84151593846112c5575b8061129c575b611251575b60005460015461111991036000190161168e565b97875b818110611231575087985061113190336135bd565b6111e8575b5050611186575b50803411611154575b506111516001600a55565b80f35b8180611161819334612231565b81811561117d575b3390f115611178578038611146565b61223e565b506108fc611169565b3360009081526010602052604090207f83a1aaa194b8a77a08f581bb99db83951c1abac5453c3af420106c9173b8dc26906111df906111c6905b54612214565b6040805194855260208501919091523393918291820190565b0390a23861113d565b336000908152600f60205260409020547f86dae78951b4501244f6f1ab999fe0d86921c0df304204186c4bb2553092a26e91611227916111c691612231565b0390a23880611136565b8061123f61124c928c6116bd565b610e17610e063383612482565b61111c565b336000908152601160205260409020611272905b805460ff19166001179055565b337fac9518c6c2eb95c17373d9e7a5a53216b31da728efa73bc5a79331bba20dd25d8880a2611105565b503360009081526011602052604090206112c0906112bc905b5460ff1690565b1590565b611100565b3360009081526010602052604090206112df8782546116bd565b90556110fa565b336000908152600f602052604090206113008482546116bd565b90556110f0565b50600a891115610fe7565b604051633ee5aeb560e01b8152600490fd5b3461031e57606036600319011261031e5760043560243561134481610391565b6044356001600160401b03811161031e5761136661144b913690600401610f3d565b9061136f611fd0565b60018510158061148b575b611383906128bd565b6113976113926112bc876131dd565b612909565b6113a2821515612955565b6000546001546113bb9160149190036000190110612995565b6000546001546113d091036000190186612231565b600181111561147c576009546113fa91906113f4906001600160a01b031691612222565b906135bd565b611403846134f3565b60005460015461141b91879190036000190114612a07565b611432611265866000526013602052604060002090565b611446856000526012602052604060002090565b612b04565b6001600160a01b0316907f4343032d0e158cfdf15c64bd447a9509447b9509e93b2c68a6d422fc2deebdb1600080a3005b50611486846134f3565b611403565b50601485111561137a565b3461031e57604036600319011261031e576001600160401b0360043560243582811161031e576114ca903690600401610f3d565b6114d5929192611fd0565b60148211158061161d575b6114e990612bcb565b6114f5610436836131dd565b600092828452602094601286526040852090831161079a576115218361151b835461072f565b83612aca565b8495601f841160011461158f57508285967f8d8eae0e5345d1c16ad28df8a9b7877bef40718a2cbd7e162849853175715540959691611584575b508360011b906000198560031b1c19161790555b61157e60405192839283612c07565b0390a280f35b90508201353861155b565b601f198416966115a483600052602060002090565b9187905b898210611605575050847f8d8eae0e5345d1c16ad28df8a9b7877bef40718a2cbd7e162849853175715540969798106115eb575b5050600183811b01905561156f565b830135600019600386901b60f8161c1916905538806115dc565b806001849582949589013581550194019201906115a8565b508015156114e0565b3461031e57600036600319011261031e57600c546040516001600160a01b039091168152602090f35b3461031e57600036600319011261031e576009546040516001600160a01b039091168152602090f35b634e487b7160e01b600052601160045260246000fd5b906001820180921161169c57565b611678565b906002820180921161169c57565b906003820180921161169c57565b9190820180921161169c57565b3461031e57600036600319011261031e57602060405160158152f35b3461031e57600036600319011261031e57602060ff600b54166040519015158152f35b3461031e57602036600319011261031e576004356000526013602052602060ff604060002054166040519015158152f35b3461031e5760208060031936011261031e576001600160401b0360043581811161031e5761176c903690600401610f3d565b91611775611fd0565b821161079a5761178f8261178a60145461072f565b612a69565b600092601f83116001146117cd57509181926000926117c2575b5050600019600383901b1c191660019190911b17601455005b0135905038806117a9565b90601f1983169361180060146000527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec90565b9281905b86821061183c5750508360019510611822575b505050811b01601455005b0135600019600384901b60f8161c19169055388080611817565b80600184968294958701358155019501920190611804565b3461031e5760008060031936011261061f5760405190806003546118778161072f565b808552916001918083169081156105f557506001146118a0576105968561058a8187038261079f565b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8284106118e357505050810160200161058a8261059661057a565b805460208587018101919091529093019281016118c8565b3461031e57604036600319011261031e5760043561191881610391565b6024359081151580920361031e573360009081526007602090815260408083206001600160a01b0385168452909152902060ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b3461031e57602036600319011261031e576004356119aa81610391565b60018060a01b031660005260106020526020604060002054604051908152f35b3461031e57602036600319011261031e5760043580151580910361031e576119f0611fd0565b60ff8019600b5416911617600b55600080f35b6001600160401b03811161079a57601f01601f191660200190565b929192611a2a82611a03565b91611a38604051938461079f565b82948184528183011161031e578281602093846000960137010152565b608036600319011261031e57600435611a6d81610391565b602435611a7981610391565b606435916001600160401b03831161031e573660238401121561031e57611aad61090c933690602481600401359101611a1e565b91604435916133dd565b6001600160401b03811161079a5760051b60200190565b81601f8201121561031e57803591611ae583611ab7565b92611af3604051948561079f565b808452602092838086019260051b82010192831161031e578301905b828210611b1d575050505090565b81358152908301908301611b0f565b3461031e57604036600319011261031e576001600160401b0360043581811161031e573660238201121561031e578060040135611b6881611ab7565b91611b76604051938461079f565b81835260209160248385019160051b8301019136831161031e57602401905b828210611bbe576024358587821161031e57611bb861090c923690600401611ace565b90612cae565b8380918335611bcc81610391565b815201910190611b95565b3461031e57602036600319011261031e576105966108926004356126ef565b3461031e57600036600319011261031e5760206040516108ae8152f35b6020908160408183019282815285518094520193019160005b828110611c3a575050505090565b835185529381019392810192600101611c2c565b3461031e57602036600319011261031e57610596611c76600435611c7181610391565b612ffc565b60405191829182611c13565b3461031e5760008060031936011261061f576040519080601454611ca58161072f565b808552916001918083169081156105f55750600114611cce576105968561058a8187038261079f565b9250601483527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec5b828410611d1157505050810160200161058a8261059661057a565b80546020858701810191909152909301928101611cf6565b3461031e57604036600319011261031e57602060ff611d85600435611d4d81610391565b60243590611d5a82610391565b60018060a01b03166000526007845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461031e57602036600319011261031e57600480356001600160401b03811161031e57611dc19036908301610c7b565b9190611dd4611dcf84612199565b612867565b600c5460009491939190611df0906001600160a01b0316610465565b945b818110611e0757604051806105968782611c13565b611e32611e15828487612899565b35611e22610436826131dd565b600052600d602052604060002090565b5460405163188cd00360e01b8152848101918252919060809081908490819060200103818b5afa90811561117857611ed7936000809181938295611edc575b5050611e85611e7f86612199565b8b6128a9565b52611e9b611e95610d8386612199565b8a6128a9565b52611eb6611eb0611eab85612199565b6116a1565b896128a9565b52611ed1611ecb611ec684612199565b6116af565b886128a9565b52612205565b611df2565b9250925050611f009250803d10611f0b575b611ef8818361079f565b810190612460565b919091923880611e71565b503d611eee565b3461031e57602036600319011261031e57600435600052600d6020526020604060002054604051908152f35b3461031e57602036600319011261031e57600435611f5b81610391565b611f63611fd0565b6001600160a01b03908116908115611fb757600954826bffffffffffffffffffffffff60a01b821617600955167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b604051631e4fbdf760e01b815260006004820152602490fd5b6009546001600160a01b03163303611fe457565b60405163118cdaa760e01b8152336004820152602490fd5b1561200357565b60405162461bcd60e51b815260206004820152601360248201527226b4b73a34b7339034b9903737ba1037b832b760691b6044820152606490fd5b1561204557565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964207175616e7469747960801b6044820152606490fd5b1561208457565b60405162461bcd60e51b815260206004820152601760248201527f576f756c6420657863656564206d617820737570706c790000000000000000006044820152606490fd5b156120d057565b60405162461bcd60e51b815260206004820152603a60248201527f437573746f6d20746f6b656e73206d757374206265206d696e7465642062656660448201527f6f726520726567756c6172206d696e74696e6720626567696e730000000000006064820152608490fd5b1561214257565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b90680ad78ebc5ac62000009182810292818404149015171561169c57565b908160021b918083046004149015171561169c57565b8181029291811591840414171561169c57565b156121c957565b60405162461bcd60e51b8152602060048201526014602482015273125b9cdd59999a58da595b9d081c185e5b595b9d60621b6044820152606490fd5b600019811461169c5760010190565b600103906001821161169c57565b60001981019190821161169c57565b9190820391821161169c57565b6040513d6000823e3d90fd5b61053a9161225791612260565b90929192612340565b81519190604183036122915761228a92506020820151906060604084015193015160001a9061229c565b9192909190565b505060009160029190565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161231457926020929160ff608095604051948552168484015260408301526060820152600092839182805260015afa156111785780516001600160a01b0381161561230b57918190565b50809160019190565b50505060009160039190565b6004111561232a57565b634e487b7160e01b600052602160045260246000fd5b61234981612320565b80612352575050565b61235b81612320565b600181036123755760405163f645eedf60e01b8152600490fd5b61237e81612320565b6002810361239f5760405163fce698f760e01b815260048101839052602490fd5b806123ab600392612320565b146123b35750565b6040516335e2f38360e21b81526004810191909152602490fd5b9290919260009233600052600f602052604060002054810390811161169c578082101561245b5750805b80948183039183831161169c57829382612450575b5050612416575090565b33600090815260106020526040902090935061243291506111c0565b8083101561244a5750815b82810390811161169c5790565b9161243d565b14159050388061240c565b6123f7565b919082608091031261031e578151916020810151916060604083015192015190565b9060005b603281106124e15760405162461bcd60e51b815260206004820152602560248201527f556e61626c6520746f2067656e657261746520756e6971756520636f6d62696e60448201526430ba34b7b760d91b6064820152608490fd5b604080514260208083019182524483850152606086811b6bffffffffffffffffffffffff1916908401526074830187905260948084018690528352601f19939290919061252f60b48261079f565b519020600c5490939061254a906001600160a01b0316610465565b835163188cd00360e01b81526004810186905292608092918390859060249082905afa80156111785760009485948692612602575b50506125a8906125b4949596519586938401978891606093918352602083015260408201520190565b0390810183528261079f565b5190206125d16112bc6112b583600052600e602052604060002090565b6125e55750506125e090612205565b612486565b90935061053a92506112659150600052600e602052604060002090565b6125a896506125b495506126229250803d10611f0b57611ef8818361079f565b9196909550909150869061257f565b1561263857565b60405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606490fd5b61053a905461072f565b6040519061268b8261077f565b60008252565b60208183031261031e578051906001600160401b03821161031e570181601f8201121561031e5780516126c381611a03565b926126d1604051948561079f565b8184526020828401011161031e5761053a91602080850191016104e1565b6126fb610436826131dd565b601481111561280a5761271881600052600d602052604060002090565b54600c5461272e906001600160a01b0316610465565b60405163188cd00360e01b8152600481018390529190608083602481845afa918215611178576000928394849085926127da575b5060405163334a8b6360e01b81526004810197909752602487019290925260448601939093526064850193909352608484019290925260a48301526000908290818060c481015b03915afa908115611178576000916127bf575090565b61053a913d8091833e6127d2818361079f565b810190612691565b9050600095506127a994506127fd915060803d8111611f0b57611ef8818361079f565b9196509194909190612762565b612813816131dd565b80612843575b1561283a5761283561053a916000526012602052604060002090565b6107c0565b5061053a61267e565b5061286061285b826000526012602052604060002090565b612674565b1515612819565b9061287182611ab7565b61287e604051918261079f565b828152809261288f601f1991611ab7565b0190602036910137565b9190811015610b6d5760051b0190565b8051821015610b6d5760209160051b010190565b156128c457565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420637573746f6d20746f6b656e2049440000000000000000006044820152606490fd5b1561291057565b60405162461bcd60e51b815260206004820152601b60248201527f437573746f6d20746f6b656e20616c7265616479206d696e74656400000000006044820152606490fd5b1561295c57565b60405162461bcd60e51b815260206004820152601160248201527013595d1859185d18481c995c5d5a5c9959607a1b6044820152606490fd5b1561299c57565b60405162461bcd60e51b815260206004820152603760248201527f437573746f6d20746f6b656e2072616e6765206578636565646564202d20726560448201527f67756c6172206d696e74696e672068617320626567756e0000000000000000006064820152608490fd5b15612a0e57565b606460405162461bcd60e51b815260206004820152602060248201527f546f6b656e204944206d69736d6174636820647572696e67206d696e74696e676044820152fd5b818110612a5d575050565b60008155600101612a52565b90601f8211612a76575050565b6107fe9160146000527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec906020601f840160051c83019310612ac0575b601f0160051c0190612a52565b9091508190612ab3565b9190601f8111612ad957505050565b6107fe926000526020600020906020601f840160051c83019310612ac057601f0160051c0190612a52565b9092916001600160401b03811161079a57612b2981612b23845461072f565b84612aca565b6000601f8211600114612b635781929394600092612b58575b50508160011b916000199060031b1c1916179055565b013590503880612b42565b601f19821694612b7884600052602060002090565b91805b878110612bb3575083600195969710612b99575b505050811b019055565b0135600019600384901b60f8161c19169055388080612b8f565b90926020600181928686013581550194019101612b7b565b15612bd257565b60405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606490fd5b90918060409360208452816020850152848401376000828201840152601f01601f1916010190565b15612c3657565b60405162461bcd60e51b81526020600482015260126024820152712737ba10309031bab9ba37b6903a37b5b2b760711b6044820152606490fd5b15612c7757565b60405162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd081bdddb9959608a1b6044820152606490fd5b90612cb7611fd0565b8151815103612d1357600092835b8251851015612cf257612cd885846128a9565b51810180911161169c57612cec9094612205565b93612cc5565b612d0e91945092612d096127106107fe9514612d4d565b612da3565b612e37565b60405162461bcd60e51b81526020600482015260126024820152714d69736d617463686564206c656e6774687360701b6044820152606490fd5b15612d5457565b60405162461bcd60e51b815260206004820152602160248201527f546f74616c20736861726573206d7573742062652031303030302028313030256044820152602960f81b6064820152608490fd5b8051906001600160401b03821161079a57600160401b821161079a5760155482601555808310612e13575b50602080910190601560005260005b838110612dea5750505050565b82516001600160a01b03166000805160206136b983398151915282015591810191600101612ddd565b612e3190836000805160206136b98339815191529182019101612a52565b38612dce565b8051906001600160401b03821161079a57600160401b821161079a5760165482601655808310612e9e575b50602080910190601660005260005b838110612e7e5750505050565b82516000805160206136d983398151915282015591810191600101612e71565b612ebc90836000805160206136d98339815191529182019101612a52565b38612e62565b15612ec957565b60405162461bcd60e51b815260206004820152601860248201527f4d69736d617463686564206172726179206c656e6774687300000000000000006044820152606490fd5b15612f1557565b60405162461bcd60e51b815260206004820152601760248201527f4e6f20726563697069656e7473207370656369666965640000000000000000006044820152606490fd5b15612f6157565b60405162461bcd60e51b815260206004820152601f60248201527f5175616e74697479206d7573742062652067726561746572207468616e2030006044820152606490fd5b3561053a81610391565b15612fb757565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c696420726563697069656e742061646472657373000000000000006044820152606490fd5b6130058161310b565b80156130835761301481612867565b6000546001549192919003600019019260009060015b8581111561303c575b50505050905090565b6001600160a01b038061304e83613145565b1690831614613066575b61306190612205565b61302a565b918083611ed161307693886128a9565b9183830361305857613033565b50506040516130918161077f565b60008152600036813790565b3d156130c8573d906130ae82611a03565b916130bc604051938461079f565b82523d6000602084013e565b606090565b156130d457565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b6001600160a01b031680156131345760005260056020526001600160401b036040600020541690565b6323d3ad8160e21b60005260046000fd5b6001908082116131cc57613163816000526004602052604060002090565b54918215613180575b5050600160e01b81161561053a57806131cc565b6000548210156131cc5790815b1561316c57909150600019016131ad816000526004602052604060002090565b549182156131c5575050600160e01b81166131cc5790565b908161318d565b636f96cda160e11b60005260046000fd5b6000919060019083818311156131f257505050565b805482106131ff57505050565b9293509082815b613218575b505050600160e01b161590565b82815260046020526040812054935090918361324057801561169c5760001901919081613206565b61320b565b91909161325182613145565b6001600160a01b03918216939091908183168590036133c557600084815260066020526040902080546132936001600160a01b03881633908114908314171590565b61337e575b613374575b506001600160a01b0385811660009081526005602090815260408083208054600019019055928416825282822080546001019055868252600490522091169384929091600160e11b904260a01b85178217905581161561332a575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a41561332557565b6136a7565b60018401613342816000526004602052604060002090565b541561334f575b506132f8565b60005481146133495761336c906000526004602052604060002090565b553880613349565b600090553861329d565b6133bb6112bc6112b5336133a48b60018060a01b03166000526007602052604060002090565b9060018060a01b0316600052602052604060002090565b1561329857613696565b613686565b90916107fe9260405192610a8a8461077f565b9291906133eb828286613245565b803b6133f8575b50505050565b61340193613435565b1561340f57388080806133f2565b6368d2bf6b60e11b60005260046000fd5b9081602091031261031e575161053a8161030c565b604051630a85bd0160e11b8082523360048301526001600160a01b03928316602483015260448201949094526080606482015292936020928492909183916000918390613486906084830190610504565b0393165af1600091816134c3575b506134b5576134a161309d565b8051156134b057805190602001fd5b61340f565b6001600160e01b0319161490565b6134e591925060203d81116134ec575b6134dd818361079f565b810190613420565b9038613494565b503d6134d3565b6000805480825260046020526040822090926001600160a01b0381169161353e91904260a01b8417600160e11b17905b556001600160a01b0316600090815260056020526040902090565b68010000000000000001815401905580156135af57600190818401939180805b61356a575b5050505055565b1561359e575b83818484877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461355e565b809201918483036135705780613563565b622e076360e81b8252600482fd5b906000908154928115613677576001916135fb60018060a01b0383169284831460e11b4260a01b178417613523886000526004602052604060002090565b68010000000000000001820281540190558115613669578401939180805b613624575050505055565b15613658575b83818484877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4613619565b8092019184830361362a5780613563565b622e076360e81b8452600484fd5b63b562e8dd60e01b8352600483fd5b62a1148160e81b60005260046000fd5b632ce44b5f60e11b60005260046000fd5b633a954ecd60e21b60005260046000fdfe55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475d833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289a2646970667358221220b4fd48d62fbc617c44ce101d601c0483a3042441a5acf5367aff0e229a62446e64736f6c634300081400330000000000000000000000002897ab218b4e598c1aa5bdb819a2416c4adf9c46
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610307578063046dc1661461030257806304e05008146102fd57806306fdde03146102f8578063081812fc146102f3578063095ea7b3146102ee5780631199d298146102e957806318160ddd146102e457806323b872dd146102df57806324de93c3146102da578063296f303a146102d55780633ccfd60b146102d057806342842e0e146102cb57806349bc4aed146102c657806356d3163d146102c157806357a858fc146102bc5780635b7633d0146102b757806363037b0c146102b25780636352211e146102ad57806367243482146102a85780636aa1b09e146102a357806370a082311461029e578063715018a61461029957806371e2e87f14610294578063726d45291461028f578063814249181461028a5780638954409e146102855780638ada6b0f146102805780638da5cb5b1461027b5780638e046f88146102765780638f4bb4971461027157806392f649741461026c578063938e3d7b1461026757806395d89b4114610262578063a22cb4651461025d578063a29d4cc914610258578063b033caf114610253578063b88d4fde1461024e578063bcc7445f14610249578063c87b56dd14610244578063d5abeb011461023f578063d9d616551461023a578063e8a3d48514610235578063e985e9c514610230578063ebdffcd11461022b578063f0503e80146102265763f2fde38b1461022157600080fd5b611f3e565b611f12565b611d91565b611d29565b611c82565b611c4e565b611bf6565b611bd7565b611b2c565b611a55565b6119ca565b61198d565b6118fb565b611854565b61173a565b611709565b6116e6565b6116ca565b61164f565b611626565b611496565b611324565b610f79565b610f21565b610ec3565b610e9c565b610e78565b610cab565b610c4c565b610c03565b610bd6565b610b97565b610ac4565b610a93565b610a70565b61098d565b610950565b61090e565b6108fa565b6108a6565b610866565b610675565b610622565b61053d565b6103ee565b6103a2565b610323565b6001600160e01b031981160361031e57565b600080fd5b3461031e57602036600319011261031e5760206004356103428161030c565b63ffffffff60e01b166301ffc9a760e01b8114908115610380575b811561036f575b506040519015158152f35b635b5e139f60e01b14905038610364565b6380ac58cd60e01b8114915061035d565b6001600160a01b0381160361031e57565b3461031e57602036600319011261031e576004356103bf81610391565b6103c7611fd0565b600b8054610100600160a81b03191660089290921b610100600160a81b0316919091179055005b3461031e57604036600319011261031e5760043560243561040e81610391565b610416611fd0565b6014821115806104cf575b61042a90612bcb565b61043b610436836131dd565b612631565b600091808352601360205261045660ff604085205416612c2f565b61047161046561046583613145565b6001600160a01b031690565b6001600160a01b0381811693839161048a861515612c70565b81168095036104be575b5050507f4343032d0e158cfdf15c64bd447a9509447b9509e93b2c68a6d422fc2deebdb18380a380f35b6104c7926133ca565b388181610494565b506001600160a01b0381161515610421565b60005b8381106104f45750506000910152565b81810151838201526020016104e4565b9060209161051d815180928185528580860191016104e1565b601f01601f1916010190565b90602061053a928181520190610504565b90565b3461031e5760008060031936011261061f5760405190806002546105608161072f565b808552916001918083169081156105f5575060011461059a575b6105968561058a8187038261079f565b60405191829182610529565b0390f35b9250600283527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8284106105dd57505050810160200161058a8261059661057a565b805460208587018101919091529093019281016105c2565b8695506105969693506020925061058a94915060ff191682840152151560051b820101929361057a565b80fd5b3461031e57602036600319011261031e5760043561063f816131dd565b15610664576000526006602052602060018060a01b0360406000205416604051908152f35b6333d1c03960e21b60005260046000fd5b604036600319011261031e5760043561068d81610391565b6024356001600160a01b03806106a283613145565b16908133036106fd575b600083815260066020526040812080546001600160a01b0319166001600160a01b0387161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b600082815260076020908152604080832033845290915290205460ff166106ac576367d9dca160e11b60005260046000fd5b90600182811c9216801561075f575b602083101461074957565b634e487b7160e01b600052602260045260246000fd5b91607f169161073e565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b0382111761079a57604052565b610769565b90601f801991011681019081106001600160401b0382111761079a57604052565b90604051918260008254926107d48461072f565b9081845260019485811690816000146108435750600114610800575b50506107fe9250038361079f565b565b9093915060005260209081600020936000915b81831061082b5750506107fe935082010138806107f0565b85548884018501529485019487945091830191610813565b9150506107fe94506020925060ff191682840152151560051b82010138806107f0565b3461031e57602036600319011261031e57600435600052601260205261059661089260406000206107c0565b604051918291602083526020830190610504565b3461031e57600036600319011261031e5760005460015460209103600019015b604051908152f35b606090600319011261031e576004356108e681610391565b906024356108f381610391565b9060443590565b61090c610906366108ce565b91613245565b005b3461031e57602036600319011261031e5760043561092b81610391565b60018060a01b03166000526011602052602060ff604060002054166040519015158152f35b3461031e57602036600319011261031e5760043561096d81610391565b60018060a01b0316600052600f6020526020604060002054604051908152f35b3461031e5760008060031936011261061f576109a7611fd0565b478015610a3457815b601554811015610a305780610a26848080806109ef6109e76109e16109d7610a2b9a610b48565b90549060031b1c90565b8a6121af565b612710900490565b610a16610465610465610a018a610b72565b905460039190911b1c6001600160a01b031690565b5af1610a2061309d565b506130cd565b612205565b6109b0565b8280f35b60405162461bcd60e51b81526020600482015260146024820152734e6f2066756e647320746f20776974686472617760601b6044820152606490fd5b61090c610a7c366108ce565b9060405192610a8a8461077f565b600084526133dd565b3461031e57602036600319011261031e57600435600052600e602052602060ff604060002054166040519015158152f35b3461031e57602036600319011261031e57600435610ae181610391565b610ae9611fd0565b600c80546001600160a01b039283166001600160a01b0319821681179092559091167f10e9b6d73105db46c6a41a698f35efb8e1688178fe274b7b21f0bdc792de3ea5600080a3005b634e487b7160e01b600052603260045260246000fd5b601654811015610b6d5760166000526000805160206136d98339815191520190600090565b610b32565b601554811015610b6d5760156000526000805160206136b98339815191520190600090565b3461031e57602036600319011261031e5760043560165481101561031e5760209060166000526000805160206136d98339815191520154604051908152f35b3461031e57600036600319011261031e57600b5460405160089190911c6001600160a01b03168152602090f35b3461031e57602036600319011261031e5760043560155481101561031e5760156000526000805160206136b983398151915201546040516001600160a01b039091168152602090f35b3461031e57602036600319011261031e5760206001600160a01b03610c72600435613145565b16604051908152f35b9181601f8401121561031e578235916001600160401b03831161031e576020808501948460051b01011161031e57565b3461031e5760408060031936011261031e576001600160401b0360043581811161031e57610cdd903690600401610c7b565b909160243590811161031e57610cf7903690600401610c7b565b929091610d02611fd0565b610d0d848214612ec2565b610d18811515612f0e565b6000805b858110610e2257506108ae610d3a610d4192600019600054016116bd565b111561207d565b60005b818110610d4d57005b610d60610d5b828486612899565b612fa6565b610d6b828787612899565b60005460015491359291610d8891036000190161168e565b61168e565b9060005b838110610deb5750829181610dc6610de696957fada993ad066837289fe186cd37227aa338d27519a8a1547472ecb9831486d272946135bd565b8a5193845260208401919091526001600160a01b031691604090a2612205565b610d44565b80610df9610e1d92856116bd565b610e17610e068583612482565b91600052600d602052604060002090565b55612205565b610d8c565b90610e6d610e7391610e40610e38858a8a612899565b351515612f5a565b610e5b610e54610465610d5b87898b612899565b1515612fb0565b610e66848989612899565b35906116bd565b91612205565b610d1c565b3461031e57600036600319011261031e576020604051680ad78ebc5ac62000008152f35b3461031e57602036600319011261031e5760206108c6600435610ebe81610391565b61310b565b3461031e5760008060031936011261061f57610edd611fd0565b600980546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b3461031e57600036600319011261031e57602060405160148152f35b9181601f8401121561031e578235916001600160401b03831161031e576020838186019501011161031e57565b60643590811515820361031e57565b608036600319011261031e576004356001600160401b03811161031e57610fa4903690600401610f3d565b906024359160443590610fb5610f6a565b6002600a5414611312576110c76110da926002600a556110af600b5491610fde60ff8416611ffc565b88151580611307575b610ff09061203e565b6110a960009861100c6108ae610d3a8d8d6000199054016116bd565b6000546001546110269160149190036000190110156120c9565b6040516bffffffffffffffffffffffff193360601b1660208201908152603482018d9052605482018b905288151560f81b6074830152605582526110a19161106f60758261079f565b5190207f19457468657265756d205369676e6564204d6573736167653a0a333200000000600052601c52603c60002090565b923691611a1e565b9061224a565b6001600160a01b0390811660089290921c161461213b565b6110d28184876123cd565b93909361217b565b936110e7853410156121c2565b811515806112e6575b84151593846112c5575b8061129c575b611251575b60005460015461111991036000190161168e565b97875b818110611231575087985061113190336135bd565b6111e8575b5050611186575b50803411611154575b506111516001600a55565b80f35b8180611161819334612231565b81811561117d575b3390f115611178578038611146565b61223e565b506108fc611169565b3360009081526010602052604090207f83a1aaa194b8a77a08f581bb99db83951c1abac5453c3af420106c9173b8dc26906111df906111c6905b54612214565b6040805194855260208501919091523393918291820190565b0390a23861113d565b336000908152600f60205260409020547f86dae78951b4501244f6f1ab999fe0d86921c0df304204186c4bb2553092a26e91611227916111c691612231565b0390a23880611136565b8061123f61124c928c6116bd565b610e17610e063383612482565b61111c565b336000908152601160205260409020611272905b805460ff19166001179055565b337fac9518c6c2eb95c17373d9e7a5a53216b31da728efa73bc5a79331bba20dd25d8880a2611105565b503360009081526011602052604090206112c0906112bc905b5460ff1690565b1590565b611100565b3360009081526010602052604090206112df8782546116bd565b90556110fa565b336000908152600f602052604090206113008482546116bd565b90556110f0565b50600a891115610fe7565b604051633ee5aeb560e01b8152600490fd5b3461031e57606036600319011261031e5760043560243561134481610391565b6044356001600160401b03811161031e5761136661144b913690600401610f3d565b9061136f611fd0565b60018510158061148b575b611383906128bd565b6113976113926112bc876131dd565b612909565b6113a2821515612955565b6000546001546113bb9160149190036000190110612995565b6000546001546113d091036000190186612231565b600181111561147c576009546113fa91906113f4906001600160a01b031691612222565b906135bd565b611403846134f3565b60005460015461141b91879190036000190114612a07565b611432611265866000526013602052604060002090565b611446856000526012602052604060002090565b612b04565b6001600160a01b0316907f4343032d0e158cfdf15c64bd447a9509447b9509e93b2c68a6d422fc2deebdb1600080a3005b50611486846134f3565b611403565b50601485111561137a565b3461031e57604036600319011261031e576001600160401b0360043560243582811161031e576114ca903690600401610f3d565b6114d5929192611fd0565b60148211158061161d575b6114e990612bcb565b6114f5610436836131dd565b600092828452602094601286526040852090831161079a576115218361151b835461072f565b83612aca565b8495601f841160011461158f57508285967f8d8eae0e5345d1c16ad28df8a9b7877bef40718a2cbd7e162849853175715540959691611584575b508360011b906000198560031b1c19161790555b61157e60405192839283612c07565b0390a280f35b90508201353861155b565b601f198416966115a483600052602060002090565b9187905b898210611605575050847f8d8eae0e5345d1c16ad28df8a9b7877bef40718a2cbd7e162849853175715540969798106115eb575b5050600183811b01905561156f565b830135600019600386901b60f8161c1916905538806115dc565b806001849582949589013581550194019201906115a8565b508015156114e0565b3461031e57600036600319011261031e57600c546040516001600160a01b039091168152602090f35b3461031e57600036600319011261031e576009546040516001600160a01b039091168152602090f35b634e487b7160e01b600052601160045260246000fd5b906001820180921161169c57565b611678565b906002820180921161169c57565b906003820180921161169c57565b9190820180921161169c57565b3461031e57600036600319011261031e57602060405160158152f35b3461031e57600036600319011261031e57602060ff600b54166040519015158152f35b3461031e57602036600319011261031e576004356000526013602052602060ff604060002054166040519015158152f35b3461031e5760208060031936011261031e576001600160401b0360043581811161031e5761176c903690600401610f3d565b91611775611fd0565b821161079a5761178f8261178a60145461072f565b612a69565b600092601f83116001146117cd57509181926000926117c2575b5050600019600383901b1c191660019190911b17601455005b0135905038806117a9565b90601f1983169361180060146000527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec90565b9281905b86821061183c5750508360019510611822575b505050811b01601455005b0135600019600384901b60f8161c19169055388080611817565b80600184968294958701358155019501920190611804565b3461031e5760008060031936011261061f5760405190806003546118778161072f565b808552916001918083169081156105f557506001146118a0576105968561058a8187038261079f565b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8284106118e357505050810160200161058a8261059661057a565b805460208587018101919091529093019281016118c8565b3461031e57604036600319011261031e5760043561191881610391565b6024359081151580920361031e573360009081526007602090815260408083206001600160a01b0385168452909152902060ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b3461031e57602036600319011261031e576004356119aa81610391565b60018060a01b031660005260106020526020604060002054604051908152f35b3461031e57602036600319011261031e5760043580151580910361031e576119f0611fd0565b60ff8019600b5416911617600b55600080f35b6001600160401b03811161079a57601f01601f191660200190565b929192611a2a82611a03565b91611a38604051938461079f565b82948184528183011161031e578281602093846000960137010152565b608036600319011261031e57600435611a6d81610391565b602435611a7981610391565b606435916001600160401b03831161031e573660238401121561031e57611aad61090c933690602481600401359101611a1e565b91604435916133dd565b6001600160401b03811161079a5760051b60200190565b81601f8201121561031e57803591611ae583611ab7565b92611af3604051948561079f565b808452602092838086019260051b82010192831161031e578301905b828210611b1d575050505090565b81358152908301908301611b0f565b3461031e57604036600319011261031e576001600160401b0360043581811161031e573660238201121561031e578060040135611b6881611ab7565b91611b76604051938461079f565b81835260209160248385019160051b8301019136831161031e57602401905b828210611bbe576024358587821161031e57611bb861090c923690600401611ace565b90612cae565b8380918335611bcc81610391565b815201910190611b95565b3461031e57602036600319011261031e576105966108926004356126ef565b3461031e57600036600319011261031e5760206040516108ae8152f35b6020908160408183019282815285518094520193019160005b828110611c3a575050505090565b835185529381019392810192600101611c2c565b3461031e57602036600319011261031e57610596611c76600435611c7181610391565b612ffc565b60405191829182611c13565b3461031e5760008060031936011261061f576040519080601454611ca58161072f565b808552916001918083169081156105f55750600114611cce576105968561058a8187038261079f565b9250601483527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec5b828410611d1157505050810160200161058a8261059661057a565b80546020858701810191909152909301928101611cf6565b3461031e57604036600319011261031e57602060ff611d85600435611d4d81610391565b60243590611d5a82610391565b60018060a01b03166000526007845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461031e57602036600319011261031e57600480356001600160401b03811161031e57611dc19036908301610c7b565b9190611dd4611dcf84612199565b612867565b600c5460009491939190611df0906001600160a01b0316610465565b945b818110611e0757604051806105968782611c13565b611e32611e15828487612899565b35611e22610436826131dd565b600052600d602052604060002090565b5460405163188cd00360e01b8152848101918252919060809081908490819060200103818b5afa90811561117857611ed7936000809181938295611edc575b5050611e85611e7f86612199565b8b6128a9565b52611e9b611e95610d8386612199565b8a6128a9565b52611eb6611eb0611eab85612199565b6116a1565b896128a9565b52611ed1611ecb611ec684612199565b6116af565b886128a9565b52612205565b611df2565b9250925050611f009250803d10611f0b575b611ef8818361079f565b810190612460565b919091923880611e71565b503d611eee565b3461031e57602036600319011261031e57600435600052600d6020526020604060002054604051908152f35b3461031e57602036600319011261031e57600435611f5b81610391565b611f63611fd0565b6001600160a01b03908116908115611fb757600954826bffffffffffffffffffffffff60a01b821617600955167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b604051631e4fbdf760e01b815260006004820152602490fd5b6009546001600160a01b03163303611fe457565b60405163118cdaa760e01b8152336004820152602490fd5b1561200357565b60405162461bcd60e51b815260206004820152601360248201527226b4b73a34b7339034b9903737ba1037b832b760691b6044820152606490fd5b1561204557565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964207175616e7469747960801b6044820152606490fd5b1561208457565b60405162461bcd60e51b815260206004820152601760248201527f576f756c6420657863656564206d617820737570706c790000000000000000006044820152606490fd5b156120d057565b60405162461bcd60e51b815260206004820152603a60248201527f437573746f6d20746f6b656e73206d757374206265206d696e7465642062656660448201527f6f726520726567756c6172206d696e74696e6720626567696e730000000000006064820152608490fd5b1561214257565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b90680ad78ebc5ac62000009182810292818404149015171561169c57565b908160021b918083046004149015171561169c57565b8181029291811591840414171561169c57565b156121c957565b60405162461bcd60e51b8152602060048201526014602482015273125b9cdd59999a58da595b9d081c185e5b595b9d60621b6044820152606490fd5b600019811461169c5760010190565b600103906001821161169c57565b60001981019190821161169c57565b9190820391821161169c57565b6040513d6000823e3d90fd5b61053a9161225791612260565b90929192612340565b81519190604183036122915761228a92506020820151906060604084015193015160001a9061229c565b9192909190565b505060009160029190565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161231457926020929160ff608095604051948552168484015260408301526060820152600092839182805260015afa156111785780516001600160a01b0381161561230b57918190565b50809160019190565b50505060009160039190565b6004111561232a57565b634e487b7160e01b600052602160045260246000fd5b61234981612320565b80612352575050565b61235b81612320565b600181036123755760405163f645eedf60e01b8152600490fd5b61237e81612320565b6002810361239f5760405163fce698f760e01b815260048101839052602490fd5b806123ab600392612320565b146123b35750565b6040516335e2f38360e21b81526004810191909152602490fd5b9290919260009233600052600f602052604060002054810390811161169c578082101561245b5750805b80948183039183831161169c57829382612450575b5050612416575090565b33600090815260106020526040902090935061243291506111c0565b8083101561244a5750815b82810390811161169c5790565b9161243d565b14159050388061240c565b6123f7565b919082608091031261031e578151916020810151916060604083015192015190565b9060005b603281106124e15760405162461bcd60e51b815260206004820152602560248201527f556e61626c6520746f2067656e657261746520756e6971756520636f6d62696e60448201526430ba34b7b760d91b6064820152608490fd5b604080514260208083019182524483850152606086811b6bffffffffffffffffffffffff1916908401526074830187905260948084018690528352601f19939290919061252f60b48261079f565b519020600c5490939061254a906001600160a01b0316610465565b835163188cd00360e01b81526004810186905292608092918390859060249082905afa80156111785760009485948692612602575b50506125a8906125b4949596519586938401978891606093918352602083015260408201520190565b0390810183528261079f565b5190206125d16112bc6112b583600052600e602052604060002090565b6125e55750506125e090612205565b612486565b90935061053a92506112659150600052600e602052604060002090565b6125a896506125b495506126229250803d10611f0b57611ef8818361079f565b9196909550909150869061257f565b1561263857565b60405162461bcd60e51b8152602060048201526014602482015273151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b6044820152606490fd5b61053a905461072f565b6040519061268b8261077f565b60008252565b60208183031261031e578051906001600160401b03821161031e570181601f8201121561031e5780516126c381611a03565b926126d1604051948561079f565b8184526020828401011161031e5761053a91602080850191016104e1565b6126fb610436826131dd565b601481111561280a5761271881600052600d602052604060002090565b54600c5461272e906001600160a01b0316610465565b60405163188cd00360e01b8152600481018390529190608083602481845afa918215611178576000928394849085926127da575b5060405163334a8b6360e01b81526004810197909752602487019290925260448601939093526064850193909352608484019290925260a48301526000908290818060c481015b03915afa908115611178576000916127bf575090565b61053a913d8091833e6127d2818361079f565b810190612691565b9050600095506127a994506127fd915060803d8111611f0b57611ef8818361079f565b9196509194909190612762565b612813816131dd565b80612843575b1561283a5761283561053a916000526012602052604060002090565b6107c0565b5061053a61267e565b5061286061285b826000526012602052604060002090565b612674565b1515612819565b9061287182611ab7565b61287e604051918261079f565b828152809261288f601f1991611ab7565b0190602036910137565b9190811015610b6d5760051b0190565b8051821015610b6d5760209160051b010190565b156128c457565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420637573746f6d20746f6b656e2049440000000000000000006044820152606490fd5b1561291057565b60405162461bcd60e51b815260206004820152601b60248201527f437573746f6d20746f6b656e20616c7265616479206d696e74656400000000006044820152606490fd5b1561295c57565b60405162461bcd60e51b815260206004820152601160248201527013595d1859185d18481c995c5d5a5c9959607a1b6044820152606490fd5b1561299c57565b60405162461bcd60e51b815260206004820152603760248201527f437573746f6d20746f6b656e2072616e6765206578636565646564202d20726560448201527f67756c6172206d696e74696e672068617320626567756e0000000000000000006064820152608490fd5b15612a0e57565b606460405162461bcd60e51b815260206004820152602060248201527f546f6b656e204944206d69736d6174636820647572696e67206d696e74696e676044820152fd5b818110612a5d575050565b60008155600101612a52565b90601f8211612a76575050565b6107fe9160146000527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec906020601f840160051c83019310612ac0575b601f0160051c0190612a52565b9091508190612ab3565b9190601f8111612ad957505050565b6107fe926000526020600020906020601f840160051c83019310612ac057601f0160051c0190612a52565b9092916001600160401b03811161079a57612b2981612b23845461072f565b84612aca565b6000601f8211600114612b635781929394600092612b58575b50508160011b916000199060031b1c1916179055565b013590503880612b42565b601f19821694612b7884600052602060002090565b91805b878110612bb3575083600195969710612b99575b505050811b019055565b0135600019600384901b60f8161c19169055388080612b8f565b90926020600181928686013581550194019101612b7b565b15612bd257565b60405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606490fd5b90918060409360208452816020850152848401376000828201840152601f01601f1916010190565b15612c3657565b60405162461bcd60e51b81526020600482015260126024820152712737ba10309031bab9ba37b6903a37b5b2b760711b6044820152606490fd5b15612c7757565b60405162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd081bdddb9959608a1b6044820152606490fd5b90612cb7611fd0565b8151815103612d1357600092835b8251851015612cf257612cd885846128a9565b51810180911161169c57612cec9094612205565b93612cc5565b612d0e91945092612d096127106107fe9514612d4d565b612da3565b612e37565b60405162461bcd60e51b81526020600482015260126024820152714d69736d617463686564206c656e6774687360701b6044820152606490fd5b15612d5457565b60405162461bcd60e51b815260206004820152602160248201527f546f74616c20736861726573206d7573742062652031303030302028313030256044820152602960f81b6064820152608490fd5b8051906001600160401b03821161079a57600160401b821161079a5760155482601555808310612e13575b50602080910190601560005260005b838110612dea5750505050565b82516001600160a01b03166000805160206136b983398151915282015591810191600101612ddd565b612e3190836000805160206136b98339815191529182019101612a52565b38612dce565b8051906001600160401b03821161079a57600160401b821161079a5760165482601655808310612e9e575b50602080910190601660005260005b838110612e7e5750505050565b82516000805160206136d983398151915282015591810191600101612e71565b612ebc90836000805160206136d98339815191529182019101612a52565b38612e62565b15612ec957565b60405162461bcd60e51b815260206004820152601860248201527f4d69736d617463686564206172726179206c656e6774687300000000000000006044820152606490fd5b15612f1557565b60405162461bcd60e51b815260206004820152601760248201527f4e6f20726563697069656e7473207370656369666965640000000000000000006044820152606490fd5b15612f6157565b60405162461bcd60e51b815260206004820152601f60248201527f5175616e74697479206d7573742062652067726561746572207468616e2030006044820152606490fd5b3561053a81610391565b15612fb757565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c696420726563697069656e742061646472657373000000000000006044820152606490fd5b6130058161310b565b80156130835761301481612867565b6000546001549192919003600019019260009060015b8581111561303c575b50505050905090565b6001600160a01b038061304e83613145565b1690831614613066575b61306190612205565b61302a565b918083611ed161307693886128a9565b9183830361305857613033565b50506040516130918161077f565b60008152600036813790565b3d156130c8573d906130ae82611a03565b916130bc604051938461079f565b82523d6000602084013e565b606090565b156130d457565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b6001600160a01b031680156131345760005260056020526001600160401b036040600020541690565b6323d3ad8160e21b60005260046000fd5b6001908082116131cc57613163816000526004602052604060002090565b54918215613180575b5050600160e01b81161561053a57806131cc565b6000548210156131cc5790815b1561316c57909150600019016131ad816000526004602052604060002090565b549182156131c5575050600160e01b81166131cc5790565b908161318d565b636f96cda160e11b60005260046000fd5b6000919060019083818311156131f257505050565b805482106131ff57505050565b9293509082815b613218575b505050600160e01b161590565b82815260046020526040812054935090918361324057801561169c5760001901919081613206565b61320b565b91909161325182613145565b6001600160a01b03918216939091908183168590036133c557600084815260066020526040902080546132936001600160a01b03881633908114908314171590565b61337e575b613374575b506001600160a01b0385811660009081526005602090815260408083208054600019019055928416825282822080546001019055868252600490522091169384929091600160e11b904260a01b85178217905581161561332a575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a41561332557565b6136a7565b60018401613342816000526004602052604060002090565b541561334f575b506132f8565b60005481146133495761336c906000526004602052604060002090565b553880613349565b600090553861329d565b6133bb6112bc6112b5336133a48b60018060a01b03166000526007602052604060002090565b9060018060a01b0316600052602052604060002090565b1561329857613696565b613686565b90916107fe9260405192610a8a8461077f565b9291906133eb828286613245565b803b6133f8575b50505050565b61340193613435565b1561340f57388080806133f2565b6368d2bf6b60e11b60005260046000fd5b9081602091031261031e575161053a8161030c565b604051630a85bd0160e11b8082523360048301526001600160a01b03928316602483015260448201949094526080606482015292936020928492909183916000918390613486906084830190610504565b0393165af1600091816134c3575b506134b5576134a161309d565b8051156134b057805190602001fd5b61340f565b6001600160e01b0319161490565b6134e591925060203d81116134ec575b6134dd818361079f565b810190613420565b9038613494565b503d6134d3565b6000805480825260046020526040822090926001600160a01b0381169161353e91904260a01b8417600160e11b17905b556001600160a01b0316600090815260056020526040902090565b68010000000000000001815401905580156135af57600190818401939180805b61356a575b5050505055565b1561359e575b83818484877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461355e565b809201918483036135705780613563565b622e076360e81b8252600482fd5b906000908154928115613677576001916135fb60018060a01b0383169284831460e11b4260a01b178417613523886000526004602052604060002090565b68010000000000000001820281540190558115613669578401939180805b613624575050505055565b15613658575b83818484877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4613619565b8092019184830361362a5780613563565b622e076360e81b8452600484fd5b63b562e8dd60e01b8352600483fd5b62a1148160e81b60005260046000fd5b632ce44b5f60e11b60005260046000fd5b633a954ecd60e21b60005260046000fdfe55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475d833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289a2646970667358221220b4fd48d62fbc617c44ce101d601c0483a3042441a5acf5367aff0e229a62446e64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002897ab218b4e598c1aa5bdb819a2416c4adf9c46
-----Decoded View---------------
Arg [0] : _renderer (address): 0x2897ab218b4E598c1aa5bdB819a2416C4AdF9c46
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000002897ab218b4e598c1aa5bdb819a2416c4adf9c46
Deployed Bytecode Sourcemap
1693:12869:14:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;-1:-1:-1;;;;;;1693:12869:14;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;:::i;:::-;;;;;;;;11092:25:15;;:101;;;;;1693:12869:14;11092:177:15;;;;1693:12869:14;;;;;;;;;;11092:177:15;-1:-1:-1;;;11244:25:15;;-1:-1:-1;11092:177:15;;;:101;-1:-1:-1;;;11168:25:15;;;-1:-1:-1;11092:101:15;;1693:12869:14;-1:-1:-1;;;;;1693:12869:14;;;;;:::o;:::-;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;1500:62:0;;:::i;:::-;11356:22:14;1693:12869;;-1:-1:-1;;;;;;1693:12869:14;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;:::i;:::-;1500:62:0;;:::i;:::-;2013:2:14;10713:25;;;:45;;;1693:12869;10705:71;;;:::i;:::-;10787:49;10795:16;;;:::i;:::-;10787:49;:::i;:::-;-1:-1:-1;1693:12869:14;;;;10855:13;1693:12869;;10847:53;1693:12869;;;;;;10847:53;:::i;:::-;13032:45:15;13040:36;13048:27;;;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;;13032:45:15;-1:-1:-1;;;;;1693:12869:14;;;;;;10963:54;10971:26;;;10963:54;:::i;:::-;1693:12869;;11034:18;;;11030:94;;1693:12869;11139:30;;;;;;;1693:12869;;11030:94;11104:7;;;:::i;:::-;11030:94;;;;;10713:45;-1:-1:-1;;;;;;1693:12869:14;;10742:16;;10713:45;;1693:12869;;;;;;;;-1:-1:-1;;1693:12869:14;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;1693:12869:14;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;11659:5:15;1693:12869:14;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;11659:5:15;1693:12869:14;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;18736:16:15;;;:::i;:::-;18735:17;18731:73;;-1:-1:-1;1693:12869:14;18822:15:15;1693:12869:14;;;;;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;18731:73:15;18762:41;;;-1:-1:-1;49766:91:15;1693:12869:14;-1:-1:-1;49766:91:15;1693:12869:14;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1693:12869:14;13048:27:15;1693:12869:14;13048:27:15;:::i;:::-;1693:12869:14;735:10:2;;;41521:28:15;41500:198;;1693:12869:14;-1:-1:-1;1693:12869:14;;;41708:15:15;1693:12869:14;;;;;;;-1:-1:-1;;;;;;1693:12869:14;-1:-1:-1;;;;;1693:12869:14;;;;;-1:-1:-1;1693:12869:14;41758:28:15;;;;;1693:12869:14;;41500:198:15;-1:-1:-1;1693:12869:14;;;19687:18:15;1693:12869:14;;;;;;;;735:10:2;1693:12869:14;;;;;;;;;;41500:198:15;41563:135;41640:42;;;-1:-1:-1;49766:91:15;1693:12869:14;-1:-1:-1;49766:91:15;1693:12869:14;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;:::o;:::-;;;;;;-1:-1:-1;1693:12869:14;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:::o;:::-;;;;;-1:-1:-1;1693:12869:14;;;;-1:-1:-1;1693:12869:14;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;-1:-1:-1;1693:12869:14;2482:48;1693:12869;;;;;-1:-1:-1;1693:12869:14;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1693:12869:14;;;;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;1693:12869:14;2429:46;1693:12869;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;1693:12869:14;2312:51;1693:12869;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;1500:62:0;;:::i;:::-;14220:21:14;14260:11;;1693:12869;;14312:13;14346:3;14331:6;1693:12869;14327:17;;;;;14395:9;14505:35;14395:9;;;;14384:29;14385:19;1693:12869;14395:9;14346:3;14395:9;;:::i;:::-;1693:12869;;;;;;;;;14385:19;;:::i;:::-;14408:5;1693:12869;;;;14384:29;14447:23;:18;1693:12869;14455:9;;;:::i;:::-;1693:12869;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;14447:23;:43;;;;:::i;:::-;;14505:35;:::i;:::-;14346:3;:::i;:::-;14312:13;;14327:17;;1693:12869;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;26475:39:15;1693:12869:14;;;:::i;:::-;;;;;;;;:::i;:::-;;;;26475:39:15;:::i;1693:12869:14:-;;;;;;-1:-1:-1;;1693:12869:14;;;;;;-1:-1:-1;1693:12869:14;2257:48;1693:12869;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;1500:62:0;;:::i;:::-;11496:8:14;1693:12869;;-1:-1:-1;;;;;1693:12869:14;;;-1:-1:-1;;;;;;1693:12869:14;;;;;;;;;;11571:41;-1:-1:-1;;11571:41:14;1693:12869;;;;;;;;;;;;;;14395:6;1693:12869;;;;;;14395:6;-1:-1:-1;1693:12869:14;-1:-1:-1;;;;;;;;;;;1693:12869:14;;-1:-1:-1;1693:12869:14;:::o;:::-;;:::i;:::-;14331:6;1693:12869;;;;;;14331:6;-1:-1:-1;1693:12869:14;-1:-1:-1;;;;;;;;;;;1693:12869:14;;-1:-1:-1;1693:12869:14;:::o;:::-;;;;;;-1:-1:-1;;1693:12869:14;;;;;;2653:23;1693:12869;2653:23;;;;;1693:12869;;2653:23;-1:-1:-1;1693:12869:14;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;2137:28;1693:12869;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;2623:23;1693:12869;2623:23;;;;;;-1:-1:-1;1693:12869:14;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;-1:-1:-1;;;;;13048:27:15;1693:12869:14;;13048:27:15;:::i;:::-;1693:12869:14;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;1500:62:0;;;;;:::i;:::-;12310:75:14;12318:38;;;12310:75;:::i;:::-;12396:57;12404:21;;;12396:57;:::i;:::-;-1:-1:-1;12515:13:14;12530:21;;;;;;1693:12869;1902:4;12799:30;12791:79;1693:12869;;;-1:-1:-1;1693:12869:14;;12799:30;:::i;:::-;:43;;12791:79;:::i;:::-;-1:-1:-1;12911:21:14;;;;;;1693:12869;12934:3;12974:13;;;;;;:::i;:::-;;:::i;:::-;13021;;;;;:::i;:::-;7312::15;1693:12869:14;7328:12:15;1693:12869:14;;;;13086:13;:17;;1693:12869;-1:-1:-1;;1693:12869:14;13086:17;:::i;:13::-;:17;:::i;:::-;13123:13;-1:-1:-1;13138:12:14;;;;;;13346:8;;;;;12934:3;13346:8;;13375:42;13346:8;;:::i;:::-;1693:12869;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;13375:42;12934:3;:::i;:::-;12896:13;;13152:3;13194:16;;13152:3;13194:16;;;:::i;:::-;13229:14;13246:39;;;;:::i;:::-;13229:14;1693:12869;;13229:5;1693:12869;;;;;;;13229:14;1693:12869;13152:3;:::i;:::-;13123:13;;12553:3;12581:13;12729:30;12553:3;12581:13;12573:61;12581:13;;;;;:::i;:::-;1693:12869;12581:17;;12573:61;:::i;:::-;12649:65;12657:27;:13;;;;;;:::i;:27::-;;;12649:65;:::i;:::-;12746:13;;;;;:::i;:::-;1693:12869;12729:30;;:::i;:::-;12553:3;;:::i;:::-;12515:13;;1693:12869;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;1956:9;1693:12869;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;1500:62:0;;:::i;:::-;3004:6;1693:12869:14;;-1:-1:-1;;;;;;1693:12869:14;;;;;;;-1:-1:-1;;;;;1693:12869:14;3052:40:0;1693:12869:14;;3052:40:0;1693:12869:14;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;2013:2;1693:12869;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;1693:12869:14;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;1899:1:4;2702:7;1693:12869:14;2702:18:4;2698:86;;4311:93:14;4599:31;1693:12869;1899:1:4;2702:7;1693:12869:14;4319:46;3738:11;1693:12869;;3730:43;1693:12869;;;3730:43;:::i;:::-;3792:12;;;:30;;;1693:12869;3784:59;;;:::i;:::-;1693:12869;7798:13:15;1693:12869:14;3854:74;1902:4;3862:25;1693:12869;;;;;;;3862:25;:::i;3854:74::-;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;3939:102;;2013:2;;1693:12869;;-1:-1:-1;;1693:12869:14;3947:31;;3939:102;:::i;:::-;1693:12869;;-1:-1:-1;;4117:10:14;1693:12869;;;;4086:133;;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;4086:133;;;4264:36;;4086:133;1693:12869;;4086:133;:::i;:::-;1693:12869;4076:144;;1349:325:7;;;;;;;;1247:433;;4264:36:14;1693:12869;;;;:::i;:::-;4319:46;;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;4319:63;4311:93;:::i;:::-;4477:89;;;;;:::i;:::-;4599:31;;;;:::i;:::-;4649:9;4641:55;4649:9;;:22;;4641:55;:::i;:::-;4713:11;;;4709:83;;;1693:12869;4806:12;;;4802:86;;;;1693:12869;4902:44;;;1693:12869;4898:156;;1693:12869;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;5089:17;;1693:12869;-1:-1:-1;;1693:12869:14;13086:17;:::i;5089:::-;5122:13;;5137:12;;;;;;4117:10;;;;5327:8;4117:10;;5327:8;:::i;:::-;5349:124;;5117:172;5483:119;;;;5117:172;4649:9;;;5618:21;5614:105;;5117:172;2531:1:4;;1857;3068:21;1693:12869:14;2888:208:4;2531:1;1693:12869:14;;5614:105;4649:9;;5685:21;4649:9;;;5685:21;:::i;:::-;5656:51;;;;;5614:105;4117:10;5656:51;;;;;5614:105;;;;5656:51;;:::i;:::-;;;;;5483:119;4117:10;1693:12869;;;;4835:17;1693:12869;;;;;5521:69;;;;5556:33;;5560:29;1693:12869;5556:33;:::i;:::-;1693:12869;;;;;;;;;;;;;4117:10;;1693:12869;;;;;;;5521:69;;;;5483:119;;;5349:124;4117:10;1693:12869;;;;4741:16;1693:12869;;;;;;5386:75;;;;5414:46;;;:::i;5386:75::-;;;;5349:124;;;;5151:3;5189:16;;5151:3;5189:16;;;:::i;:::-;5220:14;5237:40;4117:10;5237:40;;:::i;5151:3::-;5122:13;;4898:156;4117:10;1693:12869;;;;4920:14;1693:12869;;;;;4963:33;;:26;1693:12869;;-1:-1:-1;;1693:12869:14;4992:4;1693:12869;;;;4963:33;4117:10;5016:26;;;;4898:156;;4902:44;-1:-1:-1;4117:10:14;1693:12869;;;;4920:14;1693:12869;;;;;4919:27;;4920:26;;;1693:12869;;;;;4920:26;4919:27;;1693:12869;4919:27;4902:44;;4802:86;4117:10;1693:12869;;;;4835:17;1693:12869;;;;;4835:41;1693:12869;;;4835:41;:::i;:::-;1693:12869;;4802:86;;4709:83;4117:10;1693:12869;;;;4741:16;1693:12869;;;;;4741:39;1693:12869;;;4741:39;:::i;:::-;1693:12869;;4709:83;;3792:30;-1:-1:-1;2702:7:4;3808:14:14;;;3792:30;;2698:86:4;1693:12869:14;;-1:-1:-1;;;2743:30:4;;1693:12869:14;;2743:30:4;1693:12869:14;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;:::i;:::-;1500:62:0;;;:::i;:::-;9429:1:14;9418:12;;;:41;;;1693:12869;9410:77;;;:::i;:::-;9498:57;9506:17;9507:16;;;:::i;9506:17::-;9498:57;:::i;:::-;9566:56;9574:26;;;9566:56;:::i;:::-;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;9633:98;;2013:2;;1693:12869;;-1:-1:-1;;1693:12869:14;9641:30;9633:98;:::i;:::-;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;9767:23;;1693:12869;-1:-1:-1;;1693:12869:14;9767:23;;:::i;:::-;9429:1;9807:16;;9429:1;;;1710:6:0;1693:12869:14;9855:16;;1693:12869;9855:16;;-1:-1:-1;;;;;1693:12869:14;9855:16;;:::i;:::-;;;:::i;:::-;9887:19;;;:::i;:::-;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;10030:69;;10006:13;;1693:12869;;-1:-1:-1;;1693:12869:14;10038:24;10030:69;:::i;:::-;10112:29;:22;;1693:12869;;10112:13;1693:12869;;;;;;;10112:29;10152:23;;1693:12869;;10152:14;1693:12869;;;;;;;10152:23;1693:12869;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;10204:37;-1:-1:-1;;10204:37:14;1693:12869;9803:167;9939:19;;;;:::i;:::-;9803:167;;9418:41;-1:-1:-1;2013:2:14;9434:25;;;9418:41;;1693:12869;;;;;;-1:-1:-1;;1693:12869:14;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;:::i;:::-;1500:62:0;;;;;:::i;:::-;2013:2:14;10365:25;;;:55;;;1693:12869;10357:81;;;:::i;:::-;10449:49;10457:16;;;:::i;10449:49::-;-1:-1:-1;1693:12869:14;;;;;;10511:14;1693:12869;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;10561:36;1693:12869;;;;;;;;;;;;;;;;;;;;;;;10561:36;1693:12869;;10561:36;;;;;:::i;:::-;;;;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10561:36;1693:12869;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10365:55;-1:-1:-1;10394:26:14;;;10365:55;;1693:12869;;;;;;-1:-1:-1;;1693:12869:14;;;;2172:31;1693:12869;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;1710:6:0;1693:12869:14;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;13102:1;1693:12869;;;;;;;:::o;:::-;;:::i;:::-;;9171:1;1693:12869;;;;;;;:::o;:::-;;9216:1;1693:12869;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;2099:31;1693:12869;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;-1:-1:-1;1693:12869:14;2537:45;1693:12869;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;:::i;:::-;1500:62:0;;;:::i;:::-;1693:12869:14;;;;;;;11703:18;1693:12869;;:::i;:::-;;:::i;:::-;-1:-1:-1;1693:12869:14;;;;;;;;;;;;-1:-1:-1;1693:12869:14;;;;-1:-1:-1;;;;1693:12869:14;;;;;;;;;;;;;11703:18;1693:12869;;;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;11703:18;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;11703:18;1693:12869;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;;;;;;;735:10:2;-1:-1:-1;1693:12869:14;;;19280:18:15;1693:12869:14;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;735:10:2;19355:55:15;1693:12869:14;735:10:2;19355:55:15;;1693:12869:14;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;1693:12869:14;2370:52;1693:12869;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;1500:62:0;;:::i;:::-;1693:12869:14;;;11250:18;1693:12869;;;;;11250:18;1693:12869;-1:-1:-1;1693:12869:14;;;-1:-1:-1;;;;;1693:12869:14;;;;;;-1:-1:-1;;1693:12869:14;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1693:12869:14;;;;;;:::o;:::-;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11737:456;1693:12869;;;;;;:::i;:::-;11737:456;;:::i;1693:12869::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;1902:4;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;8378:12;1693:12869;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;8378:12;1693:12869;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;19687:35:15;1693:12869:14;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;1693:12869:14;19687:18:15;1693:12869:14;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;19687:35:15;1693:12869:14;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;:::i;:::-;8557:19;;8543:34;8557:19;;;:::i;:::-;8543:34;:::i;:::-;8996:8;1693:12869;-1:-1:-1;;8603:13:14;;;1693:12869;8996:32;;-1:-1:-1;;;;;1693:12869:14;;;8996:32;8598:645;8618:19;;;;;;1693:12869;;;;;;;:::i;8639:3::-;8796:14;8677:11;;;;;:::i;:::-;1693:12869;8703:49;8711:16;;;:::i;8703:49::-;1693:12869;;13229:5;1693:12869;;;;;;;8796:14;1693:12869;;;-1:-1:-1;;;8996:38:14;;;;;1693:12869;;;;;8996:38;;;;1693:12869;;;;;;8996:38;;;;;;;;;;8639:3;8996:38;-1:-1:-1;;;;;;8996:38:14;;;8639:3;9071:5;;9063:32;9071:5;;;:::i;:::-;9063:32;;:::i;:::-;1693:12869;9110:30;9118:9;:5;;;:::i;:9::-;9110:30;;:::i;:::-;1693:12869;9155:30;9163:9;:5;;;:::i;:::-;:9;:::i;:::-;9155:30;;:::i;:::-;1693:12869;9200:31;9208:9;:5;;;:::i;:::-;:9;:::i;:::-;9200:31;;:::i;:::-;1693:12869;8639:3;:::i;:::-;8603:13;;8996:38;;;;;;;;;;;-1:-1:-1;8996:38:14;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;1693:12869;;;;;;-1:-1:-1;;1693:12869:14;;;;;;-1:-1:-1;1693:12869:14;2210:40;1693:12869;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;1500:62:0;;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;;;2627:22:0;;2623:91;;3004:6;1693:12869:14;;;;;;;;3004:6:0;1693:12869:14;;3052:40:0;-1:-1:-1;3052:40:0;;1693:12869:14;2623:91:0;1693:12869:14;;-1:-1:-1;;;2672:31:0;;-1:-1:-1;1693:12869:14;2672:31:0;;1693:12869:14;;;2672:31:0;1796:162;1710:6;1693:12869:14;-1:-1:-1;;;;;1693:12869:14;735:10:2;1855:23:0;1851:101;;1796:162::o;1851:101::-;1693:12869:14;;-1:-1:-1;;;1901:40:0;;735:10:2;1901:40:0;;;1693:12869:14;;;1901:40:0;1693:12869:14;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;1956:9;1693:12869;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;:::o;:::-;5105:1;1693:12869;;5105:1;1693:12869;;;;:::o;:::-;-1:-1:-1;;1693:12869:14;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;3714:255:6;3927:8;3714:255;3871:27;3714:255;3871:27;:::i;:::-;3927:8;;;;;:::i;2129:778::-;1693:12869:14;;;2129:778:6;2319:2;2299:22;;2319:2;;2751:25;2535:196;;;;;;;;;;;;;;;-1:-1:-1;2535:196:6;2751:25;;:::i;:::-;2744:32;;;;;:::o;2295:606::-;2807:83;;2823:1;2807:83;2827:35;2807:83;;:::o;5203:1551::-;;;6283:66;6270:79;;6266:164;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6541:24:6;;;;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;6579:20:6;6575:113;;6698:49;;5203:1551;:::o;6575:113::-;6615:62;;;6541:24;6615:62;;:::o;6266:164::-;6365:54;;;6381:1;6365:54;6385:30;6365:54;;:::o;1693:12869:14:-;;-1:-1:-1;1693:12869:14;;;:::o;:::-;;;;;;;;;;;;7280:532:6;1693:12869:14;;;:::i;:::-;7366:29:6;;;7411:7;;:::o;7362:444::-;1693:12869:14;;;:::i;:::-;7471:29:6;7462:38;;7471:29;;1693:12869:14;;-1:-1:-1;;;7523:23:6;;;;;7458:348;1693:12869:14;;;:::i;:::-;7576:35:6;7567:44;;7576:35;;1693:12869:14;;-1:-1:-1;;;7634:46:6;;;;;1693:12869:14;;;;;7634:46:6;7563:243;1693:12869:14;;7710:30:6;1693:12869:14;;:::i;:::-;7701:39:6;7697:109;;7563:243;7280:532::o;7697:109::-;1693:12869:14;;-1:-1:-1;;;7763:32:6;;;;;1693:12869:14;;;;;;7634:46:6;5734:815:14;;;;;1693:12869;5954:36;6068:10;1693:12869;;6051:16;1693:12869;;;;;;;;;;;;;6100:31;;;;;;:65;;;6090:75;1693:12869;;;;;;;;;;6176:28;6229:38;;;;6100:65;6225:264;;;;6509:32;5734:815;:::o;6225:264::-;6068:10;1693:12869;;;;4835:17;1693:12869;;;;;6068:10;;-1:-1:-1;6307:33:14;;-1:-1:-1;6311:29:14;1693:12869;6307:33;6366:32;;;;;;:67;;;6355:78;1693:12869;;;;;;;5734:815;:::o;6366:67::-;;;;6229:38;6246:21;;;-1:-1:-1;6229:38:14;;;;6100:65;;;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;6557:965::-;;6675:1;6739:22;6709:2;6739:22;;;;1693:12869;;-1:-1:-1;;;7467:47:14;;1693:12869;7083:38;7467:47;;1693:12869;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;7634:46:6;6732:715:14;1693:12869;;;6846:15;6811:178;;;;1693:12869;;;6880:16;1693:12869;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;;6811:178;;-1:-1:-1;;;1693:12869:14;6811:178;;;;1693:12869;;6811:178;:::i;:::-;1693:12869;6801:189;;7083:8;1693:12869;6801:189;;1693:12869;7083:32;;-1:-1:-1;;;;;1693:12869:14;;;7083:32;1693:12869;;-1:-1:-1;;;7083:38:14;;;;;1693:12869;;;;7083:38;;;;;1693:12869;;;;;;7083:38;;;;;;6675:1;;;;;7083:38;;;6732:715;1693:12869;;7172:50;1693:12869;7172:50;1693:12869;;;;7172:50;;;;;;;1693:12869;;;;;;;;;;;;;;;;;7172:50;;;;;;;;;:::i;:::-;1693:12869;7162:61;;7256:34;7257:33;;;1693:12869;;7257:16;1693:12869;;;;;;;7256:34;7252:145;;7425:10;;;;;:::i;:::-;6732:715;;7252:145;7311:33;;;:40;:33;;;;;1693:12869;;7257:16;1693:12869;;;;;;;7083:38;7172:50;7083:38;;7172:50;7083:38;;;;;;;-1:-1:-1;7083:38:14;;;;;;:::i;:::-;;;;;-1:-1:-1;7083:38:14;;-1:-1:-1;7083:38:14;;;;1693:12869;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;7530:763::-;7621:49;7629:16;;;:::i;7621:49::-;2013:2;7695:25;;;7691:239;;7957:14;;1693:12869;;13229:5;1693:12869;;;;;;;7957:14;1693:12869;8133:8;1693:12869;8133:32;;-1:-1:-1;;;;;1693:12869:14;;;8133:32;1693:12869;;-1:-1:-1;;;8133:38:14;;;;;1693:12869;;;;;8133:38;1693:12869;;;;8133:38;;;;;;;-1:-1:-1;;;;;;;8133:38:14;;;7530:763;-1:-1:-1;1693:12869:14;;-1:-1:-1;;;8199:86:14;;8133:38;8199:86;;1693:12869;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;8199:86;;;;;;;;;;-1:-1:-1;8199:86:14;;;8192:93;7530:763;:::o;8199:86::-;;;;;;;;;;;;:::i;:::-;;;;;:::i;8133:38::-;;;-1:-1:-1;8133:38:14;;8199:86;8133:38;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;8133:38:14;;;;;;;7691:239;7741:16;;;:::i;:::-;:61;;;7691:239;7737:182;;;7830:23;1693:12869;7830:23;1693:12869;;10152:14;1693:12869;;;;;;;7830:23;1693:12869;:::i;7737:182::-;1693:12869;;;:::i;7741:61::-;7767:23;7761:37;7767:23;;1693:12869;;10152:14;1693:12869;;;;;;;7767:23;7761:37;:::i;:::-;:41;;7741:61;;1693:12869;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;11703:18;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;1693:12869:14;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;1500:62:0;;;;:::i;:::-;1693:12869:14;;;;11850:36;1693:12869;;-1:-1:-1;11955:13:14;;11992:3;1693:12869;;11970:20;;;;;12027:12;;;;:::i;:::-;1693:12869;;;;;;;;11992:3;12012:27;11992:3;;:::i;:::-;11955:13;;;11970:20;1693:12869;11970:20;;;;12061:66;12084:5;1693:12869;11970:20;12069;12061:66;:::i;:::-;1693:12869;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;-1:-1:-1;;;1693:12869:14;;;;12138:18;1693:12869;;12138:18;1693:12869;;;;;;;;;;;;;12138:18;-1:-1:-1;1693:12869:14;-1:-1:-1;1693:12869:14;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1693:12869:14;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;1693:12869:14;;;;-1:-1:-1;;;1693:12869:14;;;;12167:18;1693:12869;;12167:18;1693:12869;;;;;;;;;;;;;12167:18;-1:-1:-1;1693:12869:14;-1:-1:-1;1693:12869:14;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;1693:12869:14;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;13444:700;13562:16;;;:::i;:::-;13593:12;;13589:68;;13688:22;;;:::i;:::-;7312:13:15;1693:12869:14;7328:12:15;1693:12869:14;13745:13;;;1693:12869;;-1:-1:-1;;1693:12869:14;13769:17;13604:1;13812:19;13830:1;13833:24;;;;;;;13807:294;14121:15;;;;;;13444:700;:::o;13859:9::-;-1:-1:-1;;;;;1693:12869:14;13048:27:15;;;:::i;:::-;1693:12869:14;;;;13889:25;13885:205;;13859:9;;;;:::i;:::-;13812:19;;13885:205;13935:25;;;;13979:7;13935:25;;;:::i;13979:7::-;;;;14009:16;13885:205;14005:70;14050:5;;13589:68;1693:12869;;;;;;;:::i;:::-;-1:-1:-1;1693:12869:14;;-1:-1:-1;1693:12869:14;;;13622:23;:::o;1693:12869::-;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;1693:12869:14;;;;:::o;:::-;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1693:12869:14;;;;;;;;;;;;-1:-1:-1;;;1693:12869:14;;;;;;;8570:239:15;-1:-1:-1;;;;;1693:12869:14;8665:19:15;;8661:69;;8682:1;1693:12869:14;8747:18:15;1693:12869:14;;-1:-1:-1;;;;;1693:12869:14;8682:1:15;1693:12869:14;;8747:55:15;8570:239;:::o;8661:69::-;8694:35;;;8682:1;49766:91;;8682:1;49766:91;14380:2173;3513:1:14;14477:26:15;;;;16507:38;14473:2017;14528:26;;1693:12869:14;;14528:17:15;1693:12869:14;;;;;;;14528:26:15;1693:12869:14;14847:11:15;;;14843:1270;;14473:2017;-1:-1:-1;;;;;16435:24:15;;:29;16431:48;;14473:2017;16507:38;:::i;14843:1270::-;-1:-1:-1;1693:12869:14;14882:24:15;;;14878:77;;15502:597;;3513:1:14;;14843:1270:15;3513:1:14;1693:12869;;;;;;15578:28:15;;1693:12869:14;;14528:17:15;1693:12869:14;;;;;;;15578:28:15;1693:12869:14;15654:11:15;;;15650:25;;-1:-1:-1;;;;;15701:24:15;;16041:38;15697:48;15732:13;:::o;15650:25::-;15502:597;;;;14878:77;14916:38;;;-1:-1:-1;49766:91:15;;-1:-1:-1;49766:91:15;19978:465;1693:12869:14;;19978:465:15;3513:1:14;;1693:12869;20070:26:15;;;;20066:371;;19978:465;;;:::o;20066:371::-;1693:12869:14;;20221:23:15;;20217:210;;19978:465;;;:::o;20217:210::-;20264:14;;-1:-1:-1;20264:14:15;;;3513:1:14;;;20296:60:15;-1:-1:-1;;;;;;20383:24:15;:29;;19978:465::o;20296:60::-;1693:12869:14;;;20313:17:15;1693:12869:14;;;;;;;-1:-1:-1;1693:12869:14;;;20303:42:15;;1693:12869:14;;;;-1:-1:-1;;1693:12869:14;;20296:60:15;;;;20303:42;;;22796:3447;;;;22963:27;;;:::i;:::-;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;23173:45:15;;;23169:95;;-1:-1:-1;1693:12869:14;;;21929:15:15;1693:12869:14;;;;;22057:132:15;;23463:69;-1:-1:-1;;;;;21135:472:15;;735:10:2;21135:472:15;;;;;;;4919:27:14;;1693:12869;23463:69:15;23459:188;;22796:3447;23764:190;;22796:3447;-1:-1:-1;;;;;;1693:12869:14;;;;;;;24316:18:15;1693:12869:14;;;;;;;;;;-1:-1:-1;;1693:12869:14;;;;;;;;;;;;;-1:-1:-1;2943:14:15;1693:12869:14;;;;;14528:17:15;1693:12869:14;;;17192:331:15;;;;;1693:12869:14;;-1:-1:-1;;;2550:8:15;17192:331;;;;;;;;1693:12869:14;24959:47:15;;:52;24955:617;;22796:3447;25749:367;;-1:-1:-1;25749:367:15;;26129:13;26125:58;;22796:3447::o;26125:58::-;26152:30;:::i;24955:617::-;1693:12869:14;;;25184:30:15;;1693:12869:14;;14528:17:15;1693:12869:14;;;;;;;25184:30:15;1693:12869:14;25184:35:15;25180:378;;24955:617;;;;25180:378;-1:-1:-1;1693:12869:14;25301:239:15;;25180:378;25301:239;25465:30;;1693:12869:14;;14528:17:15;1693:12869:14;;;;;;;25465:30:15;1693:12869:14;25301:239:15;;25180:378;;23764:190;;;;;;;23459:188;23550:44;19687:35;;735:10:2;19687:25:15;;1693:12869:14;;;;;;;;19687:18:15;1693:12869:14;;;;;;;19687:25:15;1693:12869:14;;;;;;;;;;;;;;;;23550:44:15;23546:101;23459:188;23546:101;23604:42;:::i;23169:95::-;23228:35;:::i;26334:187::-;;;26475:39;26334:187;1693:12869:14;;;;;;:::i;27102:405:15:-;;;;27294:7;;;;;:::i;:::-;27316:14;;27312:189;;27102:405;;;;;:::o;27312:189::-;27354:56;;;:::i;:::-;27353:57;27349:152;;27312:189;;;;;;27349:152;27438:47;;;27334:1;49766:91;;27334:1;49766:91;1693:12869:14;;;;;;;;;;;;;:::i;29533:673:15:-;1693:12869:14;;-1:-1:-1;;;29711:88:15;;;735:10:2;29711:88:15;;;1693:12869:14;-1:-1:-1;;;;;1693:12869:14;;;;;;;;;;;;;;;;;;;;;29711:88:15;;1693:12869:14;;29533:673:15;;1693:12869:14;;-1:-1:-1;;1693:12869:14;;;;;;;;;:::i;:::-;29711:88:15;1693:12869:14;;29711:88:15;;-1:-1:-1;;29711:88:15;;;29533:673;-1:-1:-1;29707:493:15;;29943:257;;:::i;:::-;1693:12869:14;;29989:18:15;29985:113;;30111:79;;;29711:88;30111:79;;29985:113;30035:47;:::i;29707:493::-;-1:-1:-1;;;;;;1693:12869:14;29867:64:15;;29860:71::o;29711:88::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;30652:2343;30747:13;1693:12869:14;;;;;14528:17:15;1693:12869:14;;;;;;;-1:-1:-1;;;;;17192:331:15;;;31704:22;;1693:12869:14;17192:331:15;1693:12869:14;17192:331:15;;;-1:-1:-1;;;17192:331:15;;31323:31;1693:12869:14;-1:-1:-1;;;;;1693:12869:14;;;;;24316:18:15;1693:12869:14;;;;;;;31704:22:15;31742:32;1693:12869:14;;;;;31960:13:15;;31956:54;;1693:12869:14;;;;;32076:30:15;32213:662;;;1693:12869:14;;;32213:662:15;1693:12869:14;;;;;30652:2343:15:o;32213:662::-;;;;;32857:16;32234:450;;;;;;;;32213:662;;;2943:14;;;32857:16;;;;32213:662;32857:16;;;;31956:54;-1:-1:-1;;;49766:91:15;;;31983:26;49766:91;30652:2343;;30747:13;1693:12869:14;;;30774:13:15;;;30770:53;;17787:151;1693:12869:14;31704:22:15;1693:12869:14;;;;;17192:331:15;;17787:151;;;;;;17192:331;;;;;;31323:31;;1693:12869:14;;14528:17:15;1693:12869:14;;;;;;;31704:22:15;31742:32;1653:2;;1693:12869:14;;;;;31960:13:15;;31956:54;;1693:12869:14;;32076:30:15;32213:662;;;17787:151;;;1693:12869:14;;;;;30652:2343:15:o;32213:662::-;;;;;32857:16;32234:450;;;;;;;;32213:662;;;2943:14;;;32857:16;;;;32213:662;32857:16;;;;31956:54;-1:-1:-1;;;49766:91:15;;;31983:26;49766:91;30770:53;-1:-1:-1;;;49766:91:15;;;30797:25;49766:91;49703:160;23228:35;;;49766:91;;;;;49703:160;23604:42;;;49766:91;;;;;49703:160;26152:30;;;49766:91;;;;
Swarm Source
ipfs://b4fd48d62fbc617c44ce101d601c0483a3042441a5acf5367aff0e229a62446e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.