Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 383,110 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 36563185 | 14 mins ago | IN | 0 ETH | 0.00000552 | ||||
| Set Approval For... | 36561012 | 32 mins ago | IN | 0 ETH | 0.00000461 | ||||
| Safe Batch Trans... | 36558296 | 54 mins ago | IN | 0 ETH | 0.00000995 | ||||
| Safe Batch Trans... | 36558227 | 55 mins ago | IN | 0 ETH | 0.00001076 | ||||
| Set Approval For... | 36557372 | 1 hr ago | IN | 0 ETH | 0.00000516 | ||||
| Mint Token | 36535499 | 3 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36535488 | 3 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36535480 | 3 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36535468 | 3 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36535459 | 3 hrs ago | IN | 0 ETH | 0.00001372 | ||||
| Batch Redeem | 36533455 | 4 hrs ago | IN | 0 ETH | 0.00003492 | ||||
| Batch Redeem | 36532568 | 4 hrs ago | IN | 0 ETH | 0.00000596 | ||||
| Mint Token | 36532033 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36532024 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36532020 | 4 hrs ago | IN | 0 ETH | 0.00001123 | ||||
| Mint Token | 36531963 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36531883 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36531868 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36531859 | 4 hrs ago | IN | 0 ETH | 0.00001014 | ||||
| Mint Token | 36531852 | 4 hrs ago | IN | 0 ETH | 0.00001123 | ||||
| Mint Token | 36531846 | 4 hrs ago | IN | 0 ETH | 0.00001395 | ||||
| Set Approval For... | 36531256 | 4 hrs ago | IN | 0 ETH | 0.00000489 | ||||
| Mint Token | 36528634 | 4 hrs ago | IN | 0 ETH | 0.00001451 | ||||
| Mint Token | 36528575 | 4 hrs ago | IN | 0 ETH | 0.00001 | ||||
| Mint Token | 36528568 | 4 hrs ago | IN | 0 ETH | 0.00001 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 234841 | 363 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DYLI
Compiler Version
v0.8.24+commit.e11b9ed9
ZkSolc Version
v1.5.7
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "solady/src/utils/ECDSA.sol";
import "solady/src/utils/LibBitmap.sol";
import "solady/src/auth/Ownable.sol";
import "solady/src/utils/LibString.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC1155C, ERC1155OpenZeppelin} from "@limitbreak/creator-token-contracts/contracts/erc1155c/ERC1155C.sol";
import {ERC2981, BasicRoyalties} from "@limitbreak/creator-token-contracts/contracts/programmable-royalties/BasicRoyalties.sol";
/**
* @title DYLI
* @dev ERC1155C token contract with programmable royalties and fair drop lottery queue system
* @author DYLI (https://www.dyli.io/)
*/
contract DYLI is ERC1155C, Ownable, BasicRoyalties {
/// @notice BitMap for refund override status of token IDs
using LibBitmap for LibBitmap.Bitmap;
/// @notice Error for invalid nonce
error InvalidNonce();
/// @notice Error for invalid signature
error InvalidSignature();
/// @notice Error when a payment fails
error PaymentFailed();
/// @notice Error when the sale has not started
error SaleNotStarted();
/// @notice Error when the caller is not the token owner or a marketplace
error OnlyTokenOwnerOrMarketplaceCanTransfer();
/// @notice Error when the sale has ended
error SaleEnded();
/// @notice Error when exceeding maximum quantity
error ExceedsMaxQuantity();
/// @notice Error when token minting is disabled
error TokenMintingDisabled();
/// @notice Error when token is not refundable
error TokenNotRefundable();
/// @notice Error for refund transfer failure
error RefundTransferFailed();
/// @notice Error for blockhash not found
error BlockhashNotFound();
/// @notice Error for blockhash expiration
error BlockhashExpired();
/// @notice Error for a user not in the queue
error NotInQueue();
/// @notice Error when the queue is already processed
error QueueAlreadyProcessed();
/// @notice Error when the queue is still open
error QueueStillOpen();
/// @notice Error when the queue period has ended
error QueuePeriodEnded();
/// @notice Error when the queue is empty
error QueueEmpty();
/// @notice Error when a user is already in the queue
error AlreadyInQueue();
/// @notice Error when the queue blockhash is not ready
error BlockhashNotReady();
/// @notice Error when the queue is already revealed
error QueueAlreadyRevealed();
/// @notice Error when a queue has already been committed for processing
error QueueAlreadyCommitted();
/// @notice Error for insufficient tokens to refund
error InsufficientTokensToRefund();
/// @notice Error for insufficient tokens to redeem
error InsufficientTokensToRedeem();
/// @notice Error lose queue refund being more than queue fee
error LoseQueueRefundExceedsQueueFee();
/// @notice Mapping of tokenId to queue data
mapping(uint256 => Queue) public queue;
/// @notice Mapping of tokenId to whether a user has entered the queue
mapping(uint256 => mapping(address => bool)) public enteredQueue;
/// @notice Mapping of tokenId to token data
mapping(uint256 => TokenData) public tokenData;
/// @notice Mapping of tokenId to disabled status
mapping(uint256 => bool) public tokenDisabled;
/// @notice Mapping of tokenId to total minted count
mapping(uint256 => uint256) public totalMinted;
/// @notice Mapping of tokenId to total refunded count
mapping(uint256 => uint256) public totalRefunded;
/// @notice Mapping of tokenId to total redeemed count
mapping(uint256 => uint256) public totalRedeemed;
/// @notice Mapping of user address to nonce
mapping(address => uint256) public nonces;
/// @notice Mapping of user address and nonce to whether it was used
mapping(address => mapping(uint256 => bool)) public nonceUsed;
/// @notice Mapping of blacklisted marketplaces
mapping(address => bool) public blacklistedMarketplaces;
/// @notice USDC token contract
IERC20 public immutable USDC;
/// @notice Current token ID
uint256 public currentTokenId = 0;
/// @notice Address of the signer
address public signerAddress;
/// @notice Fee amount
uint256 public fee;
/// @notice Queue fee amount
uint256 public queueFee;
/// @notice Fee you get back if you lose the queue
uint256 public loseQueueRefund;
/// @notice Create fee amount
uint256 public createFee;
/// @notice Base URI for tokens
string public baseURI;
/// @dev Fee recipient address
address private _feeRecipient;
/// @notice Bitmap to override the refundable status of token IDs.
LibBitmap.Bitmap private isRefundableOverride;
/// @notice Emitted when a new drop is created
event DropCreated(
uint256 indexed tokenId,
address indexed creator,
uint256 price
);
/// @notice Emitted when a token is minted
event TokenMinted(
uint256 indexed tokenId,
address indexed minter,
uint256 price,
uint256 fee
);
/// @notice Emitted when a token is refunded
event TokenRefunded(
uint256 indexed tokenId,
address indexed minter,
uint256 amount,
uint256 price
);
/// @notice Emitted when a token is redeemed
event TokenRedeemed(uint256 indexed tokenId, address indexed redeemer);
/// @notice Emitted when a user joins a queue
event QueueJoined(
uint256 indexed tokenId,
address indexed user,
uint256 amount
);
/// @notice Emitted when a user leaves a queue
event QueueLeft(
uint256 indexed tokenId,
address indexed user,
uint256 amount
);
/**
* @dev Modifier to validate and update nonces
*/
modifier checkNonce(address user, uint256 nonce) {
if (nonceUsed[user][nonce]) revert InvalidNonce();
nonceUsed[user][nonce] = true;
nonces[user]++;
_;
}
/**
* @dev Token data structure
*/
struct TokenData {
uint256 nonReserved;
uint256 price;
uint256 startTimestamp;
uint256 endTimestamp;
uint256 minMint;
address creator;
bool isOE;
uint256 reserved;
uint256 purchased;
}
/**
* @dev Queue structure
*/
struct Queue {
uint256 reserved;
uint256 cost;
uint256 blockCommit;
uint256 rng;
uint256 entries;
uint256 claimed;
uint256 queueFee;
uint256 loseQueueRefund;
}
/**
* @notice Constructor to initialize the contract
* @param _baseURI Base URI for token metadata
* @param usdc_ Address of the USDC token contract
* @param signerAddress_ Address of the signer
* @param feeRecipient_ Address to receive fees
* @param royaltyFeeNumerator_ Royalty fee numerator
* @param initialQueueFee Initial fee for joining the queue
* @param initialLoseQueueRefund Initial refund if a user loses the queue
* @param initialCreateFee Initial fee for creating a new drop
* @param initialFee Initial fee amount for minting
*/
constructor(
string memory _baseURI,
address usdc_,
address signerAddress_,
address feeRecipient_,
uint96 royaltyFeeNumerator_,
uint256 initialQueueFee,
uint256 initialLoseQueueRefund,
uint256 initialCreateFee,
uint256 initialFee
)
ERC1155OpenZeppelin(_baseURI)
BasicRoyalties(feeRecipient_, royaltyFeeNumerator_)
{
_initializeOwner(msg.sender);
USDC = IERC20(usdc_);
baseURI = _baseURI;
signerAddress = signerAddress_;
_feeRecipient = feeRecipient_;
fee = initialFee;
queueFee = initialQueueFee;
loseQueueRefund = initialLoseQueueRefund;
createFee = initialCreateFee;
}
/**
* @notice Returns the name of the contract
* @return The name of the contract
*/
function name() external pure returns (string memory) {
return "DYLI";
}
/**
* @notice Returns the symbol of the contract
* @return The symbol of the contract
*/
function symbol() external pure returns (string memory) {
return "DYLI";
}
/**
* @notice Updates the base URI for token metadata
* @param _URI New base URI
*/
function setURI(string memory _URI) external onlyOwner {
baseURI = _URI;
}
/**
* @notice Updates the fee recipient address
* @param newFeeRecipient Address of the new fee recipient
*/
function setFeeRecipient(address newFeeRecipient) external onlyOwner {
_feeRecipient = newFeeRecipient;
}
/**
* @notice Updates the fee amount
* @param newFee New fee amount
*/
function setFee(uint256 newFee) external onlyOwner {
fee = newFee;
}
/**
* @notice Updates the queue fee amount and ensures loseQueueRefund is not greater than queueFee
* @param newQueueFee New queue fee amount
*/
function setQueueFee(uint256 newQueueFee) external onlyOwner {
queueFee = newQueueFee;
if (loseQueueRefund > queueFee) {
loseQueueRefund = queueFee;
}
}
/**
* @notice Updates the refund you get back if you lose the queue
* @param newLoseQueueRefund New refund you get back if you lose the queue
*/
function setNewLoseQueueRefund(uint256 newLoseQueueRefund)
external
onlyOwner
{
if (newLoseQueueRefund > queueFee) {
revert LoseQueueRefundExceedsQueueFee();
}
loseQueueRefund = newLoseQueueRefund;
}
/**
* @notice Updates the create fee amount
* @param newCreateFee New create fee amount
*/
function setCreateFee(uint256 newCreateFee) external onlyOwner {
createFee = newCreateFee;
}
/**
* @notice Updates the signer address
* @param newSigner Address of the new signer
*/
function setSigner(address newSigner) external onlyOwner {
signerAddress = newSigner;
}
/**
* @notice Updates the refundable override status for a token ID
* @param tokenId Token ID to update
* @param refundable New refundable status
*/
function setRefundableOverride(uint256 tokenId, bool refundable)
external
onlyOwner
{
isRefundableOverride.setTo(tokenId, refundable);
}
/**
* @notice Creates a new drop
* @param nonReserved Maximum number of tokens available for public minting, excluding reserved tokens.
* @param price Price per token
* @param _isOE Whether the drop is open edition
* @param isStripe Whether the payment is made via Stripe
* @param signature Cryptographic signature for verification
* @param nonce Nonce for transaction validation
* @param startTimestamp Start timestamp of the sale
* @param endTimestamp End timestamp of the sale
* @param minMint Minimum number of tokens to mint
* @param reserved Number of tokens reserved
* @return tokenId ID of the newly created drop
*/
function createDrop(
uint256 nonReserved,
uint256 price,
bool _isOE,
bool isStripe,
bytes memory signature,
uint256 nonce,
uint256 startTimestamp,
uint256 endTimestamp,
uint256 minMint,
uint256 reserved
) external checkNonce(msg.sender, nonce) returns (uint256) {
if (startTimestamp == 0) startTimestamp = block.timestamp;
if (endTimestamp != 0 && endTimestamp <= startTimestamp)
revert SaleEnded();
bytes32 hash = ECDSA.toEthSignedMessageHash(
keccak256(
abi.encode(
msg.sender,
nonReserved,
price,
_isOE,
isStripe,
nonce,
startTimestamp,
endTimestamp,
minMint,
reserved
)
)
);
if (!_verify(hash, signature)) revert InvalidSignature();
if (
!isStripe &&
!USDC.transferFrom(msg.sender, _feeRecipient, createFee)
) revert PaymentFailed();
return
_createDrop(
msg.sender,
nonReserved,
price,
_isOE,
startTimestamp,
endTimestamp,
minMint,
reserved
);
}
/**
* @notice Mints a token
* @param tokenId ID of the token to mint
* @param signature Cryptographic signature for verification
* @param nonce Nonce for transaction validation
* @param isStripe Whether the payment is made via Stripe
* @param tax Additional tax amount
*/
function mintToken(
uint256 tokenId,
bytes memory signature,
uint256 nonce,
bool isStripe,
uint256 tax
) external checkNonce(msg.sender, nonce) {
TokenData storage data = tokenData[tokenId];
if (data.endTimestamp != 0 && block.timestamp > data.endTimestamp)
revert SaleEnded();
bytes32 hash = ECDSA.toEthSignedMessageHash(
keccak256(abi.encode(msg.sender, tokenId, nonce, isStripe, tax))
);
if (!_verify(hash, signature)) revert InvalidSignature();
if (!isStripe) {
uint256 totalFee = fee + tax;
if (!USDC.transferFrom(msg.sender, address(this), data.price))
revert PaymentFailed();
if (!USDC.transferFrom(msg.sender, _feeRecipient, totalFee))
revert PaymentFailed();
}
_mintToken(msg.sender, tokenId, data, false);
}
/**
* @notice Allows the creator or contract owner to mint tokens for a recipient before sale starts.
* @dev Nonce is checked for replay protection. Payments handled based on the `isStripe` flag.
* @param tokenId ID of the token to mint.
* @param signature Signature for verifying the transaction.
* @param recipient Address of the recipient to receive minted tokens.
* @param nonce Unique transaction nonce.
* @param isStripe Flag indicating whether the payment was made via Stripe.
* @param tax Additional tax amount.
*/
function mintTokenByCreator(
uint256 tokenId,
bytes memory signature,
address recipient,
uint256 nonce,
bool isStripe,
uint256 tax
) external checkNonce(msg.sender, nonce) {
bytes32 hash = ECDSA.toEthSignedMessageHash(
keccak256(abi.encode(msg.sender, tokenId, nonce, isStripe, tax))
);
if (!_verify(hash, signature)) revert InvalidSignature();
TokenData storage data = tokenData[tokenId];
if (msg.sender != data.creator && msg.sender != owner())
revert SaleNotStarted();
if (data.endTimestamp != 0 && block.timestamp > data.endTimestamp) {
revert SaleEnded();
}
if (!isStripe) {
uint256 totalFee = fee + tax;
if (!USDC.transferFrom(recipient, address(this), data.price))
revert PaymentFailed();
if (!USDC.transferFrom(recipient, _feeRecipient, totalFee))
revert PaymentFailed();
}
_mintToken(recipient, tokenId, data, false);
}
/**
* @notice Redeems multiple tokens in a batch.
* @dev Uses nonces for replay protection and checks the provided signature.
* @param tokenIds Array of token IDs to redeem.
* @param nonce Unique transaction nonce.
* @param fees Array of additional fees for each token.
* @param signature Signature for verifying the transaction.
*/
function batchRedeem(
uint256[] memory tokenIds,
uint256 nonce,
uint256[] memory fees,
bytes memory signature
) external checkNonce(msg.sender, nonce) {
bytes32 hash = ECDSA.toEthSignedMessageHash(
keccak256(abi.encode(msg.sender, tokenIds, nonce, fees))
);
if (!_verify(hash, signature)) revert InvalidSignature();
for (uint256 i = 0; i < tokenIds.length; i++) {
if (fees[i] > 0) {
if (!USDC.transferFrom(msg.sender, _feeRecipient, fees[i]))
revert PaymentFailed();
}
totalRedeemed[tokenIds[i]] += 1;
_burn(msg.sender, tokenIds[i], 1);
emit TokenRedeemed(tokenIds[i], msg.sender);
}
}
/**
* @notice Refunds tokens to the sender.
* @dev Requires valid signature and verifies refund eligibility.
* @param tokenId ID of the token to refund.
* @param amount Number of tokens to refund.
* @param nonce Unique transaction nonce.
* @param signature Signature for verifying the transaction.
*/
function refundToken(
uint256 tokenId,
uint256 amount,
uint256 nonce,
bytes memory signature
) external checkNonce(msg.sender, nonce) {
bytes32 hash = ECDSA.toEthSignedMessageHash(
keccak256(abi.encode(msg.sender, tokenId, amount, nonce))
);
if (!_verify(hash, signature)) revert InvalidSignature();
TokenData storage data = tokenData[tokenId];
if (!isRefundableOverride.get(tokenId)) {
if (
block.timestamp > data.endTimestamp &&
totalMinted[tokenId] <= data.minMint
) {
revert TokenNotRefundable();
}
}
uint256 totalRefund;
unchecked {
totalRefund = data.price * amount;
}
if (totalRefund == 0) revert RefundTransferFailed();
unchecked {
totalRefunded[tokenId] += amount;
}
_burn(msg.sender, tokenId, amount);
if (!USDC.transfer(msg.sender, totalRefund))
revert RefundTransferFailed();
emit TokenRefunded(tokenId, msg.sender, amount, totalRefund);
}
/**
* @notice Allows a user to join a token's queue.
* @dev Requires that the queue exists and the user is not already in it.
* @param tokenId ID of the token queue to join.
*/
function joinQueue(uint256 tokenId) external {
TokenData storage data = tokenData[tokenId];
if (data.reserved == 0) revert QueueEmpty();
if (block.timestamp > data.startTimestamp) revert QueuePeriodEnded();
if (enteredQueue[tokenId][msg.sender]) revert AlreadyInQueue();
uint256 totalAmount = data.price + queueFee;
enteredQueue[tokenId][msg.sender] = true;
queue[tokenId].entries++;
if (!USDC.transferFrom(msg.sender, address(this), totalAmount))
revert PaymentFailed();
emit QueueJoined(tokenId, msg.sender, totalAmount);
}
/**
* @notice Allows a user to leave a token's queue.
* @dev Refunds the user and removes them from the queue.
* @param tokenId ID of the token queue to leave.
*/
function leaveQueue(uint256 tokenId) external {
if (!enteredQueue[tokenId][msg.sender]) revert NotInQueue();
if (queue[tokenId].blockCommit != 0) revert QueueAlreadyCommitted();
uint256 amount = queue[tokenId].cost + queue[tokenId].queueFee;
enteredQueue[tokenId][msg.sender] = false;
queue[tokenId].entries--;
if (!USDC.transfer(msg.sender, amount)) revert RefundTransferFailed();
emit QueueLeft(tokenId, msg.sender, amount);
}
/**
* @notice Commits the queue for processing.
* @dev Ensures the queue is ready for RNG calculation.
* @param tokenId ID of the token queue to commit.
*/
function commitQueue(uint256 tokenId) external {
TokenData storage data = tokenData[tokenId];
Queue storage queueData = queue[tokenId];
if (block.timestamp < data.startTimestamp) revert QueueStillOpen();
if (queueData.reserved == 0) revert QueueEmpty();
if (block.number > queueData.blockCommit + 256 && queueData.rng == 0) {
queueData.blockCommit = block.number + 5;
return;
}
if (queueData.blockCommit != 0) revert QueueAlreadyProcessed();
queueData.blockCommit = block.number + 5;
}
/**
* @notice Reveals the RNG for a queue after the block is committed.
* @dev Uses the blockhash to determine the RNG.
* @param tokenId ID of the token queue to reveal.
*/
function revealQueue(uint256 tokenId) external {
Queue storage queueData = queue[tokenId];
if (queueData.rng != 0) revert QueueAlreadyRevealed();
if (block.number < queueData.blockCommit) revert BlockhashNotReady();
bytes32 blockHash = blockhash(queueData.blockCommit);
if (blockHash == 0) revert BlockhashNotFound();
if (block.number >= queueData.blockCommit + 256)
revert BlockhashExpired();
queueData.rng = uint256(blockHash);
}
/**
* @notice Claims a token from the queue if the user is a winner.
* @dev Refunds the user if they are not a winner.
* @param tokenId ID of the token to claim.
*/
function claimFromQueue(uint256 tokenId) external {
if (!enteredQueue[tokenId][msg.sender]) revert NotInQueue();
bool isWinner = checkQueueResult(tokenId, msg.sender);
enteredQueue[tokenId][msg.sender] = false;
if (!isWinner) {
if (
!USDC.transfer(
msg.sender,
queue[tokenId].cost + queue[tokenId].loseQueueRefund
)
) revert RefundTransferFailed();
return;
}
TokenData storage data = tokenData[tokenId];
_mintToken(msg.sender, tokenId, data, true);
}
/**
* @notice Blacklists or removes a blacklist for a specific marketplace.
* @param marketplace Address of the marketplace.
* @param isBlacklisted Boolean indicating whether the marketplace is blacklisted.
*/
function blacklistMarketplace(address marketplace, bool isBlacklisted)
public
onlyOwner
{
blacklistedMarketplaces[marketplace] = isBlacklisted;
}
/**
* @notice Enables or disables minting for a specific token.
* @param tokenId ID of the token to enable/disable.
* @param disabled Boolean indicating whether minting is disabled.
*/
function disableToken(uint256 tokenId, bool disabled) public onlyOwner {
tokenDisabled[tokenId] = disabled;
}
/**
* @notice Transfers a token from one address to another.
* @dev Validates that the caller is either the owner or a non-blacklisted marketplace.
* @param from Address of the sender.
* @param to Address of the recipient.
* @param id ID of the token to transfer.
* @param amount Amount of tokens to transfer.
* @param data Additional data for the transfer.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public override {
if (msg.sender != from && blacklistedMarketplaces[msg.sender])
revert OnlyTokenOwnerOrMarketplaceCanTransfer();
super.safeTransferFrom(from, to, id, amount, data);
}
/**
* @notice Transfers multiple tokens in a batch from one address to another.
* @dev Validates that the caller is either the owner or a non-blacklisted marketplace.
* @param from Address of the sender.
* @param to Address of the recipient.
* @param ids Array of token IDs to transfer.
* @param amounts Array of token amounts to transfer.
* @param data Additional data for the transfer.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public override {
if (msg.sender != from && blacklistedMarketplaces[msg.sender])
revert PaymentFailed();
super.safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @notice Withdraws a specified amount of USDC from the contract.
* @param amount Amount of USDC to withdraw.
*/
function withdraw(uint256 amount) public onlyOwner {
if (amount == 0) revert PaymentFailed();
USDC.transfer(msg.sender, amount);
}
/**
* @notice Withdraws the full USDC balance from the contract.
*/
function fullWithdraw() public onlyOwner {
USDC.transfer(msg.sender, USDC.balanceOf(address(this)));
}
/**
* @notice Checks whether a user is a winner in a token's queue.
* @dev The result of this function is dynamic and can change based on the following factors:
* - The state of the `rng` (random number generator) for the queue.
* - The number of `claimed` entries in the queue, which can increase over time.
* Users should claim their tokens promptly if they are determined to be winners, as the result of this function
* is not guaranteed to remain consistent.
* @param tokenId ID of the token queue to check.
* @param user Address of the user to check.
* @return Boolean indicating whether the user is a winner.
*/
function checkQueueResult(uint256 tokenId, address user)
public
view
returns (bool)
{
Queue memory queueData = queue[tokenId];
if (!enteredQueue[tokenId][user]) {
return false;
}
uint256 rng = queueData.rng;
uint256 entries = queueData.entries;
uint256 reserved = queueData.reserved;
if (rng == 0 || queueData.claimed >= queueData.reserved) {
return false;
}
if (queueData.entries <= queueData.reserved) return true;
uint256 rank = uint256(keccak256(abi.encode(rng, user)));
return (rank % entries) < reserved;
}
/**
* @notice Returns the URI for a specific token ID.
* @param tokenId ID of the token to retrieve the URI for.
* @return The URI of the token.
*/
function uri(uint256 tokenId) public view override returns (string memory) {
return
string(abi.encodePacked(baseURI, "/", LibString.toString(tokenId)));
}
/**
* @notice Checks if a given interface is supported.
* @param interfaceId ID of the interface to check.
* @return Boolean indicating whether the interface is supported.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC1155C, ERC2981)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
/**
* @notice Internal function to create a new drop
* @param creator Address of the creator
* @param nonReserved Maximum number of tokens available for public minting, excluding reserved tokens.
* @param price Price per token
* @param _isOE Whether the drop is open edition
* @param startTimestamp Start timestamp of the sale
* @param endTimestamp End timestamp of the sale
* @param minMint Minimum number of tokens to mint
* @param reserved Number of tokens reserved
* @return tokenId ID of the newly created drop
*/
function _createDrop(
address creator,
uint256 nonReserved,
uint256 price,
bool _isOE,
uint256 startTimestamp,
uint256 endTimestamp,
uint256 minMint,
uint256 reserved
) internal returns (uint256) {
unchecked {
currentTokenId++;
}
tokenData[currentTokenId] = TokenData(
nonReserved,
price,
startTimestamp,
endTimestamp,
minMint,
creator,
_isOE,
reserved,
0
);
emit DropCreated(currentTokenId, creator, price);
if (reserved > 0) {
queue[currentTokenId] = Queue(
reserved,
price,
0,
0,
0,
0,
queueFee,
loseQueueRefund
);
}
return currentTokenId;
}
/**
* @notice Internal function to mint a token to a user.
* @dev Handles minting logic, including checks for open edition and maximum supply.
* @param user Address of the user to mint the token to.
* @param tokenId ID of the token to mint.
* @param fromQueue bool to decide if the mint is coming from claiming or regular mint.
* @param data Token data structure for the specified tokenId.
*/
function _mintToken(
address user,
uint256 tokenId,
TokenData storage data,
bool fromQueue
) internal {
if (tokenDisabled[tokenId]) revert TokenMintingDisabled();
Queue storage queueData = queue[tokenId];
uint256 availableSupply = 0;
if (fromQueue) {
availableSupply = queueData.reserved - queueData.claimed;
queueData.claimed++;
} else if (!data.isOE) {
uint256 unclaimedFromQueue = queueData.entries < data.reserved
? data.reserved - queueData.entries
: 0;
uint256 realNonreserved = data.nonReserved + unclaimedFromQueue;
availableSupply = realNonreserved - data.purchased;
data.purchased++;
} else {
data.purchased++;
}
if (!data.isOE && availableSupply <= 0) revert ExceedsMaxQuantity();
totalMinted[tokenId] += 1;
_mint(user, tokenId, 1, "");
emit TokenMinted(tokenId, user, data.price, fee);
}
/**
* @dev Internal function to enforce that the caller is the contract owner.
*/
function _requireCallerIsContractOwner() internal view virtual override {
if (msg.sender != owner()) revert SaleNotStarted();
}
/**
* @notice Verifies the validity of a signature.
* @dev Recovers the signer address and compares it with the stored signer address.
* @param hash Hash of the data being signed.
* @param signature Signature to verify.
* @return Boolean indicating whether the signature is valid.
*/
function _verify(bytes32 hash, bytes memory signature)
internal
view
returns (bool)
{
address recovered = ECDSA.recover(hash, signature);
return recovered == signerAddress;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
/// This is for more safety by default.
/// Use the `tryRecover` variants if you need to get the zero address back
/// upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
/// See: https://eips.ethereum.org/EIPS/eip-2098
/// This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT directly use signatures as unique identifiers:
/// - The recovery operations do NOT check if a signature is non-malleable.
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
/// EIP-712 also enables readable signing of typed data for better user safety.
/// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
library ECDSA {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The order of the secp256k1 elliptic curve.
uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;
/// @dev `N/2 + 1`. Used for checking the malleability of the signature.
uint256 private constant _HALF_N_PLUS_1 =
0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The signature is invalid.
error InvalidSignature();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RECOVERY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
} {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { continue }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if returndatasize() { break }
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
} {
switch signature.length
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
}
default { continue }
mstore(0x00, hash)
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if returndatasize() { break }
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRY-RECOVER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// WARNING!
// These functions will NOT revert upon recovery failure.
// Instead, they will return the zero address upon recovery failure.
// It is critical that the returned address is NEVER compared against
// a zero address (e.g. an uninitialized address variable).
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecover(bytes32 hash, bytes memory signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {} {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
for { let m := mload(0x40) } 1 {} {
switch signature.length
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
}
default { break }
mstore(0x00, hash)
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, hash) // Store into scratch space for keccak256.
mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
}
}
/// @dev Returns an Ethereum Signed Message, created from `s`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
/// Note: Supports lengths of `s` up to 999999 bytes.
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let sLength := mload(s)
let o := 0x20
mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
mstore(0x00, 0x00)
// Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
for { let temp := sLength } 1 {} {
o := sub(o, 1)
mstore8(o, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
// Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
mstore(s, sLength) // Restore the length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CANONICAL HASH FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// The following functions returns the hash of the signature in it's canonicalized format,
// which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
// If `s` is greater than `N / 2` then it will be converted to `N - s`
// and the `v` value will be flipped.
// If the signature has an invalid length, or if `v` is invalid,
// a uniquely corrupt hash will be returned.
// These functions are useful for "poor-mans-VRF".
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
let l := mload(signature)
for {} 1 {} {
mstore(0x00, mload(add(signature, 0x20))) // `r`.
let s := mload(add(signature, 0x40))
let v := mload(add(signature, 0x41))
if eq(l, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(l, 64), 2)) {
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHashCalldata(bytes calldata signature)
internal
pure
returns (bytes32 result)
{
// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
mstore(0x00, calldataload(signature.offset)) // `r`.
let s := calldataload(add(signature.offset, 0x20))
let v := calldataload(add(signature.offset, 0x21))
if eq(signature.length, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(signature.length, 64), 2)) {
calldatacopy(mload(0x40), signature.offset, signature.length)
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
let v := add(shr(255, vs), 27)
let s := shr(1, shl(1, vs))
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes.
function emptySignature() internal pure returns (bytes calldata signature) {
/// @solidity memory-safe-assembly
assembly {
signature.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBit} from "./LibBit.sol";
/// @notice Library for storage of packed unsigned booleans.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)
library LibBitmap {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when a bitmap scan does not find a result.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A bitmap in storage.
struct Bitmap {
mapping(uint256 => uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the boolean value of the bit at `index` in `bitmap`.
function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
// It is better to set `isSet` to either 0 or 1, than zero vs non-zero.
// Both cost the same amount of gas, but the former allows the returned value
// to be reused without cleaning the upper bits.
uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;
/// @solidity memory-safe-assembly
assembly {
isSet := b
}
}
/// @dev Updates the bit at `index` in `bitmap` to true.
function set(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] |= (1 << (index & 0xff));
}
/// @dev Updates the bit at `index` in `bitmap` to false.
function unset(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
}
/// @dev Flips the bit at `index` in `bitmap`.
/// Returns the boolean result of the flipped bit.
function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let shift := and(index, 0xff)
let storageValue := xor(sload(storageSlot), shl(shift, 1))
// It makes sense to return the `newIsSet`,
// as it allow us to skip an additional warm `sload`,
// and it costs minimal gas (about 15),
// which may be optimized away if the returned value is unused.
newIsSet := and(1, shr(shift, storageValue))
sstore(storageSlot, storageValue)
}
}
/// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.
function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let storageValue := sload(storageSlot)
let shift := and(index, 0xff)
sstore(
storageSlot,
// Unsets the bit at `shift` via `and`, then sets its new value via `or`.
or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
)
}
}
/// @dev Consecutively sets `amount` of bits starting from the bit at `start`.
function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), max)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
}
}
/// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.
function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), 0)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(
storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
)
}
}
/// @dev Returns number of set bits within a range by
/// scanning `amount` of bits starting from the bit at `start`.
function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)
internal
view
returns (uint256 count)
{
unchecked {
uint256 bucket = start >> 8;
uint256 shift = start & 0xff;
if (!(amount + shift < 257)) {
count = LibBit.popCount(bitmap.map[bucket] >> shift);
uint256 bucketEnd = bucket + ((amount + shift) >> 8);
amount = (amount + shift) & 0xff;
shift = 0;
for (++bucket; bucket != bucketEnd; ++bucket) {
count += LibBit.popCount(bitmap.map[bucket]);
}
}
count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));
}
}
/// @dev Returns the index of the most significant set bit in `[0..upTo]`.
/// If no set bit is found, returns `NOT_FOUND`.
function findLastSet(Bitmap storage bitmap, uint256 upTo)
internal
view
returns (uint256 setBitIndex)
{
setBitIndex = NOT_FOUND;
uint256 bucket = upTo >> 8;
uint256 bits;
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, not(upTo)) // `256 - (255 & upTo) - 1`.
bits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
if iszero(or(bits, iszero(bucket))) {
for {} 1 {} {
bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.
mstore(0x00, bucket)
bits := sload(keccak256(0x00, 0x40))
if or(bits, iszero(bucket)) { break }
}
}
}
if (bits != 0) {
setBitIndex = (bucket << 8) | LibBit.fls(bits);
/// @solidity memory-safe-assembly
assembly {
setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, upTo)))
}
}
}
/// @dev Returns the index of the least significant unset bit in `[begin..upTo]`.
/// If no unset bit is found, returns `NOT_FOUND`.
function findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 upTo)
internal
view
returns (uint256 unsetBitIndex)
{
unsetBitIndex = NOT_FOUND;
uint256 bucket = begin >> 8;
uint256 negBits;
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, begin)
negBits := shl(offset, shr(offset, not(sload(keccak256(0x00, 0x40)))))
if iszero(negBits) {
let lastBucket := shr(8, upTo)
for {} 1 {} {
bucket := add(bucket, 1)
mstore(0x00, bucket)
negBits := not(sload(keccak256(0x00, 0x40)))
if or(negBits, gt(bucket, lastBucket)) { break }
}
if gt(bucket, lastBucket) {
negBits := shl(and(0xff, not(upTo)), shr(and(0xff, not(upTo)), negBits))
}
}
}
if (negBits != 0) {
uint256 r = (bucket << 8) | LibBit.ffs(negBits);
/// @solidity memory-safe-assembly
assembly {
unsetBitIndex := or(r, sub(0, or(gt(r, upTo), lt(r, begin))))
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBytes} from "./LibBytes.sol";
/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated string storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct StringStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/// @dev The input string must be a 7-bit ASCII.
error StringNot7BitASCII();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
/// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
/// @dev Lookup for '0123456789'.
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
/// @dev Lookup for '0123456789abcdefABCDEF'.
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
/// @dev Lookup for '01234567'.
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
/// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
/// @dev Lookup for ' \t\n\r\x0b\x0c'.
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRING STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the string storage `$` to `s`.
function set(StringStorage storage $, string memory s) internal {
LibBytes.set(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to `s`.
function setCalldata(StringStorage storage $, string calldata s) internal {
LibBytes.setCalldata(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to the empty string.
function clear(StringStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty string "".
function isEmpty(StringStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(StringStorage storage $) internal view returns (uint256) {
return LibBytes.length(bytesStorage($));
}
/// @dev Returns the value stored in `$`.
function get(StringStorage storage $) internal view returns (string memory) {
return string(LibBytes.get(bytesStorage($)));
}
/// @dev Helper to cast `$` to a `BytesStorage`.
function bytesStorage(StringStorage storage $)
internal
pure
returns (LibBytes.BytesStorage storage casted)
{
/// @solidity memory-safe-assembly
assembly {
casted.slot := $.slot
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end of the memory to calculate the length later.
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 1)`.
// Store the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10) // Keep dividing `temp` until zero.
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = toString(~uint256(value) + 1);
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let n := mload(result) // Load the string length.
mstore(result, 0x2d) // Store the '-' character.
result := sub(result, 1) // Move back the string pointer by a byte.
mstore(result, add(n, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2 + 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, byteCount);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(byteCount, byteCount))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := add(mload(result), 2) // Compute the length.
mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := mload(result) // Get the length.
result := add(result, o) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory result) {
result = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(result, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Allocate memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
result := add(result, 2)
mstore(result, 40) // Store the length.
let o := add(result, 0x20)
mstore(add(o, 40), 0) // Zeroize the slot after the string.
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory result) {
result = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(raw)
result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(result, add(n, n)) // Store the length of the output.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let o := add(result, 0x20)
let end := add(raw, n)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
let mask := shl(7, div(not(0), 255))
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string,
/// AND all characters are in the `allowed` lookup.
/// Note: If `s` is empty, returns true regardless of `allowed`.
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
/// @dev Converts the bytes in the 7-bit ASCII string `s` to
/// an allowed lookup for use in `is7BitASCII(s, allowed)`.
/// To save runtime gas, you can cache the result in an immutable variable.
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
revert(0x1c, 0x04)
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory)
{
return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.indexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.contains(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.startsWith(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.endsWith(bytes(subject), bytes(needle));
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
return string(LibBytes.repeat(bytes(subject), times));
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory)
{
return string(LibBytes.slice(bytes(subject), start, end));
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start) internal pure returns (string memory) {
return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory)
{
return LibBytes.indicesOf(bytes(subject), bytes(needle));
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
/// @solidity memory-safe-assembly
assembly {
result := a
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(LibBytes.concat(bytes(a), bytes(b)));
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n) // Store the length.
let o := add(result, 0x20)
mstore(o, s) // Store the bytes of the string.
mstore(add(o, n), 0) // Zeroize the slot after the string.
mstore(0x40, add(result, 0x40)) // Allocate memory.
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), c)
o := add(o, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(o, mload(0x19)) // "\\u00XX".
o := add(o, 6)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Encodes `s` so that it can be safely used in a URI,
/// just like `encodeURIComponent` in JavaScript.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
/// See: https://datatracker.ietf.org/doc/html/rfc2396
/// See: https://datatracker.ietf.org/doc/html/rfc3986
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Store "0123456789ABCDEF" in scratch space.
// Uppercased to be consistent with JavaScript's implementation.
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// If not in `[0-9A-Z-a-z-_.!~*'()]`.
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25) // '%'.
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(string memory a, string memory b) internal pure returns (int256) {
return LibBytes.cmp(bytes(a), bytes(b));
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40) // Grab the free memory pointer.
mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
mstore(result, 0) // Zeroize the length slot.
mstore(add(result, 0x1f), packed) // Store the length and bytes.
mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
or( // Load the length and the bytes of `a` and `b`.
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
// `totalLen != 0 && totalLen < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLen, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
resultA := mload(0x40) // Grab the free memory pointer.
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/CreatorTokenBase.sol";
import "../token/erc1155/ERC1155OpenZeppelin.sol";
/**
* @title ERC1155C
* @author Limit Break, Inc.
* @notice Extends OpenZeppelin's ERC1155 implementation with Creator Token functionality, which
* allows the contract owner to update the transfer validation logic by managing a security policy in
* an external transfer validation security policy registry. See {CreatorTokenTransferValidator}.
*/
abstract contract ERC1155C is ERC1155OpenZeppelin, CreatorTokenBase {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ICreatorToken).interfaceId || super.supportsInterface(interfaceId);
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory /*amounts*/,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory /*amounts*/,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
}
/**
* @title ERC1155CInitializable
* @author Limit Break, Inc.
* @notice Initializable implementation of ERC1155C to allow for EIP-1167 proxy clones.
*/
abstract contract ERC1155CInitializable is ERC1155OpenZeppelinInitializable, CreatorTokenBase {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ICreatorToken).interfaceId || super.supportsInterface(interfaceId);
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory /*amounts*/,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory /*amounts*/,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
/**
* @title BasicRoyaltiesBase
* @author Limit Break, Inc.
* @dev Base functionality of an NFT mix-in contract implementing the most basic form of programmable royalties.
*/
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
/**
* @title BasicRoyalties
* @author Limit Break, Inc.
* @notice Constructable BasicRoyalties Contract implementation.
*/
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}
/**
* @title BasicRoyaltiesInitializable
* @author Limit Break, Inc.
* @notice Initializable BasicRoyalties Contract implementation to allow for EIP-1167 clones.
*/
abstract contract BasicRoyaltiesInitializable is BasicRoyaltiesBase {}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
let bLen := mload(b)
let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
if n {
for { let i := 0x20 } 1 {} {
let x := mload(add(a, i))
let y := mload(add(b, i))
if iszero(or(xor(x, y), eq(i, n))) {
i := add(i, 0x20)
continue
}
result := sub(gt(x, y), lt(x, y))
break
}
}
// forgefmt: disable-next-item
if iszero(result) {
let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
result := sub(gt(x, y), lt(x, y))
if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
}
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
/// To load an address, you can use `address(bytes20(load(a, offset)))`.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
/// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for bit twiddling and boolean operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BIT TWIDDLING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Find last set.
/// Returns the index of the most significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
function fls(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Count leading zeros.
/// Returns the number of zeros preceding the most significant one bit.
/// If `x` is zero, returns 256.
function clz(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
/// @dev Find first set.
/// Returns the index of the least significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
/// Equivalent to `ctz` (count trailing zeros), which gives
/// the number of zeros following the least significant one bit.
function ffs(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Isolate the least significant bit.
x := and(x, add(not(x), 1))
// For the upper 3 bits of the result, use a De Bruijn-like lookup.
// Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
// forgefmt: disable-next-item
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/// @dev Returns the number of set bits in `x`.
function popCount(uint256 x) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let isMax := eq(x, max)
x := sub(x, and(shr(1, x), div(max, 3)))
x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x := and(add(x, shr(4, x)), div(max, 17))
c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
/// @dev Returns whether `x` is a power of 2.
function isPo2(uint256 x) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `x && !(x & (x - 1))`.
result := iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.
function reverseBits(uint256 x) internal pure returns (uint256 r) {
uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
uint256 m1 = m0 ^ (m0 << 2);
uint256 m2 = m1 ^ (m1 << 1);
r = reverseBytes(x);
r = (m2 & (r >> 1)) | ((m2 & r) << 1);
r = (m1 & (r >> 2)) | ((m1 & r) << 2);
r = (m0 & (r >> 4)) | ((m0 & r) << 4);
}
/// @dev Returns `x` reversed at the byte level.
function reverseBytes(uint256 x) internal pure returns (uint256 r) {
unchecked {
// Computing masks on-the-fly reduces bytecode size by about 200 bytes.
uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == uint256(0)) >> 192);
uint256 m1 = m0 ^ (m0 << 32);
uint256 m2 = m1 ^ (m1 << 16);
uint256 m3 = m2 ^ (m2 << 8);
r = (m3 & (x >> 8)) | ((m3 & x) << 8);
r = (m2 & (r >> 16)) | ((m2 & r) << 16);
r = (m1 & (r >> 32)) | ((m1 & r) << 32);
r = (m0 & (r >> 64)) | ((m0 & r) << 64);
r = (r >> 128) | (r << 128);
}
}
/// @dev Returns the common prefix of `x` and `y` at the bit level.
function commonBitPrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = 256 - clz(x ^ y);
return (x >> s) << s;
}
}
/// @dev Returns the common prefix of `x` and `y` at the nibble level.
function commonNibblePrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = (64 - (clz(x ^ y) >> 2)) << 2;
return (x >> s) << s;
}
}
/// @dev Returns the common prefix of `x` and `y` at the byte level.
function commonBytePrefix(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
uint256 s = (32 - (clz(x ^ y) >> 3)) << 3;
return (x >> s) << s;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BOOLEAN OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// A Solidity bool on the stack or memory is represented as a 256-bit word.
// Non-zero values are true, zero is false.
// A clean bool is either 0 (false) or 1 (true) under the hood.
// Usually, if not always, the bool result of a regular Solidity expression,
// or the argument of a public/external function will be a clean bool.
// You can usually use the raw variants for more performance.
// If uncertain, test (best with exact compiler settings).
// Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).
/// @dev Returns `x & y`. Inputs must be clean.
function rawAnd(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(x, y)
}
}
/// @dev Returns `x & y`.
function and(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `x | y`. Inputs must be clean.
function rawOr(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, y)
}
}
/// @dev Returns `x | y`.
function or(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.
function rawToUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.
function toUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @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;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @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) {
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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
import "../interfaces/ICreatorToken.sol";
import "../interfaces/ICreatorTokenTransferValidator.sol";
import "../utils/TransferValidation.sol";
import "@openzeppelin/contracts/interfaces/IERC165.sol";
/**
* @title CreatorTokenBase
* @author Limit Break, Inc.
* @notice CreatorTokenBase is an abstract contract that provides basic functionality for managing token
* transfer policies through an implementation of ICreatorTokenTransferValidator. This contract is intended to be used
* as a base for creator-specific token contracts, enabling customizable transfer restrictions and security policies.
*
* <h4>Features:</h4>
* <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul>
* <ul>TransferValidation: Implements the basic token transfer validation interface.</ul>
* <ul>ICreatorToken: Implements the interface for creator tokens, providing view functions for token security policies.</ul>
*
* <h4>Benefits:</h4>
* <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul>
* <ul>Allows creators to enforce policies such as whitelisted operators and permitted contract receivers.</ul>
* <ul>Can be easily integrated into other token contracts as a base contract.</ul>
*
* <h4>Intended Usage:</h4>
* <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and
* security policies.</ul>
* <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the
* creator token.</ul>
*/
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
error CreatorTokenBase__InvalidTransferValidatorContract();
error CreatorTokenBase__SetTransferValidatorFirst();
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x0000721C310194CcfC01E523fc93C9cCcFa2A0Ac);
TransferSecurityLevels public constant DEFAULT_TRANSFER_SECURITY_LEVEL = TransferSecurityLevels.One;
uint120 public constant DEFAULT_OPERATOR_WHITELIST_ID = uint120(1);
ICreatorTokenTransferValidator private transferValidator;
/**
* @notice Allows the contract owner to set the transfer validator to the official validator contract
* and set the security policy to the recommended default settings.
* @dev May be overridden to change the default behavior of an individual collection.
*/
function setToDefaultSecurityPolicy() public virtual {
_requireCallerIsContractOwner();
setTransferValidator(DEFAULT_TRANSFER_VALIDATOR);
ICreatorTokenTransferValidator(DEFAULT_TRANSFER_VALIDATOR).setTransferSecurityLevelOfCollection(address(this), DEFAULT_TRANSFER_SECURITY_LEVEL);
ICreatorTokenTransferValidator(DEFAULT_TRANSFER_VALIDATOR).setOperatorWhitelistOfCollection(address(this), DEFAULT_OPERATOR_WHITELIST_ID);
}
/**
* @notice Allows the contract owner to set the transfer validator to a custom validator contract
* and set the security policy to their own custom settings.
*/
function setToCustomValidatorAndSecurityPolicy(
address validator,
TransferSecurityLevels level,
uint120 operatorWhitelistId,
uint120 permittedContractReceiversAllowlistId) public {
_requireCallerIsContractOwner();
setTransferValidator(validator);
ICreatorTokenTransferValidator(validator).
setTransferSecurityLevelOfCollection(address(this), level);
ICreatorTokenTransferValidator(validator).
setOperatorWhitelistOfCollection(address(this), operatorWhitelistId);
ICreatorTokenTransferValidator(validator).
setPermittedContractReceiverAllowlistOfCollection(address(this), permittedContractReceiversAllowlistId);
}
/**
* @notice Allows the contract owner to set the security policy to their own custom settings.
* @dev Reverts if the transfer validator has not been set.
*/
function setToCustomSecurityPolicy(
TransferSecurityLevels level,
uint120 operatorWhitelistId,
uint120 permittedContractReceiversAllowlistId) public {
_requireCallerIsContractOwner();
ICreatorTokenTransferValidator validator = getTransferValidator();
if (address(validator) == address(0)) {
revert CreatorTokenBase__SetTransferValidatorFirst();
}
validator.setTransferSecurityLevelOfCollection(address(this), level);
validator.setOperatorWhitelistOfCollection(address(this), operatorWhitelistId);
validator.setPermittedContractReceiverAllowlistOfCollection(address(this), permittedContractReceiversAllowlistId);
}
/**
* @notice Sets the transfer validator for the token contract.
*
* @dev Throws when provided validator contract is not the zero address and doesn't support
* the ICreatorTokenTransferValidator interface.
* @dev Throws when the caller is not the contract owner.
*
* @dev <h4>Postconditions:</h4>
* 1. The transferValidator address is updated.
* 2. The `TransferValidatorUpdated` event is emitted.
*
* @param transferValidator_ The address of the transfer validator contract.
*/
function setTransferValidator(address transferValidator_) public {
_requireCallerIsContractOwner();
bool isValidTransferValidator = false;
if(transferValidator_.code.length > 0) {
try IERC165(transferValidator_).supportsInterface(type(ICreatorTokenTransferValidator).interfaceId)
returns (bool supportsInterface) {
isValidTransferValidator = supportsInterface;
} catch {}
}
if(transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(transferValidator), transferValidator_);
transferValidator = ICreatorTokenTransferValidator(transferValidator_);
}
/**
* @notice Returns the transfer validator contract address for this token contract.
*/
function getTransferValidator() public view override returns (ICreatorTokenTransferValidator) {
return transferValidator;
}
/**
* @notice Returns the security policy for this token contract, which includes:
* Transfer security level, operator whitelist id, permitted contract receiver allowlist id.
*/
function getSecurityPolicy() public view override returns (CollectionSecurityPolicy memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getCollectionSecurityPolicy(address(this));
}
return CollectionSecurityPolicy({
transferSecurityLevel: TransferSecurityLevels.Zero,
operatorWhitelistId: 0,
permittedContractReceiversId: 0
});
}
/**
* @notice Returns the list of all whitelisted operators for this token contract.
* @dev This can be an expensive call and should only be used in view-only functions.
*/
function getWhitelistedOperators() public view override returns (address[] memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getWhitelistedOperators(
transferValidator.getCollectionSecurityPolicy(address(this)).operatorWhitelistId);
}
return new address[](0);
}
/**
* @notice Returns the list of permitted contract receivers for this token contract.
* @dev This can be an expensive call and should only be used in view-only functions.
*/
function getPermittedContractReceivers() public view override returns (address[] memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getPermittedContractReceivers(
transferValidator.getCollectionSecurityPolicy(address(this)).permittedContractReceiversId);
}
return new address[](0);
}
/**
* @notice Checks if an operator is whitelisted for this token contract.
* @param operator The address of the operator to check.
*/
function isOperatorWhitelisted(address operator) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
return transferValidator.isOperatorWhitelisted(
transferValidator.getCollectionSecurityPolicy(address(this)).operatorWhitelistId, operator);
}
return false;
}
/**
* @notice Checks if a contract receiver is permitted for this token contract.
* @param receiver The address of the receiver to check.
*/
function isContractReceiverPermitted(address receiver) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
return transferValidator.isContractReceiverPermitted(
transferValidator.getCollectionSecurityPolicy(address(this)).permittedContractReceiversId, receiver);
}
return false;
}
/**
* @notice Determines if a transfer is allowed based on the token contract's security policy. Use this function
* to simulate whether or not a transfer made by the specified `caller` from the `from` address to the `to`
* address would be allowed by this token's security policy.
*
* @notice This function only checks the security policy restrictions and does not check whether token ownership
* or approvals are in place.
*
* @param caller The address of the simulated caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @return True if the transfer is allowed, false otherwise.
*/
function isTransferAllowed(address caller, address from, address to) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
try transferValidator.applyCollectionTransferPolicy(caller, from, to) {
return true;
} catch {
return false;
}
}
return true;
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 /*tokenId*/,
uint256 /*value*/) internal virtual override {
if (address(transferValidator) != address(0)) {
transferValidator.applyCollectionTransferPolicy(caller, from, to);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../../access/OwnablePermissions.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
abstract contract ERC1155OpenZeppelinBase is ERC1155 {
}
abstract contract ERC1155OpenZeppelin is ERC1155OpenZeppelinBase {
constructor(string memory uri_) ERC1155(uri_) {}
}
abstract contract ERC1155OpenZeppelinInitializable is OwnablePermissions, ERC1155OpenZeppelinBase {
error ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
bool private _erc1155Initialized;
function initializeERC1155(string memory uri_) public {
_requireCallerIsContractOwner();
if(_erc1155Initialized) {
revert ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
}
_erc1155Initialized = true;
_setURI(uri_);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev 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 {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// 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^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
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 log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract OwnablePermissions is Context {
function _requireCallerIsContractOwner() internal view virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IEOARegistry.sol";
import "./ITransferSecurityRegistry.sol";
import "./ITransferValidator.sol";
interface ICreatorTokenTransferValidator is ITransferSecurityRegistry, ITransferValidator, IEOARegistry {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../interfaces/ICreatorTokenTransferValidator.sol";
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (ICreatorTokenTransferValidator);
function getSecurityPolicy() external view returns (CollectionSecurityPolicy memory);
function getWhitelistedOperators() external view returns (address[] memory);
function getPermittedContractReceivers() external view returns (address[] memory);
function isOperatorWhitelisted(address operator) external view returns (bool);
function isContractReceiverPermitted(address receiver) external view returns (bool);
function isTransferAllowed(address caller, address from, address to) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
/**
* @title TransferValidation
* @author Limit Break, Inc.
* @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks.
* Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows
* developers to validate or customize transfers within the context of a mint, a burn, or a transfer.
*/
abstract contract TransferValidation is Context {
error ShouldNotMintToBurnAddress();
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IEOARegistry is IERC165 {
function isVerifiedEOA(address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/TransferPolicy.sol";
interface ITransferSecurityRegistry {
event AddedToAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
event CreatedAllowlist(AllowlistTypes indexed kind, uint256 indexed id, string indexed name);
event ReassignedAllowlistOwnership(AllowlistTypes indexed kind, uint256 indexed id, address indexed newOwner);
event RemovedFromAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
event SetAllowlist(AllowlistTypes indexed kind, address indexed collection, uint120 indexed id);
event SetTransferSecurityLevel(address indexed collection, TransferSecurityLevels level);
function createOperatorWhitelist(string calldata name) external returns (uint120);
function createPermittedContractReceiverAllowlist(string calldata name) external returns (uint120);
function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external;
function reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) external;
function renounceOwnershipOfOperatorWhitelist(uint120 id) external;
function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 id) external;
function setTransferSecurityLevelOfCollection(address collection, TransferSecurityLevels level) external;
function setOperatorWhitelistOfCollection(address collection, uint120 id) external;
function setPermittedContractReceiverAllowlistOfCollection(address collection, uint120 id) external;
function addOperatorToWhitelist(uint120 id, address operator) external;
function addPermittedContractReceiverToAllowlist(uint120 id, address receiver) external;
function removeOperatorFromWhitelist(uint120 id, address operator) external;
function removePermittedContractReceiverFromAllowlist(uint120 id, address receiver) external;
function getCollectionSecurityPolicy(address collection) external view returns (CollectionSecurityPolicy memory);
function getWhitelistedOperators(uint120 id) external view returns (address[] memory);
function getPermittedContractReceivers(uint120 id) external view returns (address[] memory);
function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool);
function isContractReceiverPermitted(uint120 id, address receiver) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/TransferPolicy.sol";
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
enum AllowlistTypes {
Operators,
PermittedContractReceivers
}
enum ReceiverConstraints {
None,
NoCode,
EOA
}
enum CallerConstraints {
None,
OperatorWhitelistEnableOTC,
OperatorWhitelistDisableOTC
}
enum StakerConstraints {
None,
CallerIsTxOrigin,
EOA
}
enum TransferSecurityLevels {
Zero,
One,
Two,
Three,
Four,
Five,
Six
}
struct TransferSecurityPolicy {
CallerConstraints callerConstraints;
ReceiverConstraints receiverConstraints;
}
struct CollectionSecurityPolicy {
TransferSecurityLevels transferSecurityLevel;
uint120 operatorWhitelistId;
uint120 permittedContractReceiversId;
}{
"evmVersion": "paris",
"optimizer": {
"enabled": true,
"mode": "3"
},
"outputSelection": {
"*": {
"*": [
"abi",
"metadata"
],
"": [
"ast"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"},{"internalType":"address","name":"usdc_","type":"address"},{"internalType":"address","name":"signerAddress_","type":"address"},{"internalType":"address","name":"feeRecipient_","type":"address"},{"internalType":"uint96","name":"royaltyFeeNumerator_","type":"uint96"},{"internalType":"uint256","name":"initialQueueFee","type":"uint256"},{"internalType":"uint256","name":"initialLoseQueueRefund","type":"uint256"},{"internalType":"uint256","name":"initialCreateFee","type":"uint256"},{"internalType":"uint256","name":"initialFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInQueue","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BlockhashExpired","type":"error"},{"inputs":[],"name":"BlockhashNotFound","type":"error"},{"inputs":[],"name":"BlockhashNotReady","type":"error"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"CreatorTokenBase__SetTransferValidatorFirst","type":"error"},{"inputs":[],"name":"ExceedsMaxQuantity","type":"error"},{"inputs":[],"name":"InsufficientTokensToRedeem","type":"error"},{"inputs":[],"name":"InsufficientTokensToRefund","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"LoseQueueRefundExceedsQueueFee","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotInQueue","type":"error"},{"inputs":[],"name":"OnlyTokenOwnerOrMarketplaceCanTransfer","type":"error"},{"inputs":[],"name":"PaymentFailed","type":"error"},{"inputs":[],"name":"QueueAlreadyCommitted","type":"error"},{"inputs":[],"name":"QueueAlreadyProcessed","type":"error"},{"inputs":[],"name":"QueueAlreadyRevealed","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueuePeriodEnded","type":"error"},{"inputs":[],"name":"QueueStillOpen","type":"error"},{"inputs":[],"name":"RefundTransferFailed","type":"error"},{"inputs":[],"name":"SaleEnded","type":"error"},{"inputs":[],"name":"SaleNotStarted","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"inputs":[],"name":"TokenMintingDisabled","type":"error"},{"inputs":[],"name":"TokenNotRefundable","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"DefaultRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"DropCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"QueueJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"QueueLeft","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"TokenMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"}],"name":"TokenRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"TokenRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"TokenRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DEFAULT_OPERATOR_WHITELIST_ID","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_TRANSFER_SECURITY_LEVEL","outputs":[{"internalType":"enum TransferSecurityLevels","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"batchRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"bool","name":"isBlacklisted","type":"bool"}],"name":"blacklistMarketplace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklistedMarketplaces","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"checkQueueResult","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"claimFromQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"commitQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonReserved","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"_isOE","type":"bool"},{"internalType":"bool","name":"isStripe","type":"bool"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"minMint","type":"uint256"},{"internalType":"uint256","name":"reserved","type":"uint256"}],"name":"createDrop","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"disableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"enteredQueue","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPermittedContractReceivers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSecurityPolicy","outputs":[{"components":[{"internalType":"enum TransferSecurityLevels","name":"transferSecurityLevel","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversId","type":"uint120"}],"internalType":"struct CollectionSecurityPolicy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"contract ICreatorTokenTransferValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistedOperators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"isContractReceiverPermitted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isOperatorWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isTransferAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"joinQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"leaveQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"loseQueueRefund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bool","name":"isStripe","type":"bool"},{"internalType":"uint256","name":"tax","type":"uint256"}],"name":"mintToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bool","name":"isStripe","type":"bool"},{"internalType":"uint256","name":"tax","type":"uint256"}],"name":"mintTokenByCreator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"nonceUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"queue","outputs":[{"internalType":"uint256","name":"reserved","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"uint256","name":"blockCommit","type":"uint256"},{"internalType":"uint256","name":"rng","type":"uint256"},{"internalType":"uint256","name":"entries","type":"uint256"},{"internalType":"uint256","name":"claimed","type":"uint256"},{"internalType":"uint256","name":"queueFee","type":"uint256"},{"internalType":"uint256","name":"loseQueueRefund","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queueFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"refundToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"revealQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCreateFee","type":"uint256"}],"name":"setCreateFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLoseQueueRefund","type":"uint256"}],"name":"setNewLoseQueueRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newQueueFee","type":"uint256"}],"name":"setQueueFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"refundable","type":"bool"}],"name":"setRefundableOverride","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversAllowlistId","type":"uint120"}],"name":"setToCustomSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversAllowlistId","type":"uint120"}],"name":"setToCustomValidatorAndSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setToDefaultSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_URI","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","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":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenData","outputs":[{"internalType":"uint256","name":"nonReserved","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"minMint","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"bool","name":"isOE","type":"bool"},{"internalType":"uint256","name":"reserved","type":"uint256"},{"internalType":"uint256","name":"purchased","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalRedeemed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalRefunded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000bb5a032acc5f8f10b274ca9461f26fdbda23c5e6228711c8023ea893d9e00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000012000000000000000000000000084a71ccd554cc1b02749b35d22f684cc8ec987e1000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c647807000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c64780700000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c4b4000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000000000000000000000000000000000000000002068747470733a2f2f7777772e64796c692e696f2f6170692f6d65746164617461
Deployed Bytecode
0x00020000000000020011000000000002000000000801034f0001000000010355000000600110027000000a9e0310019700000001002001900000004e0000c13d0000008001000039000000400010043f000000040030008c0000006f0000413d000000000138034f000000000208043b000000e00220027000000ab90020009c0000008a0000a13d00000aba0020009c000000cf0000a13d00000abb0020009c000002050000a13d00000abc0020009c000002700000213d00000ac30020009c0000063a0000a13d00000ac40020009c00000e940000613d00000ac50020009c00000ad80000613d00000ac60020009c0000006f0000c13d000000240030008c0000006f0000413d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d00000aab01000041000000000101041a0000000002000411000000000012004b00000edb0000c13d00000b21010000410000000c0010043f0000000b01000029000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3a011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000900000001001d000000000101041a000a00000001001d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b0000000a0010006c000015b40000a13d00000b3d01000041000000000010043f00000b300100004100002a7700010430000000a002000039000000400020043f0000000001000416000000000001004b0000006f0000c13d0000001f0130003900000a9f01100197000000a001100039000000400010043f0000001f0430018f00000aa005300198000000a001500039000000600000613d000000000608034f000000006706043c0000000002720436000000000012004b0000005c0000c13d000000000004004b0000006d0000613d000000000258034f0000000304400210000000000501043300000000054501cf000000000545022f000000000202043b0000010004400089000000000242022f00000000024201cf000000000252019f0000000000210435000001200030008c000000710000813d000000000100001900002a7700010430000000a00200043d00000aa10020009c0000006f0000213d0000001f01200039000000000031004b000000000400001900000aa20400804100000aa201100197000000000001004b000000000500001900000aa20500404100000aa20010009c000000000504c019000000000005004b0000006f0000c13d000000a001200039000000000101043300000aa10010009c0000019c0000a13d00000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a770001043000000aee0020009c000000e00000213d00000b080020009c000002350000213d00000b150020009c000002dd0000a13d00000b160020009c000006620000a13d00000b170020009c0000029f0000613d00000b180020009c00000d7e0000613d00000b190020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000b00000001001d0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000a00000001001d0000000b010000290000000201100039000000000101041a000b00000001001d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b0000000b0010006c000014ac0000813d000000400100043d00000b9e020000410000117c0000013d00000ad50020009c000001f60000213d00000ae20020009c000002870000a13d00000ae30020009c000005e90000a13d00000ae40020009c00000aaa0000613d00000ae50020009c00000a370000613d00000ae60020009c0000006f0000c13d0000000001000416000000000001004b0000006f0000c13d00000aab0100004100000d870000013d00000aef0020009c000002510000213d00000afc0020009c000002f00000a13d00000afd0020009c000006720000a13d00000afe0020009c00000edf0000613d00000aff0020009c00000d830000613d00000b000020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff0010019000000a7c0000613d0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000a00000002001d00000b4c0020009c000000840000213d000000000101043b0000000a040000290000010002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a0000006003400039000900000003001d00000000002304350000000402100039000000000202041a0000008003400039000700000003001d00000000002304350000000502100039000000000202041a000000a003400039000800000003001d00000000002304350000000602100039000000000202041a000000c0034000390000000000230435000000e0024000390000000701100039000000000101041a00000000001204350000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000200041100000aa302200197000600000002001d000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000500000000001d000019120000613d00000009010000290000000001010433000000000001004b000500000000001d000019120000613d0000000a02000029000000000302043300000008020000290000000002020433000a00000003001d000000000032004b000500000000001d000019120000813d00000007020000290000000003020433000900000003001d0000000a0030006c000019100000a13d000000400200043d00000040032000390000000604000029000000000043043500000040030000390000000003320436000000000013043500000b720020009c000000840000213d0000006001200039000000400010043f00000a9e0030009c00000a9e030080410000004001300210000000000202043300000a9e0020009c00000a9e020080410000006002200210000000000112019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b00000009101000fa0000000a0010006c00000000010000390000000101004039000019110000013d0000001f0410003900000ba7044001970000003f0440003900000ba704400197000000400500043d0000000004450019000b00000005001d000000000054004b0000000005000039000000010500403900000aa10040009c000000840000213d0000000100500190000000840000c13d000000a003300039000000400040043f0000000b040000290000000004140436000a00000004001d000000c0022000390000000004210019000000000034004b0000006f0000213d000000000001004b0000000a06000029000001be0000613d000000000300001900000000043600190000000005230019000000000505043300000000005404350000002003300039000000000013004b000001b70000413d0000000b0110002900000020011000390000000000010435000000c00100043d000900000001001d00000aa30010009c0000006f0000213d000000e00100043d000800000001001d00000aa30010009c0000006f0000213d000001000200043d00000aa30020009c0000006f0000213d000001200100043d00000aa40010009c0000006f0000213d0000000b03000029000000000403043300000aa10040009c000000840000213d0000000203000039000000000503041a000000010650019000000001055002700000007f0550618f0000001f0050008c00000000070000390000000107002039000000000076004b00000e8e0000c13d000000200050008c000001ee0000413d000000000030043f0000001f06400039000000050660027000000aa50660009a000000200040008c00000aa6060040410000001f05500039000000050550027000000aa50550009a000000000056004b000001ee0000813d000000000006041b0000000106600039000000000056004b000001ea0000413d0000001f0040008c000015050000a13d000000000030043f00000ba707400198000016090000c13d000000200600003900000aa605000041000016160000013d00000ad60020009c000002990000a13d00000ad70020009c000006020000a13d00000ad80020009c00000ab80000613d00000ad90020009c00000a570000613d00000ada0020009c0000006f0000c13d0000000001000416000000000001004b0000006f0000c13d000000150100003900000dd90000013d00000ac90020009c000002b30000a13d00000aca0020009c000006270000a13d00000acb0020009c00000ddd0000613d00000acc0020009c00000aa50000613d00000acd0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000601000039000000200010043f000000400200003900000000010000192a752a380000040f0000000702100039000000000202041a0000000603100039000000000303041a0000000504100039000000000404041a0000000405100039000000000505041a0000000306100039000000000606041a0000000207100039000000000707041a0000000108100039000000000808041a000000000101041a000000800010043f000000a00080043f000000c00070043f000000e00060043f000001000050043f000001200040043f000001400030043f000001600020043f00000b4e0100004100002a760001042e00000b090020009c000004470000a13d00000b0a0020009c000006d10000a13d00000b0b0020009c00000ef70000613d00000b0c0020009c00000d8c0000613d00000b0d0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aab02000041000000000302041a0000000002000411000000000032004b00000edb0000c13d000000000001004b000011820000c13d00000b4601000041000000800010043f00000b5a0100004100002a770001043000000af00020009c000004570000a13d00000af10020009c000006da0000a13d00000af20020009c00000f230000613d00000af30020009c00000dcc0000613d00000af40020009c0000006f0000c13d00000aab01000041000000000101041a0000000005000411000000000015004b00000edb0000c13d000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000030300003900000aad0400004100000000060000192a752a6b0000040f00000001002001900000006f0000613d00000aab01000041000000000001041b000000000100001900002a760001042e00000abd0020009c0000064b0000a13d00000abe0020009c00000eb50000613d00000abf0020009c00000bb90000613d00000ac00020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d00000b21020000410000000c0020043f000000000010043f0000000c01000039000000200200003900000dd80000013d00000ae90020009c0000047f0000213d00000aec0020009c000006f50000613d00000aed0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d000000000010043f0000000d0100003900000dd50000013d00000add0020009c000004980000213d00000ae00020009c000007020000613d00000ae10020009c0000006f0000c13d0000000001000416000000000001004b0000006f0000c13d000000c001000039000000400010043f0000000401000039000000800010043f00000b9f01000041000000a00010043f0000002001000039000000c00010043f0000008001000039000000e0020000392a7526640000040f000000c00110008a00000a9e0010009c00000a9e01008041000000600110021000000ba0011001c700002a760001042e00000ad00020009c000004b70000213d00000ad30020009c000009790000613d00000ad40020009c0000006f0000c13d0000000001000416000000000001004b0000006f0000c13d000000e001000039000000400010043f000000800000043f000000a00000043f000000c00000043f0000000301000039000000000101041a00000aa30210019800000f8a0000c13d0000014001000039000000400010043f000000e001000039000000e00000043f000001000000043f0000000002000019000000000300001900000040041000390000000000340435000000400300043d00000000022304360000002001100039000000000101043300000b23011001970000000000120435000000000104043300000b23011001970000004002300039000000000012043500000a9e0030009c00000a9e03008041000000400130021000000b5c011001c700002a760001042e00000b1c0020009c000004cf0000213d00000b1f0020009c000009ba0000613d00000b200020009c0000006f0000c13d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d0000002402800370000000000202043b2a75269e0000040f000009b30000013d00000b030020009c000004e60000213d00000b060020009c000009bf0000613d00000b070020009c0000006f0000c13d000000a40030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d0000002402800370000000000202043b000700000002001d00000aa30020009c0000006f0000213d0000004402800370000000000202043b00000aa10020009c0000006f0000213d0000002304200039000000000034004b0000006f0000813d0000000404200039000000000448034f000000000504043b00000aa10050009c000000840000213d00000005045002100000003f0640003900000b580660019700000b310060009c000000840000213d0000008006600039000000400060043f000000800050043f00000024022000390000000004240019000000000034004b0000006f0000213d000000000908034f000000000708034f000000000005004b000003280000613d0000008005000039000000000627034f000000000606043b000000200550003900000000006504350000002002200039000000000042004b000003210000413d0000006402700370000000000202043b00000aa10020009c0000006f0000213d0000002304200039000000000034004b000000000500001900000aa20500804100000aa204400197000000000004004b000000000600001900000aa20600404100000aa20040009c000000000605c019000000000006004b0000006f0000c13d0000000404200039000000000447034f000000000404043b00000aa10040009c000000840000213d00000005054002100000003f0650003900000b5806600197000000400700043d0000000006670019000400000007001d000000000076004b0000000007000039000000010700403900000aa10060009c000000840000213d0000000100700190000000840000c13d000000400060043f00000004060000290000000006460436000300000006001d00000024022000390000000005250019000000000035004b0000006f0000213d000000000709034f000000000004004b0000035d0000613d0000000404000029000000000627034f000000000606043b000000200440003900000000006404350000002002200039000000000052004b000003560000413d0000008402700370000000000402043b00000aa10040009c0000006f0000213d0000002302400039000000000032004b000000000500001900000aa20500804100000aa202200197000000000002004b000000000600001900000aa20600404100000aa20020009c000000000605c019000000000006004b0000006f0000c13d0000000405400039000000000257034f000000000202043b00000aa10020009c000000840000213d0000001f0620003900000ba7066001970000003f0660003900000ba706600197000000400700043d0000000006670019000200000007001d000000000076004b0000000007000039000000010700403900000aa10060009c000000840000213d0000000100700190000000840000c13d0000002404400039000000400060043f00000002060000290000000006260436000100000006001d0000000004420019000000000034004b0000006f0000213d0000002003500039000000000439034f00000ba7052001980000001f0620018f0000000103500029000003940000613d000000000704034f0000000108000029000000007907043c0000000008980436000000000038004b000003900000c13d000000000006004b000003a10000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f000000000043043500000001022000290000000000020435000b0aa30010019b00000000010004110000000b0010006c00001c4a0000c13d00000004010000290000000001010433000000800200043d000600000002001d000000000012004b00001d1d0000c13d000000070100002900080aa30010019c00000d740000613d000000060000006b00001dde0000c13d000000400100043d000000400200003900000000022104360000004003100039000000800400043d00000000004304350000006003100039000000000004004b000003c30000613d000000800500003900000000060000190000002005500039000000000705043300000000037304360000000106600039000000000046004b000003bd0000413d00000000041300490000000000420435000000040200002900000000040204330000000002430436000000000004004b000003d20000613d000000000300001900000004050000290000002005500039000000000605043300000000026204360000000103300039000000000043004b000003cc0000413d000000000212004900000a9e0020009c00000a9e02008041000000600220021000000a9e0010009c00000a9e010080410000004001100210000000000112019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000121019f00000aac011001c70000800d02000039000000040300003900000b900400004100000000050004110000000b0600002900000008070000292a752a6b0000040f00000001002001900000006f0000613d00000b2401000041000000000010044300000007010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b00000f210000613d000000400300043d0000004401300039000000a002000039000000000021043500000024013000390000000b02000029000000000021043500000b91010000410000000000130435000000040130003900000000020004110000000000210435000000a401300039000000800200043d0000000000210435000a00000003001d000000c401300039000000000002004b000004140000613d000000800300003900000000040000190000002003300039000000000503043300000000015104360000000104400039000000000024004b0000040e0000413d0000000a030000290000000002310049000000040220008a00000064033000390000000000230435000000040200002900000000020204330000000001210436000000000002004b000004260000613d000000000300001900000004050000290000002005500039000000000405043300000000014104360000000103300039000000000023004b000004200000413d0000000a030000290000000002310049000000040220008a00000084033000390000000000230435000000020200002900000000020204330000000001210436000000000002004b0000000106000029000004390000613d000000000300001900000000041300190000000005630019000000000505043300000000005404350000002003300039000000000023004b000004320000413d0000000003120019000000000003043500000000030004140000000804000029000000040040008c0000207a0000c13d0000000005000415000000110550008a00000005055002100000000003000031000000200030008c00000020040000390000000004034019000020af0000013d00000b100020009c000005b90000213d00000b130020009c000009d50000613d00000b140020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000b0100003900000dd50000013d00000af70020009c000005d80000213d00000afa0020009c000006ee0000613d00000afb0020009c0000006f0000c13d000000640030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d000000060010008c0000006f0000213d0000002401800370000000000101043b000a00000001001d00000b230010009c0000006f0000213d0000004401800370000000000101043b000900000001001d00000b230010009c0000006f0000213d00000aab01000041000000000101041a00000aa3011001970000000002000411000000000012004b00000f860000c13d0000000301000039000000000101041a00000aa302100198000015140000c13d00000b7101000041000000800010043f00000b5a0100004100002a770001043000000aea0020009c0000085e0000613d00000aeb0020009c0000006f0000c13d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d2a7526930000040f000b00000001001d2a75281f0000040f00000004010000390000000101100367000000000101043b000000000010043f0000000901000039000000200010043f000000400200003900000000010000192a752a380000040f000000000301041a00000ba8023001970000000b0300002900000a960000013d00000ade0020009c0000095d0000613d00000adf0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000000301000039000000000101041a00000aa302100198000009cd0000613d00000b5501000041000000800010043f0000000001000410000000840010043f0000000001000414000000040020008c000a00000002001d000011a50000c13d0000000003000031000000600030008c00000060040000390000000004034019000011c90000013d00000ad10020009c000009a40000613d00000ad20020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aab02000041000000000202041a0000000003000411000000000023004b00000edb0000c13d0000001302000039000000000202041a000000000021004b000010220000a13d00000b5901000041000000800010043f00000b5a0100004100002a770001043000000b1d0020009c00000a0a0000613d00000b1e0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000201043b00000b38002001980000006f0000c13d000000010100003900000ba20020009c0000119e0000a13d00000ba30020009c00000eb20000613d00000ba40020009c00000eb20000613d00000ba50020009c00000eb20000613d000011a20000013d00000b040020009c00000a110000613d00000b050020009c0000006f0000c13d000000840030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000004401800370000000000101043b000b00000001001d0000002401800370000000000101043b000900000001001d0000000401800370000000000101043b000a00000001001d0000006401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000404200039000000000148034f000000000101043b00000aa10010009c000000840000213d0000001f0610003900000ba7066001970000003f0660003900000ba70660019700000b310060009c000000840000213d00000024022000390000008006600039000000400060043f000000800010043f0000000002210019000000000032004b0000006f0000213d0000002002400039000000000328034f00000ba7041001980000001f0510018f000000a0024000390000051d0000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000026004b000005190000c13d000000000005004b0000052a0000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000a00110003900000000000104350000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016c70000c13d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000400100043d00000080021000390000000b03000029000000000032043500000060021000390000000903000029000000000032043500000040021000390000000a030000290000000000320435000000800200003900000000022104360000000003000411000000000032043500000b810010009c000000840000213d000000a003100039000000400030043f00000a9e0020009c00000a9e020080410000004002200210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000200010043f00000b3f01000041000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b40011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000b00000002001d000000000101043b000000800200043d000000400020008c00001c860000613d000000410020008c00001ed10000c13d000000e00200043d000000f802200270000000200020043f000000c00200043d00001c8b0000013d00000b110020009c00000a160000613d00000b120020009c0000006f0000c13d000000640030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000002401800370000000000101043b000a00000001001d00000aa30010009c0000006f0000213d0000004401800370000000000101043b000900000001001d00000aa30010009c0000006f0000213d00000001020000390000000301000039000000000101041a00000aa3031001980000144e0000c13d0000008001000039000009cf0000013d00000af80020009c00000a2a0000613d00000af90020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d2a75281f0000040f00000004010000390000000101100367000000000101043b0000001202000039000000000012041b000000000100001900002a760001042e00000ae70020009c00000a7f0000613d00000ae80020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aab02000041000000000202041a0000000003000411000000000023004b00000edb0000c13d0000001302000039000000000012041b0000001402000039000000000302041a000000000013004b00000f210000a13d000000000012041b000000000100001900002a760001042e00000adb0020009c00000a9b0000613d00000adc0020009c0000006f0000c13d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000002401800370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b0000006f0000c13d00000000020004110000000b0020006c0000132b0000c13d00000ab401000041000000800010043f0000002001000039000000840010043f0000002901000039000000a40010043f00000b6301000041000000c40010043f00000b6401000041000000e40010043f00000b650100004100002a770001043000000ace0020009c00000ac40000613d00000acf0020009c0000006f0000c13d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000002401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000000401800370000000000101043b000000000010043f000000070100003900000ea40000013d00000ac70020009c00000c740000613d00000ac80020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d2a75281f0000040f0000001701000039000006ea0000013d00000ac10020009c00000d2c0000613d00000ac20020009c0000006f0000c13d000000240030008c0000006f0000413d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d00000aab01000041000000000101041a0000000005000411000000000015004b00000edb0000c13d0000000b06000029000000000006004b000013a50000c13d00000b2f01000041000000000010043f00000b300100004100002a770001043000000b1a0020009c00000e0c0000613d00000b1b0020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d000000000010043f0000000f01000039000006fe0000013d00000b010020009c00000e710000613d00000b020020009c0000006f0000c13d000000440030008c0000006f0000413d0000000002000416000000000002004b0000006f0000c13d0000000402800370000000000202043b00000aa10020009c0000006f0000213d0000002304200039000000000034004b0000006f0000813d0000000404200039000000000448034f000000000504043b00000aa10050009c000000840000213d00000005045002100000003f0640003900000b580660019700000b310060009c000000840000213d0000008006600039000000400060043f000000800050043f00000024022000390000000004240019000000000034004b0000006f0000213d000000000908034f000000000708034f000000000005004b000006a00000613d000000a005000039000000000627034f000000000606043b00000aa30060009c0000006f0000213d00000000056504360000002002200039000000000042004b000006980000413d0000002402700370000000000202043b00000aa10020009c0000006f0000213d0000002304200039000000000034004b000000000500001900000aa20500404100000aa204400197000000000004004b000000000600001900000aa20600204100000aa20040009c000000000605c019000000000006004b0000006f0000613d0000000404200039000000000447034f000000000404043b00000aa10040009c000000840000213d00000005054002100000003f0650003900000b5806600197000000400700043d0000000006670019000800000007001d000000000076004b0000000007000039000000010700403900000aa10060009c000000840000213d0000000100700190000000840000c13d000000400060043f00000008060000290000000006460436000700000006001d00000024022000390000000005250019000000000035004b0000006f0000213d000000000004004b000018c80000c13d000000800200043d000000000002004b0000000002000019000018d70000613d000018fc0000013d00000b0e0020009c000006ee0000613d00000b0f0020009c0000006f0000c13d0000000001000416000000000001004b0000006f0000c13d000000130100003900000dd90000013d00000af50020009c00000e800000613d00000af60020009c0000006f0000c13d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d2a75281f0000040f0000001101000039000000000201041a00000ab1022001970000000b0300002900000a530000013d0000000001000416000000000001004b0000006f0000c13d0000000101000039000000800010043f00000b220100004100002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000901000039000000200010043f0000004002000039000000000100001900000ead0000013d000000840030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa10010009c0000006f0000213d0000002302100039000000000032004b0000006f0000813d0000000402100039000000000228034f000000000402043b00000aa10040009c000000840000213d00000005024002100000003f0520003900000b580550019700000b310050009c000000840000213d0000008005500039000000400050043f000000800040043f00000024011000390000000002120019000000000032004b0000006f0000213d000000000708034f000000000608034f000000000004004b0000072b0000613d0000008004000039000000000516034f000000000505043b000000200440003900000000005404350000002001100039000000000021004b000007240000413d0000002401600370000000000101043b000b00000001001d0000004401600370000000000101043b00000aa10010009c0000006f0000213d0000002302100039000000000032004b000000000400001900000aa20400804100000aa202200197000000000002004b000000000500001900000aa20500404100000aa20020009c000000000504c019000000000005004b0000006f0000c13d0000000402100039000000000226034f000000000202043b00000aa10020009c000000840000213d00000005042002100000003f0540003900000b5805500197000000400600043d0000000005560019000a00000006001d000000000065004b0000000006000039000000010600403900000aa10050009c000000840000213d0000000100600190000000840000c13d000000400050043f0000000a050000290000000005250436000900000005001d00000024011000390000000004140019000000000034004b0000006f0000213d000000000607034f000000000002004b000007630000613d0000000a02000029000000000516034f000000000505043b000000200220003900000000005204350000002001100039000000000041004b0000075c0000413d0000006401600370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b000000000400001900000aa20400804100000aa201100197000000000001004b000000000500001900000aa20500404100000aa20010009c000000000504c019000000000005004b0000006f0000c13d0000000404200039000000000146034f000000000101043b00000aa10010009c000000840000213d0000001f0510003900000ba7055001970000003f0550003900000ba705500197000000400600043d0000000005560019000800000006001d000000000065004b0000000006000039000000010600403900000aa10050009c000000840000213d0000000100600190000000840000c13d0000002402200039000000400050043f00000008050000290000000005150436000700000005001d0000000002210019000000000032004b0000006f0000213d0000002002400039000000000327034f00000ba7041001980000001f0510018f00000007024000290000079a0000613d000000000603034f0000000707000029000000006806043c0000000007870436000000000027004b000007960000c13d000000000005004b000007a70000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000070110002900000000000104350000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016c70000c13d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000400100043d000000400210003900000080040000390000000000420435000000200210003900000000030004110000000000320435000000a003100039000000800500043d0000000000530435000000c003100039000000000005004b0000080c0000613d00000000060000190000002004400039000000000704043300000000037304360000000106600039000000000056004b000008060000413d00000060041000390000000b0500002900000000005404350000000004130049000000200440008a000000800510003900000000004504350000000a0400002900000000040404330000000003430436000000000004004b000008200000613d00000000050000190000000a060000290000002006600039000000000706043300000000037304360000000105500039000000000045004b0000081a0000413d0000000003130049000000200430008a00000000004104350000001f0330003900000ba7043001970000000003140019000000000043004b0000000004000039000000010400403900000aa10030009c000000840000213d0000000100400190000000840000c13d000000400030043f00000a9e0020009c00000a9e020080410000004002200210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000200010043f00000b3f01000041000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b40011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000b00000002001d000000000101043b00000008020000290000000002020433000000400020008c000022b50000613d000000410020008c00001ed10000c13d000000080300002900000060023000390000000002020433000000f802200270000000200020043f00000040023000390000000002020433000022bc0000013d000000a40030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d0000002401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000404200039000000000148034f000000000101043b00000aa10010009c000000840000213d0000001f0610003900000ba7066001970000003f0660003900000ba70660019700000b310060009c000000840000213d00000024022000390000008006600039000000400060043f000000800010043f0000000002210019000000000032004b0000006f0000213d000000000908034f0000002002400039000000000328034f00000ba7041001980000001f0510018f000000a0024000390000088c0000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000026004b000008880000c13d000000000005004b000008990000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000a00110003900000000000104350000004401900370000000000101043b000a00000001001d0000006401900370000000000201043b000000000002004b0000000001000039000000010100c039000900000002001d000000000012004b0000006f0000c13d0000008401900370000000000101043b000800000001001d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000a02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016c70000c13d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000a02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b0000000b01000029000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000600000001001d0000000301100039000000000101041a000700000001001d000000000001004b0000091a0000613d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000070010006c00000d290000213d000000400100043d000000a0021000390000000803000029000000000032043500000080021000390000000903000029000000000032043500000060021000390000000a03000029000000000032043500000040021000390000000b030000290000000000320435000000a0020000390000000002210436000000000300041100000aa303300197000a00000003001d000000000032043500000b3e0010009c000000840000213d000000c003100039000000400030043f00000a9e0020009c00000a9e020080410000004002200210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000200010043f00000b3f01000041000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b40011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000700000002001d000000000101043b000000800200043d000000400020008c00001e320000613d000000410020008c00001ed10000c13d000000e00200043d000000f802200270000000200020043f000000c00200043d00001e370000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000201043b0000000601200039000000000101041a000000000001004b00000fab0000c13d000000400100043d00000b9d020000410000117c0000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000801000039000000200010043f000000400200003900000000010000192a752a380000040f0000000702100039000000000202041a0000000603100039000000000303041a0000000504100039000000000404041a0000000405100039000000000505041a0000000306100039000000000606041a0000000207100039000000000707041a0000000108100039000000000808041a000000000101041a000000800010043f000000a00080043f000000c00070043f000000e00060043f000001000050043f00000aa301400197000001200010043f00000b5d004001980000000001000039000000010100c039000001400010043f000001600030043f000001800020043f00000b5e0100004100002a760001042e000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000002401800370000000000201043b00000aa30020009c0000006f0000213d0000000401800370000000000101043b2a7527890000040f000000000001004b0000000001000039000000010100c039000000400200043d000000000012043500000a9e0020009c00000a9e02008041000000400120021000000b4d011001c700002a760001042e0000000001000416000000000001004b0000006f0000c13d000000100100003900000dd90000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000000301000039000000000101041a00000aa30210019800000fc00000c13d0000008001000039000000010200018f000000000021043500000a9e0010009c00000a9e01008041000000400110021000000b4d011001c700002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000012001000039000000400010043f0000010001000039000001000000043f0000000402800370000000000202043b0000000003010019000000090020008c0000000a1220011a000000f804100210000000010130008a000000000501043300000b9905500197000000000445019f00000b9a044001c70000000000410435000009e00000213d0000010102300089000000210330008a00000000002304350000001604000039000000000204041a000000010520019000000001092002700000007f0990618f0000001f0090008c00000000060000390000000106002039000000000662013f000000010060019000000e8e0000c13d000000400800043d000000000005004b00000fcd0000613d000000000040043f000000000009004b00000fd00000613d00000aaf02000041000000200480003900000000050000190000000006540019000000000702041a000000000076043500000001022000390000002005500039000000000095004b00000a020000413d00000fd00000013d0000000001000416000000000001004b0000006f0000c13d00000b6d01000041000000800010043f00000b220100004100002a760001042e0000000001000416000000000001004b0000006f0000c13d000000140100003900000dd90000013d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d000000000010043f0000000e01000039000000200010043f00000040020000390000000001000019000b0000000803532a752a380000040f0000000b0200035f0000002402200370000000000202043b00000ea90000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d2a75281f0000040f00000004010000390000000101100367000000000101043b0000001502000039000000000012041b000000000100001900002a760001042e000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d2a7526930000040f000a00000001001d2a75281f0000040f0000001801000039000000200010043f0000000b010000290000000801100270000000000010043f000000400200003900000000010000192a752a380000040f0000000b02000029000000ff0220018f0000000a0000006b0000000003000039000000010300c03900000000032301cf00000ba9022002df000000000401041a000000000224016f000000000232019f000000000021041b000000000100001900002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000012770000c13d000000400100043d00000b78020000410000117c0000013d000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d2a7526930000040f000a00000001001d2a75281f0000040f0000000b01000029000000000010043f0000000f01000039000000200010043f000000400200003900000000010000192a752a380000040f000000000301041a00000ba8023001970000000a03000029000000000003004b000000010220c1bf000000000021041b000000000100001900002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000a0100003900000dd50000013d0000000001000416000000000001004b0000006f0000c13d000000120100003900000dd90000013d0000000001000416000000000001004b0000006f0000c13d0000000001000412000f00000001001d000e00000000003d0000800501000039000000440300003900000000040004150000000f0440008a000000050440021000000b2a020000412a752a4d0000040f00000d880000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d2a7526e00000040f000000000100001900002a760001042e0000000002000416000000000002004b0000006f0000c13d0000000302000039000000000202041a00000aa30220019800000e780000613d00000b5503000041000000800030043f0000000003000410000000840030043f0000000003000414000000040020008c000b00000002001d000010260000c13d0000000003000031000000600030008c000000600400003900000000040340190000104a0000013d000000c40030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d0000002401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000404200039000000000148034f000000000101043b00000aa10010009c000000840000213d0000001f0610003900000ba7066001970000003f0660003900000ba70660019700000b310060009c000000840000213d00000024022000390000008006600039000000400060043f000000800010043f0000000002210019000000000032004b0000006f0000213d000000000908034f0000002002400039000000000328034f00000ba7041001980000001f0510018f000000a00240003900000b060000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000026004b00000b020000c13d000000000005004b00000b130000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000a00110003900000000000104350000004401900370000000000101043b000a00000001001d00000aa30010009c0000006f0000213d0000006401900370000000000101043b000900000001001d0000008401900370000000000201043b000000000002004b0000000001000039000000010100c039000800000002001d000000000012004b0000006f0000c13d000000a401900370000000000101043b000700000001001d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000902000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016c70000c13d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000902000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000400100043d000000a0021000390000000703000029000000000032043500000080021000390000000803000029000000000032043500000060021000390000000903000029000000000032043500000040021000390000000b030000290000000000320435000000a0020000390000000002210436000000000300041100000aa303300197000000000032043500000b3e0010009c000000840000213d000000c003100039000000400030043f00000a9e0020009c00000a9e020080410000004002200210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000200010043f00000b3f01000041000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b40011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000900000002001d000000000101043b000000800200043d000000400020008c00001d6f0000613d000000410020008c00001ed10000c13d000000e00200043d000000f802200270000000200020043f000000c00200043d00001d740000013d000000840030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000b00000001001d00000aa30010009c0000006f0000213d0000002401800370000000000101043b000a00000001001d000000060010008c0000006f0000213d0000004401800370000000000101043b000900000001001d00000b230010009c0000006f0000213d0000006401800370000000000101043b000800000001001d00000b230010009c0000006f0000213d00000aab01000041000000000101041a00000aa3011001970000000002000411000000000012004b00000f860000c13d0000000b010000292a7526e00000040f00000b240100004100000000001004430000000b010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000a02000029000000000021043500000b26010000410000000000130435000000000100041000000aa302100197000a00000003001d0000000401300039000700000002001d000000000021043500000000010004140000000b02000029000000040020008c00000c090000613d0000000a0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000b020000292a752a6b0000040f000000600310027000000a9e0030019d00000001002001900000187c0000613d0000000a0100002900000aa10010009c000000840000213d0000000a01000029000000400010043f00000b240100004100000000001004430000000b010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000902000029000000000021043500000b28010000410000000000130435000a00000003001d00000004013000390000000702000029000000000021043500000000010004140000000b02000029000000040020008c00000c3b0000613d0000000a0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000b020000292a752a6b0000040f000000600310027000000a9e0030019d000000010020019000001a5f0000613d0000000a0100002900000aa10010009c000000840000213d0000000a01000029000000400010043f00000b240100004100000000001004430000000b010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000802000029000000000021043500000b29010000410000000000130435000a00000003001d00000004013000390000000702000029000000000021043500000000010004140000000b02000029000000040020008c00000c6d0000613d0000000a0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000b020000292a752a6b0000040f000000600310027000000a9e0030019d000000010020019000001d100000613d0000000a0100002900000aa10010009c000000840000213d0000000a01000029000000400010043f000000000100001900002a760001042e000001440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000004401800370000000000201043b000000000002004b0000000001000039000000010100c039000b00000002001d000000000012004b0000006f0000c13d0000006401800370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b0000006f0000c13d0000008401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000404200039000000000148034f000000000101043b00000aa10010009c000000840000213d0000001f0610003900000ba7066001970000003f0660003900000ba70660019700000b310060009c000000840000213d00000024022000390000008006600039000000400060043f000000800010043f0000000002210019000000000032004b0000006f0000213d0000002002400039000000000328034f00000ba7041001980000001f0510018f000000a00240003900000cae0000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000026004b00000caa0000c13d000000000005004b00000cbb0000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000a00110003900000000000104350000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000a4020000390000000102200367000000000202043b000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016c70000c13d0000000001000411000000000010043f0000000e01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000a4020000390000000102200367000000000202043b000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000001000411000000000010043f0000000d01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b0000000102000367000000c401200370000000000101043b000900000001001d000000000001004b00000d240000c13d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d0000000102000367000000000101043b000900000001001d000000e401200370000000000401043b000000010140008a000000090010006c00001bf50000813d000000400100043d00000b6c020000410000117c0000013d000000a40030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000901043b00000aa30090009c0000006f0000213d0000002401800370000000000101043b000800000001001d00000aa30010009c0000006f0000213d0000008401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000404200039000000000148034f000000000101043b00000aa10010009c000000840000213d0000001f0510003900000ba7055001970000003f0550003900000ba70550019700000b310050009c000000840000213d00000024022000390000008005500039000000400050043f000000800010043f0000000002210019000000000032004b0000006f0000213d000900000009001d0000002002400039000000000328034f00000ba7041001980000001f0510018f000000a00240003900000d600000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000026004b00000d5c0000c13d000000000005004b00000d6d0000613d000000000343034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000a00110003900000000000104350000000002000411000000090020006c000016e10000c13d000000080000006b000017790000c13d000000400100043d000000640210003900000b92030000410000000000320435000000440210003900000b9303000041000000000032043500000024021000390000002503000039000019050000013d0000000001000416000000000001004b0000006f0000c13d000000030100003900000d870000013d0000000001000416000000000001004b0000006f0000c13d0000001101000039000000000101041a00000aa301100197000000800010043f00000b220100004100002a760001042e000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000002401800370000000000101043b000b00000001001d0000000401800370000000000101043b000000000010043f0000000501000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400300043d00000aa80030009c000000840000213d000000000101043b0000004002300039000000400020043f000000000101041a0000002004300039000000a002100270000000000024043500000aa301100198000000000013043500000dbb0000c13d000000400300043d00000aa80030009c000000840000213d0000004001300039000000400010043f0000000401000039000000000101041a0000002004300039000000a002100270000000000024043500000aa30110019700000000001304350000000b0400002900000000034200a9000000000004004b00000dc20000613d00000000044300d9000000000042004b000016cc0000c13d000027100230011a000000400300043d00000020043000390000000000240435000000000013043500000a9e0030009c00000a9e03008041000000400130021000000b96011001c700002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000c01000039000000200010043f000000400200003900000000010000192a752a380000040f000000000101041a000000800010043f00000b220100004100002a760001042e000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000303100039000000000203041a000000000002004b0000117a0000c13d000a00000003001d0000000201100039000000000101041a000b00000001001d00000b50010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000900000001001d0000000b02000029000000000021004b000014910000813d000000400100043d00000b54020000410000117c0000013d000000240030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000201043b00000aa10020009c0000006f0000213d0000002301200039000000000031004b0000006f0000813d0000000405200039000000000158034f000000000101043b00000aa10010009c000000840000213d0000001f0610003900000ba7066001970000003f0660003900000ba70660019700000b310060009c000000840000213d00000024022000390000008006600039000000400060043f000000800010043f0000000002210019000000000032004b0000006f0000213d0000002002500039000000000328034f00000ba7051001980000001f0610018f000000a00250003900000e360000613d000000a007000039000000000803034f000000008908043c0000000007970436000000000027004b00000e320000c13d000000000006004b00000e430000613d000000000353034f0000000305600210000000000602043300000000065601cf000000000656022f000000000303043b0000010005500089000000000353022f00000000035301cf000000000363019f0000000000320435000000a001100039000000000001043500000aab01000041000000000101041a0000000002000411000000000012004b00000edb0000c13d000000800200043d00000aa10020009c000000840000213d0000001601000039000000000501041a000000010050019000000001035002700000007f0330618f0000001f0030008c00000000060000390000000106002039000000000565013f000000010050019000000e8e0000c13d000000200030008c00000e690000413d000000000010043f0000001f05200039000000050550027000000aae0550009a000000200020008c00000aaf050040410000001f03300039000000050330027000000aae0330009a000000000035004b00000e690000813d000000000005041b0000000105500039000000000035004b00000e650000413d0000001f0020008c000017e70000a13d000000000010043f00000ba704200198000018ab0000c13d000000a00500003900000aaf03000041000018b90000013d0000000002000416000000000002004b0000006f0000c13d0000000302000039000000000202041a00000aa30220019800000f960000c13d000000a001000039000000400010043f0000008002000039000000800000043f000000400100043d000b00000001001d2a7526760000040f000013150000013d0000000001000416000000000001004b0000006f0000c13d0000001603000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000552013f000000010050019000000fa30000613d00000b8d01000041000000000010043f0000002201000039000000040010043f00000b2d0100004100002a7700010430000000440030008c0000006f0000413d0000000001000416000000000001004b0000006f0000c13d0000000401800370000000000101043b00000aa30010009c0000006f0000213d0000002402800370000000000202043b000b00000002001d00000aa30020009c0000006f0000213d000000000010043f0000000101000039000000200010043f000000400200003900000000010000192a752a380000040f0000000b02000029000000000020043f000000200010043f000000000100001900000040020000392a752a380000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000b220100004100002a760001042e0000000001000416000000000001004b0000006f0000c13d00000aab01000041000000000101041a0000000002000411000000000012004b00000edb0000c13d00000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000400b00043d00000b2c0100004100000000001b04350000000401b0003900000000030004100000000000310435000000000100041400000aa302200197000000040020008c000a00000002001d0000135b0000c13d0000000004000031000000200040008c0000002004008039000013860000013d00000ba101000041000000000010043f00000b300100004100002a770001043000000b21010000410000000c0010043f0000000001000411000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3a011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000001041b000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000020300003900000b790400004100000f1d0000013d00000b21010000410000000c0010043f0000000001000411000000000010043f00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000b00000001001d000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3a011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b0200002900000b970220009a000000000021041b000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000020300003900000b980400004100000000050004112a752a6b0000040f00000001002001900000006f0000613d000000000100001900002a760001042e0000000001000416000000000001004b0000006f0000c13d00000aab01000041000000000101041a00000aa3011001970000000002000411000000000012004b00000f860000c13d00000b2401000041000000000010044300000b6d010000410000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000400300043d000000000101043b000000000001004b000014a50000613d00000b6e0100004100000000001304350000000401300039000000000001043500000a9e0030009c00000a9e0100004100000000010340190000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b2d011001c700000b6d02000041000b00000003001d2a752a700000040f0000000b0b000029000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900000f5e0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000f5a0000c13d000000000006004b00000f6b0000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f0000000000150435000000000003001f0000000100200190000014a40000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200030008c0000006f0000413d0000000b020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b000017f10000c13d0000000003010019000014a50000013d00000b4401000041000000800010043f00000b5a0100004100002a770001043000000b5501000041000000e00010043f0000000001000410000000e40010043f0000000001000414000000040020008c00000fe90000c13d0000000003000031000000600030008c000000600400003900000000040340190000100d0000013d00000b5503000041000000800030043f0000000003000410000000840030043f0000000003000414000000040020008c000b00000002001d000010cd0000c13d0000000003000031000000600030008c00000060040000390000000004034019000010f10000013d000000800010043f000000000004004b000011740000613d000000000030043f000000000001004b000013010000c13d000000a0010000390000130c0000013d000900000002001d0000000201200039000000000101041a000a00000001001d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b0000000a0010006c000013b50000a13d000000400100043d00000b69020000410000117c0000013d00000b5501000041000000800010043f0000000001000410000000840010043f0000000001000414000000040020008c000a00000002001d000012220000c13d0000000003000031000000600030008c00000060040000390000000004034019000012460000013d00000ba802200197000000200480003900000000002404350000000002890019000000200420003900000b9b05000041000000000054043500000021022000390000000003030433000a00000003001d000b00000008001d000900000009001d2a7526570000040f00000009020000290000000a0320002900000001023000390000000b01000029000000000021043500000021023000392a7526450000040f0000002001000039000000400200043d000a00000002001d00000000021204360000000b010000292a7526640000040f0000000a02000029000013160000013d00000a9e0010009c00000a9e01008041000000c00110021000000b5b011001c72a752a700000040f000000e00a000039000000600310027000000a9e03300197000000600030008c000000600400003900000000040340190000001f0640018f0000006007400190000000e00570003900000ffd0000613d000000000801034f000000008908043c000000000a9a043600000000005a004b00000ff90000c13d000000000006004b0000100a0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00000001002001900000126b0000613d0000001f01400039000000e00410018f000000e001400039000000400010043f000000600030008c0000006f0000413d0000014002400039000000400020043f000000e00200043d000000060020008c0000006f0000213d0000000000210435000001000300043d00000b230030009c0000006f0000213d00000100044001bf0000000000340435000001200300043d00000b230030009c000002cc0000a13d0000006f0000013d0000001402000039000000000012041b000000000100001900002a760001042e00000a9e0030009c00000a9e03008041000000c00130021000000b56011001c72a752a700000040f000000800a000039000000600310027000000a9e03300197000000600030008c000000600400003900000000040340190000001f0640018f000000600740019000000080057001bf0000103a0000613d000000000801034f000000008908043c000000000a9a043600000000005a004b000010360000c13d000000000006004b000010470000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000012f50000613d0000001f02400039000000e00220018f0000008004200039000000400040043f000000600030008c0000006f0000413d000000e005200039000000400050043f000000800500043d000000060050008c0000006f0000213d0000000000540435000000a00400043d00000b230040009c0000006f0000213d000000a0052000390000000000450435000000c00400043d00000b230040009c0000006f0000213d000000c002200039000000000042043500000b5702000041000000400500043d0000000000250435000a00000005001d0000000402500039000000000042043500000000020004140000000b04000029000000040040008c0000107a0000613d0000000a0100002900000a9e0010009c00000a9e01008041000000400110021000000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b2d011001c70000000b020000292a752a700000040f000000600310027000000a9e0030019d00000a9e033001970000000100200190000017610000613d00000ba7053001980000001f0630018f0000000a04500029000010840000613d000000000701034f0000000a08000029000000007907043c0000000008980436000000000048004b000010800000c13d000000000006004b000010910000613d000000000151034f0000000305600210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000001f0130003900000ba7011001970000000a02100029000000000012004b0000000001000039000000010100403900000aa10020009c000000840000213d0000000100100190000000840000c13d000000400020043f00000b410030009c0000006f0000213d000000200030008c0000006f0000413d0000000a01000029000000000101043300000aa10010009c0000006f0000213d0000000a033000290000000a011000290000001f04100039000000000034004b000000000500001900000aa20500804100000aa20440019700000aa206300197000000000764013f000000000064004b000000000400001900000aa20400404100000aa20070009c000000000405c019000000000004004b0000006f0000c13d000000001401043400000aa10040009c000000840000213d00000005054002100000003f0650003900000b5806600197000000000626001900000aa10060009c000000840000213d000000400060043f00000000004204350000000004150019000000000034004b0000006f0000213d000000000041004b00000e7c0000813d0000000003020019000000001501043400000aa30050009c0000006f0000213d00000020033000390000000000530435000000000041004b000010c50000413d00000e7c0000013d00000a9e0030009c00000a9e03008041000000c00130021000000b56011001c72a752a700000040f000000600310027000000a9e03300197000000600030008c000000600400003900000000040340190000001f0640018f000000600740019000000080057001bf000010e10000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000010dd0000c13d000000000006004b000010ee0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00000001002001900000131f0000613d0000001f02400039000000e00220018f0000008004200039000000400040043f000000600030008c0000006f0000413d000000e005200039000000400050043f000000800500043d000000060050008c0000006f0000213d0000000000540435000000a00400043d00000b230040009c0000006f0000213d000000a0052000390000000000450435000000c00500043d00000b230050009c0000006f0000213d000000c002200039000000000052043500000b7f02000041000000400500043d0000000000250435000a00000005001d0000000402500039000000000042043500000000020004140000000b04000029000000040040008c000011210000613d0000000a0100002900000a9e0010009c00000a9e01008041000000400110021000000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b2d011001c70000000b020000292a752a700000040f000000600310027000000a9e0030019d00000a9e0330019700000001002001900000176d0000613d00000ba7053001980000001f0630018f0000000a045000290000112b0000613d000000000701034f0000000a08000029000000007907043c0000000008980436000000000048004b000011270000c13d000000000006004b000011380000613d000000000151034f0000000305600210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000001f0130003900000ba7011001970000000a02100029000000000012004b0000000001000039000000010100403900000aa10020009c000000840000213d0000000100100190000000840000c13d000000400020043f00000b410030009c0000006f0000213d000000200030008c0000006f0000413d0000000a01000029000000000101043300000aa10010009c0000006f0000213d0000000a033000290000000a011000290000001f04100039000000000034004b000000000500001900000aa20500804100000aa20440019700000aa206300197000000000764013f000000000064004b000000000400001900000aa20400404100000aa20070009c000000000405c019000000000004004b0000006f0000c13d000000001401043400000aa10040009c000000840000213d00000005054002100000003f0650003900000b5806600197000000000626001900000aa10060009c000000840000213d000000400060043f00000000004204350000000004150019000000000034004b0000006f0000213d000000000041004b00000e7c0000813d0000000003020019000000001501043400000aa30050009c0000006f0000213d00000020033000390000000000530435000000000041004b0000116c0000413d00000e7c0000013d00000ba802200197000000a00020043f000000000001004b000000c001000039000000a0010060390000130c0000013d000000400100043d00000b4f02000041000000000021043500000a9e0010009c00000a9e01008041000000400110021000000b34011001c700002a770001043000000b2e03000041000000800030043f00000aa302200197000000840020043f000000a40010043f00000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c000014d60000c13d000000000a0000310000002000a0008c000000200a008039000014fb0000013d00000b6e0020009c00000eb20000613d00000ba60020009c00000eb20000613d000000800000043f00000b220100004100002a760001042e00000a9e0010009c00000a9e01008041000000c00110021000000b56011001c72a752a700000040f000000600310027000000a9e03300197000000600030008c000000600400003900000000040340190000001f0640018f000000600740019000000080057001bf000011b90000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000011b50000c13d000000000006004b000011c60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000014360000613d0000001f01400039000000e00110018f0000008002100039000000400020043f000000600030008c0000006f0000413d000000e004100039000000400040043f000000800400043d000000060040008c0000006f0000213d0000000000420435000000a00200043d00000b230020009c0000006f0000213d000000a0041000390000000000240435000000c00200043d00000b230020009c0000006f0000213d000000c0011000390000000000210435000000400500043d00000024015000390000000b04000029000000000041043500000b66010000410000000000150435000900000005001d0000000401500039000000000021043500000000010004140000000a02000029000000040020008c000012690000613d000000090200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000a020000292a752a700000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000905700029000012060000613d000000000801034f0000000909000029000000008a08043c0000000009a90436000000000059004b000012020000c13d000000000006004b000012130000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00000001002001900000174b0000c13d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000121d0000c13d000018950000013d00000a9e0010009c00000a9e01008041000000c00110021000000b56011001c72a752a700000040f000000600310027000000a9e03300197000000600030008c000000600400003900000000040340190000001f0640018f000000600740019000000080057001bf000012360000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000012320000c13d000000000006004b000012430000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000014420000613d0000001f01400039000000e00110018f0000008002100039000000400020043f000000600030008c0000006f0000413d000000e004100039000000400040043f000000800400043d000000060040008c0000006f0000213d0000000000420435000000a00200043d00000b230020009c0000006f0000213d000000a0041000390000000000240435000000c00400043d00000b230040009c0000006f0000213d000000c0011000390000000000410435000000400500043d00000024015000390000000b04000029000000000041043500000b94010000410000000000150435000900000005001d0000000401500039000000000021043500000000010004140000000a02000029000000040020008c000017210000c13d00000020040000390000174b0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012720000c13d000018950000013d0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000201100039000000000101041a000000000001004b000015110000c13d0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000102100039000000000202041a0000000601100039000000000101041a000a00000002001d000900000001001d000000000021001a000016cc0000413d0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba802200197000000000021041b0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000401100039000000000201041a000000000002004b000016cc0000613d00000009040000290000000a03400029000000010220008a000000000021041b000000400200043d0000002401200039000900000003001d000000000031043500000b2e010000410000000000120435000000000100041100000aa301100197000a00000002001d0000000402200039000000000012043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c00001a040000c13d0000000004000031000000200040008c000000200400803900001a2d0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012fc0000c13d000018950000013d00000aaf0200004100000000040000190000000003040019000000000402041a000000a005300039000000000045043500000001022000390000002004300039000000000014004b000013030000413d000000c001300039000000800210008a00000080010000392a7526450000040f0000002001000039000000400200043d000b00000002001d000000000212043600000080010000392a7526640000040f0000000b02000029000000000121004900000a9e0010009c00000a9e01008041000000600110021000000a9e0020009c00000a9e020080410000004002200210000000000121019f00002a760001042e0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000013260000c13d000018950000013d000000000020043f0000000101000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba8022001970000000a03000029000000000232019f000000000021041b000000400100043d000000000031043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aa9011001c70000800d02000039000000030300003900000b620400004100000000050004110000000b0600002900000f1e0000013d00000a9e00b0009c00000a9e0300004100000000030b4019000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000b2d011001c7000b0000000b001d2a752a700000040f0000000b0b000029000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000013760000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000013720000c13d000000000006004b000013830000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000014850000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000b00000002001d00000aa10020009c000000840000213d0000000100100190000000840000c13d0000000b01000029000000400010043f000000200040008c0000006f0000413d00000000010b04330000000b030000290000002402300039000000000012043500000b2e010000410000000000130435000000000100041100000aa3011001970000000402300039000000000012043500000000010004140000000a02000029000000040020008c000015d50000c13d000000200a000039000016000000013d000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000030300003900000aad040000412a752a6b0000040f00000001002001900000006f0000613d00000aab010000410000000b02000029000000000021041b000000000100001900002a760001042e0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000016de0000c13d0000001301000039000000000201041a00000009010000290000000101100039000000000101041a000a00000002001d000900000001001d000000000012001a000016cc0000413d0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba80220019700000001022001bf000000000021041b0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000401100039000000000201041a000000010220003a000016cc0000613d00000009040000290000000a03400029000000000021041b000000400400043d0000004401400039000900000003001d0000000000310435000000000100041000000aa3011001970000002402400039000000000012043500000b45010000410000000000140435000000000100041100000aa301100197000a00000004001d0000000402400039000000000012043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c00001aa30000c13d0000000004000031000000200040008c000000200400803900001acc0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000143d0000c13d000018950000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000014490000c13d000018950000013d00000b24010000410000000000100443000800000003001d0000000400300443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400200043d00000044012000390000000903000029000000000031043500000024012000390000000a03000029000000000031043500000b35010000410000000000120435000a00000002001d00000004012000390000000b02000029000000000021043500000000010004140000000802000029000000040020008c0000147e0000613d0000000a0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000ab5011001c700000008020000292a752a700000040f000000600110027000000a9e0010019d0000000100200190000017e10000613d0000000a0100002900000aa10010009c000000840000213d0000000a01000029000000400010043f0000000102000039000009cf0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000148c0000c13d000018950000013d00000b510100004100000000001004430000000400200443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d0000000b03000029000000000101043b000000000001004b000016ca0000c13d000000400100043d00000b53020000410000117c0000013d000000400300043d00000b7001000041000000000013043500000a9e0030009c00000a9e03008041000000400130021000000b34011001c700002a77000104300000000a02000029000000000102041a000000000001004b000009760000613d0000000201200039000b00000001001d000000000201041a000900000002001d00000ba80020009c000016cc0000813d00000b50010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b00000009020000290000010002200039000000000021004b000014cb0000a13d0000000a020000290000000302200039000000000202041a000000000002004b000014cf0000613d0000000b02000029000000000202041a000000000002004b000018790000c13d00000baa0010009c000016cc0000213d00000005011000390000000b02000029000000000012041b000000000100001900002a760001042e00000a9e0010009c00000a9e01008041000000c00110021000000b95011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000000a040019000000200640019000000080046001bf000014eb0000613d0000008007000039000000000801034f000000008908043c0000000007970436000000000047004b000014e70000c13d000000000005004b000014f80000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000000000003001f0000000100200190000015c90000613d000000800100003900000000020a0019000b0000000a001d2a7526450000040f0000000b0100002900000080021001bf00000080010000392a7526d20000040f000000000100001900002a760001042e000000000004004b00000000050000190000150a0000613d0000000a050000290000000005050433000000030640021000000bab0660027f00000bab06600167000000000565016f0000000104400210000000000445019f000016220000013d000000400100043d00000b5f020000410000117c0000013d00000b24010000410000000000100443000800000002001d0000000400200443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000b02000029000000000021043500000b26010000410000000000130435000000000100041000000aa302100197000b00000003001d0000000401300039000700000002001d000000000021043500000000010004140000000802000029000000040020008c000015430000613d0000000b0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c700000008020000292a752a6b0000040f000000600310027000000a9e0030019d0000000100200190000018890000613d0000000b0100002900000aa10010009c000000840000213d0000000b01000029000000400010043f00000b2401000041000000000010044300000008010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000a02000029000000000021043500000b28010000410000000000130435000b00000003001d00000004013000390000000702000029000000000021043500000000010004140000000802000029000000040020008c000015750000613d0000000b0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c700000008020000292a752a6b0000040f000000600310027000000a9e0030019d000000010020019000001a6c0000613d0000000b0100002900000aa10010009c000000840000213d0000000b01000029000000400010043f00000b2401000041000000000010044300000008010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000902000029000000000021043500000b29010000410000000000130435000b00000003001d00000004013000390000000702000029000000000021043500000000010004140000000802000029000000040020008c000018660000613d0000000b0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c700000008020000292a752a6b0000040f000000600310027000000a9e0030019d0000000100200190000018660000c13d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000015af0000c13d000018950000013d0000000901000029000000000001041b00000aab01000041000000000501041a000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000030300003900000aad040000410000000b060000292a752a6b0000040f00000001002001900000006f0000613d0000000b0100002900000aab02000041000000000012041b000000000100001900002a760001042e0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000015d00000c13d000018950000013d0000000b0200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000a020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000000a04001900000020064001900000000b04600029000015f00000613d000000000701034f0000000b08000029000000007907043c0000000008980436000000000048004b000015ec0000c13d000000000005004b000015fd0000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000000000003001f0000000100200190000016d20000613d0000000b0100002900000000020a0019000a0000000a001d2a7526450000040f0000000b010000290000000a021000292a7526d20000040f000000000100001900002a760001042e00000aa6050000410000002006000039000000010870008a000000050880027000000aa70880009a0000000b0a0000290000000009a600190000000009090433000000000095041b00000020066000390000000105500039000000000085004b0000160f0000c13d000000000047004b000016200000813d0000000307400210000000f80770018f00000bab0770027f00000bab077001670000000b066000290000000006060433000000000676016f000000000065041b000000010440021000000001044001bf000001a00500043d000500000005001d000001800500043d000700000005001d000001600500043d000600000005001d000001400500043d000400000005001d000000000043041b000000400300043d00000aa404100197000027100040008c000016420000a13d000000640130003900000ab6020000410000000000210435000000440130003900000ab702000041000000000021043500000024013000390000002a02000039000000000021043500000ab401000041000000000013043500000004013000390000002002000039000000000021043500000a9e0030009c00000a9e03008041000000400130021000000ab8011001c700002a770001043000030aa30020019c000016540000c13d000000440130003900000ab302000041000000000021043500000024013000390000001902000039000000000021043500000ab401000041000000000013043500000004013000390000002002000039000000000021043500000a9e0030009c00000a9e03008041000000400130021000000ab5011001c700002a770001043000000aa80030009c000000840000213d0000004002300039000000400020043f0000002002300039000000000042043500000003050000290000000000530435000000a001100210000000000151019f0000000402000039000000000012041b000000400100043d000000000041043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aa9011001c70000800d02000039000000020300003900000aaa040000412a752a6b0000040f00000001002001900000006f0000613d0000001001000039000000000001041b000000000600041100000aab01000041000000000061041b000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000030300003900000aad0400004100000000050000192a752a6b0000040f00000001002001900000006f0000613d000000090100002900000aa301100197000000800010043f0000000b02000029000000000302043300000aa10030009c000000840000213d0000001602000039000000000502041a000000010050019000000001045002700000007f0440618f0000001f0040008c00000000060000390000000106002039000000000565013f000000010050019000000e8e0000c13d000000200040008c000016a50000413d000000000020043f0000001f05300039000000050550027000000aae0550009a000000200030008c00000aaf050040410000001f04400039000000050440027000000aae0440009a000000000045004b000016a50000813d000000000005041b0000000105500039000000000045004b000016a10000413d0000001f0030008c00000020040000390000000105000039000019a50000a13d000000000020043f00000ba70830019800000aaf0600004100000000070400190000000b0b000029000016ba0000613d0000002007000039000000010980008a000000050990027000000ab00990009a000000000ab70019000000000a0a04330000000000a6041b00000020077000390000000106600039000000000096004b000016b30000c13d000000000038004b000016c40000813d0000000308300210000000f80880018f00000bab0880027f00000bab088001670000000b077000290000000007070433000000000787016f000000000076041b00000001063002100000000003050019000019af0000013d000000400100043d00000b80020000410000117c0000013d00000bac0030009c0000171a0000a13d00000b8d01000041000000000010043f0000001101000039000000040010043f00000b2d0100004100002a77000104300000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000016d90000c13d000018950000013d000000400100043d00000b67020000410000117c0000013d0000000001000411000000000010043f0000000f01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000018a80000c13d0000000901000029000000000010043f0000000101000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff0010019000000d720000c13d000000400100043d000000640210003900000b89030000410000000000320435000000440210003900000b8a03000041000000000032043500000024021000390000002e03000039000019050000013d0000010002300039000000090020006b000017e40000813d0000000a02000029000000000012041b000000000100001900002a760001042e000000090200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b27011001c70000000a020000292a752a700000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000009057000290000173b0000613d000000000801034f0000000909000029000000008a08043c0000000009a90436000000000059004b000017370000c13d000000000006004b000017480000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00000001002001900000186d0000613d0000001f01400039000000600210018f0000000901200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200030008c0000006f0000413d00000009020000290000000003020433000000000003004b0000000002000039000000010200c039000000000023004b0000006f0000c13d000000010220018f000009cf0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000017680000c13d000018950000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000017740000c13d000018950000013d000000400100043d000700000001001d00000aa80010009c000000840000213d00000001030003670000004401300370000000000101043b00000007040000290000004002400039000000400020043f000000010200003900000000042404360000000000140435000000400400043d00000aa80040009c000000840000213d0000006403300370000000000303043b0000004005400039000000400050043f00000020054000390000000000350435000000000024043500000007020000290000000002020433000600000002001d000000000002004b00001a7c0000613d000000000100041100050aa30010019b00000000050000190000000904000029000000070200002900000006030000290000179f0000013d0000000105500039000000000035004b00001a790000813d0000000001020433000000000051004b0000240e0000a13d000000000004004b0000179c0000613d0000000301000039000000000101041a00000aa3061001980000179c0000613d000a00000005001d00000b24010000410000000000100443000b00000006001d0000000400600443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b00000009040000290000006f0000613d000000400500043d0000004401500039000000080200002900000000002104350000002401500039000000000041043500000b3501000041000000000015043500000004015000390000000502000029000000000021043500000000010004140000000b02000029000000040020008c000017da0000613d00000a9e0050009c00000a9e030000410000000003054019000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000ab5011001c7000b00000005001d2a752a700000040f0000000b050000290000000904000029000000600310027000000a9e0030019d000000010020019000001c790000613d00000aa10050009c000000840000213d000000400050043f000000070200002900000006030000290000000a050000290000179c0000013d000000400100043d0000000002000019000009cf0000013d000000400100043d00000b52020000410000117c0000013d000000000002004b0000000003000019000017eb0000613d000000a00300043d000000030420021000000bab0440027f00000bab04400167000000000443016f0000000103200210000018c40000013d0000000302000039000000000402041a000000200210003900000b6d030000410000000000320435000b00000004001d00000aa302400197000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000010300003900000b6f040000412a752a6b0000040f00000001002001900000006f0000613d0000000b0100002900000ab10110019700000b6d011001c70000000302000039000000000012041b00000b2401000041000000000010044300000b6d010000410000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000102000039000000000021043500000b2601000041000000000013043500000004013000390000000002000410000000000021043500000a9e0030009c000b00000003001d00000a9e0100004100000000010340190000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b27011001c700000b6d020000412a752a6b0000040f000000600310027000000a9e0030019d000000010020019000001a520000613d0000000b0100002900000aa10010009c000000840000213d0000000b01000029000000400010043f00000b2401000041000000000010044300000b6d010000410000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400300043d00000024013000390000000102000039000000000021043500000b2801000041000000000013043500000004013000390000000002000410000000000021043500000a9e0030009c000b00000003001d00000a9e0100004100000000010340190000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b27011001c700000b6d020000412a752a6b0000040f000000600310027000000a9e0030019d000000010020019000001d270000613d0000000b0100002900000aa10010009c000000840000213d0000000b01000029000000400010043f000000000100001900002a760001042e0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000018740000c13d000018950000013d000000400100043d00000b9c020000410000117c0000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000018840000c13d000018950000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000018910000c13d000000000005004b000018a20000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a9e0020009c00000a9e020080410000004002200210000000000112019f00002a7700010430000000400100043d00000b33020000410000117c0000013d00000aaf030000410000002006000039000000010540008a000000050550027000000ab00550009a000000000706001900000080066000390000000006060433000000000063041b00000020067000390000000103300039000000000053004b000018b00000c13d000000a005700039000000000024004b000018c20000813d0000000304200210000000f80440018f00000bab0440027f00000bab044001670000000005050433000000000445016f000000000043041b00000001030000390000000104200210000000000234019f000000000021041b000000000100001900002a760001042e0000000803000029000000000429034f000000000404043b000000200330003900000000004304350000002002200039000000000052004b000018c90000413d00000008020000290000000002020433000000800300043d000000000023004b000018fc0000c13d00000aa10020009c000000840000213d00000005032002100000003f0430003900000b7c05400197000000400400043d000600000004001d0000000004450019000000000054004b0000000005000039000000010500403900000aa10040009c000000840000213d0000000100500190000000840000c13d000000400040043f00000006040000290000000002240436000500000002001d0000001f0230018f000000000003004b000018f10000613d00000005040000290000000003340019000000001501043c0000000004540436000000000034004b000018ed0000c13d000000000002004b000000800100043d000000000001004b000019cf0000c13d000000400200043d000b00000002001d0000002001000039000000000212043600000006010000292a7526860000040f000013150000013d000000400100043d000000640210003900000b7a030000410000000000320435000000440210003900000b7b03000041000000000032043500000024021000390000002903000039000000000032043500000ab402000041000000000021043500000004021000390000002003000039000000000032043500000a9e0010009c00000a9e01008041000000400110021000000ab8011001c700002a77000104300000000101000039000500000001001d0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a00000ba802200197000000000021041b0000000b01000029000000000010043f000000050000006b000019680000c13d0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000201043b0000000101200039000000000101041a0000000702200039000000000202041a000000000012001a000016cc0000413d0000000001120019000000400300043d0000002402300039000000000012043500000b2e010000410000000000130435000b00000003001d00000004013000390000000602000029000000000021043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c00001af00000c13d0000000003000031000000200030008c0000002004000039000000000403401900001b190000013d0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000a00000001001d0000000901000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff0010019000001b310000c13d0000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000201043b000000000102041a0000000502200039000000000302041a000000000013004b000016cc0000213d00000bab0030009c000016cc0000613d0000000104300039000000000042041b000000000031004b00001d340000c13d0000000a010000290000000501100039000000000101041a00000b5d0010019800001d340000c13d000000400100043d00000b77020000410000117c0000013d000000000003004b0000000006000019000019aa0000613d0000000a060000290000000006060433000000030730021000000bab0770027f00000bab07700167000000000676016f0000000103300210000000000336019f000000000032041b000000080200002900000aa3022001970000001103000039000000000603041a00000ab106600197000000000226019f000000000023041b0000001702000039000000000302041a00000ab10330019700000003033001af000000000032041b00000012020000390000000503000029000000000032041b00000013020000390000000403000029000000000032041b00000014020000390000000603000029000000000032041b00000015020000390000000703000029000000000032041b000001400000044300000160001004430000010000400443000001200050044300000ab20100004100002a760001042e000000000300001900000008010000290000000001010433000000000031004b0000240e0000a13d000a00000003001d0000000503300210000000a0013000390000000001010433000b0aa30010019c000080100200003900001beb0000613d000900000003001d00000007013000290000000001010433000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c72a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000060200002900000000020204330000000a03000029000000000032004b0000240e0000a13d00000009040000290000000502400029000000000101043b000000000101041a00000000001204350000000103300039000000800100043d000000000013004b000019d00000413d000018f50000013d0000000a0300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000b27011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a0570002900001a1d0000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b00001a190000c13d000000000006004b00001a2a0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000000010020019000001ae40000613d0000001f01400039000000600210018f0000000a01200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200040008c0000006f0000413d0000000a020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001b2f0000613d0000000902000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aa9011001c70000800d02000039000000030300003900000b600400004100001d690000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a5a0000c13d000018950000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a670000c13d000018950000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a740000c13d000018950000013d00000044010000390000000101100367000000000101043b000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f000000010020019000000009020000290000006f0000613d000000000101043b000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000301041a00000001010003670000006402100370000000000202043b000b00000003001d000000000023004b00001b340000813d000000400100043d000000640210003900000b8e030000410000000000320435000000440210003900000b8f0300004100001bf10000013d0000000a0300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000ab5011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a0570002900001abc0000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b00001ab80000c13d000000000006004b00001ac90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000000010020019000001bd30000613d0000001f01400039000000600210018f0000000a01200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200040008c0000006f0000413d0000000a020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001d5b0000c13d00000b46020000410000117c0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001aeb0000c13d000018950000013d0000000b0300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000b27011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000b0570002900001b090000613d000000000801034f0000000b09000029000000008a08043c0000000009a90436000000000059004b00001b050000c13d000000000006004b00001b160000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000000010020019000001bdf0000613d0000001f01400039000000600210018f0000000b01200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200030008c0000006f0000413d0000000b020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00000f210000c13d00000b61020000410000117c0000013d000000400100043d00000b73020000410000117c0000013d0000004401100370000000000101043b000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f000000010020019000000009020000290000006f0000613d000000000101043b000000000020043f000000200010043f00000064010000390000000101100367000000000101043b000a00000001001d000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d0000000a030000290000000b02300069000000000101043b000000000021041b00000044010000390000000101100367000000000101043b000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000802000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d00000001030003670000006402300370000000000202043b000000000101043b000000000401041a000000000024001a000016cc0000413d0000000004240019000000000041041b0000004401300370000000000101043b000000400300043d00000020043000390000000000240435000000000013043500000a9e0030009c00000a9e030080410000004001300210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000040300003900000b36040000410000000005000411000000090600002900000008070000292a752a6b0000040f00000001002001900000006f0000613d00000b2401000041000000000010044300000008010000290000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b000000090200002900000f210000613d000000400400043d0000002401400039000000000021043500000b3701000041000000000014043500000004014000390000000002000411000000000021043500000001010003670000004402100370000000000202043b000000440340003900000000002304350000006401100370000000000101043b0000008402400039000000a003000039000000000032043500000064024000390000000000120435000000a402400039000000800100043d0000000000120435000b00000004001d000000c402400039000000000001004b00001bc60000613d00000000030000190000000004230019000000a005300039000000000505043300000000005404350000002003300039000000000013004b00001bbf0000413d0000000002210019000000000002043500000000020004140000000803000029000000040030008c00001ff90000c13d00000000050004150000000d0550008a00000005055002100000000004000031000000200040008c00000020040080390000202c0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001bda0000c13d000018950000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001be60000c13d000018950000013d000000400100043d000000640210003900000b7d030000410000000000320435000000440210003900000b7e03000041000000000032043500000024021000390000002a03000039000019050000013d000000400100043d0000002003100039000000000500041100000000005304350000000405200370000000000505043b000000400610003900000000005604350000002405200370000000000505043b000000a0061000390000000a07000029000000000076043500000080061000390000000b07000029000000000076043500000060061000390000000000560435000000a405200370000000000505043b00000100061000390000000000460435000000e00410003900000009060000290000000000640435000000c00410003900000000005404350000010404200370000000000404043b000001200510003900000000004504350000012402200370000000000202043b000001400410003900000000002404350000014002000039000000000021043500000b470010009c000000840000213d0000016002100039000000400020043f00000a9e0030009c00000a9e030080410000004002300210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000200010043f00000b3f01000041000000000010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b40011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000400200043d000800000002001d000000000101043b000000800200043d000000400020008c00001e9d0000613d000000410020008c00001ed10000c13d000000e00200043d000000f802200270000000200020043f000000c00200043d00001ea20000013d000000000010043f0000000f01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff0010019000001d6c0000c13d0000000b01000029000000000010043f0000000101000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000000ff00100190000003a70000c13d000017100000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001c810000c13d000018950000013d000000c00200043d000000ff032002700000001b03300039000000200030043f00000b4102200197000000600020043f000000000010043f000000a00100043d000000400010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b42011001c700000001020000392a752a700000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00001ca50000613d000000000701034f0000000108000039000000007907043c0000000008980436000000000048004b00001ca10000c13d000000010220018f000000000005004b00001cb30000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000b02000029000000400020043f000000000003004b00001ed10000613d0000001102000039000000000202041a000000000112013f00000aa300100198000024140000c13d0000000a01000029000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000b00000001001d0000000a010000290000000801100270000000000010043f0000001801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d0000000a02000029000000ff0220018f000000000101043b000000000101041a000000000121022f000000010010019000001d090000c13d0000000b010000290000000301100039000000000101041a000800000001001d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000080010006c00001d090000a13d0000000a01000029000000000010043f0000000a01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d0000000b020000290000000402200039000000000202041a000000000101043b000000000101041a000000000021004b0000241c0000a13d0000000b010000290000000101100039000000000101041a000b0009001000be00001fdb0000c13d000000400100043d00001b2f0000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001d180000c13d000018950000013d000000400100043d000000640210003900000b8b030000410000000000320435000000440210003900000b8c03000041000000000032043500000024021000390000002803000039000019050000013d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001d2f0000c13d000018950000013d0000000b01000029000000000010043f0000000a01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000400100043d000900000001001d00000b6a0010009c000000840000213d00000009020000290000002001200039000000400010043f0000000000020435000000400100043d0000000002000411000000000002004b00001f780000c13d000000640210003900000b75030000410000000000320435000000440210003900000b7603000041000000000032043500000024021000390000002103000039000019050000013d0000000902000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aa9011001c70000800d02000039000000030300003900000b68040000410000000b05000029000000000600041100000f1e0000013d000000400100043d00000b46020000410000117c0000013d000000c00200043d000000ff032002700000001b03300039000000200030043f00000b4102200197000000600020043f000000000010043f000000a00100043d000000400010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b42011001c700000001020000392a752a700000040f0000000109000039000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00001d8e0000613d000000000701034f000000007807043c0000000009890436000000000049004b00001d8a0000c13d000000010220018f000000000005004b00001d9c0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000902000029000000400020043f000000000003004b00001ed10000613d0000001102000039000000000202041a000000000112013f00000aa30010019800001e9a0000c13d0000000b01000029000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000900000001001d0000000501100039000000000101041a00000aa3011001970000000002000411000000000012004b00001dc20000613d00000aab01000041000000000101041a00000aa301100197000000000012004b0000204a0000c13d00000009010000290000000301100039000000000101041a000600000001001d000000000001004b00001dd60000613d00000b3b010000410000000000100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b3c011001c70000800b020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000060010006c00000d290000213d000000080000006b0000204d0000613d0000000a010000290000000b0200002900000009030000292a7528290000040f000000000100001900002a760001042e000000000100041100050aa30010019b0000000003000019000000060200002900001deb0000013d00000aa10040009c000000840000213d000000400040043f000000060200002900000009030000290000000103300039000000000023004b00001f070000813d000000800100043d000000000031004b0000240e0000a13d0000000b0000006b00001de80000613d0000000301000039000000000101041a00000aa30410019800001de80000613d000900000003001d00000b24010000410000000000100443000a00000004001d0000000400400443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000025bb0000613d000000000101043b000000000001004b0000006f0000613d000000400400043d00000044014000390000000802000029000000000021043500000024014000390000000b02000029000000000021043500000b3501000041000000000014043500000004014000390000000502000029000000000021043500000000010004140000000a02000029000000040020008c00001de30000613d00000a9e0040009c00000a9e030000410000000003044019000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000ab5011001c7000a00000004001d2a752a700000040f0000000a04000029000000600310027000000a9e0030019d000000010020019000001de30000c13d00000a9e033001970000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001e2d0000c13d000018950000013d000000c00200043d000000ff032002700000001b03300039000000200030043f00000b4102200197000000600020043f000000000010043f000000a00100043d000000400010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b42011001c700000001020000392a752a700000040f0000000109000039000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00001e510000613d000000000701034f000000007807043c0000000009890436000000000049004b00001e4d0000c13d000000010220018f000000000005004b00001e5f0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000702000029000000400020043f000000000003004b00001ed10000613d0000001102000039000000000202041a000000000112013f00000aa30010019800001f040000c13d000000090000006b0000216f0000c13d0000001201000039000000000201041a000700000002001d000000080020002a000016cc0000413d00000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b00000006010000290000000101100039000000000101041a000000400400043d00000044034000390000000000130435000000000100041000000aa3011001970000002403400039000000000013043500000b45010000410000000000140435000900000004001d00000004014000390000000a030000290000000000310435000000000100041400000aa302200197000500000002001d000000040020008c0000210d0000c13d0000000004000031000000200040008c0000002004008039000021370000013d00000b43010000410000000902000029000024160000013d000000c00200043d000000ff032002700000001b03300039000000200030043f00000b4102200197000000600020043f000000000010043f000000a00100043d000000400010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b42011001c700000001020000392a752a700000040f0000000109000039000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00001ebc0000613d000000000701034f000000007807043c0000000009890436000000000049004b00001eb80000c13d000000010220018f000000000005004b00001eca0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000802000029000000400020043f000000000003004b00001ed50000c13d00000b8801000041000000000010043f00000b300100004100002a77000104300000001102000039000000000202041a000000000112013f00000aa30010019800001f750000c13d0000000a0000006b000022230000c13d0000001701000039000000000101041a0000001502000039000000000202041a00000008040000290000004403400039000000000023043500000aa3011001970000002402400039000000000012043500000b45010000410000000000140435000000000100041100000aa3011001970000000402400039000000000012043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c000021e30000c13d0000000003000031000000200030008c000000200400003900000000040340190000220c0000013d00000b43010000410000000702000029000024160000013d000000800100043d000000000001004b000003b20000613d000000000200001900000004010000290000000001010433000000000021004b0000240e0000a13d000600000002001d0000000501200210000000a002100039000000000302043300000003011000290000000001010433000900000001001d000a00000003001d000000000030043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000500090010007400001a9c0000413d0000000a01000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000502000029000000000021041b0000000a01000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000802000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a0000000903000029000000000032001a000016cc0000413d0000000002320019000000000021041b00000006020000290000000102200039000000800100043d000000000012004b00001f0b0000413d000003b20000013d00000b43010000410000000802000029000024160000013d00000aa80010009c000000840000213d0000004002100039000000400020043f00000020021000390000000b03000029000000000032043500000001020000390000000000210435000000400100043d00000aa80010009c000000840000213d0000004002100039000000400020043f00000020021000390000000103000039000000000032043500000000003104350000000b01000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000400100043d0000002002100039000000010300003900000000003204350000000b02000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000040300003900000b36040000410000000005000411000000000600001900000000070500192a752a6b0000040f00000001002001900000006f0000613d000000000100041100000000020100190000000b0300002900000009040000292a7529330000040f0000000a010000290000000101100039000000000101041a0000001202000039000000000202041a000000400300043d00000020043000390000000000240435000000000013043500000a9e0030009c00000a9e030080410000004001300210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000030300003900000b740400004100001d690000013d0000000a01000029000000000010043f0000000b01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a0000000902200029000000000021041b0000000001000411000000000001004b000020cc0000c13d000000400100043d000000640210003900000b86030000410000000000320435000000440210003900000b8703000041000000000032043500000024021000390000002303000039000019050000013d0000001f0110003900000ba701100197000000c40110003900000a9e0010009c00000a9e0100804100000060011002100000000b0300002900000a9e0030009c00000a9e030080410000004003300210000000000131019f00000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000008020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000b05700029000020190000613d000000000801034f0000000b09000029000000008a08043c0000000009a90436000000000059004b000020150000c13d000000000006004b000020260000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00000000050004150000000c0550008a00000005055002100000000100200190000021750000613d0000001f01400039000000600110018f0000000b02100029000000000012004b0000000001000039000000010100403900000aa10020009c000000840000213d0000000100100190000000840000c13d0000000003020019000000400020043f000000200040008c0000006f0000413d0000000b01000029000000000101043300000b38001001980000006f0000c13d0000000502500270000000000201001f00000b390110019700000b370010009c00000f210000613d00000ab401000041000a00000003001d000000000013043500000004013000392a7529190000040f0000000a02000029000021da0000013d000000400100043d00000b44020000410000117c0000013d0000001201000039000000000201041a000600000002001d000000070020002a000016cc0000413d00000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b00000009010000290000000101100039000000000101041a000000400400043d00000044034000390000000000130435000000000100041000000aa3011001970000002403400039000000000013043500000b45010000410000000000140435000800000004001d00000004014000390000000a030000290000000000310435000000000100041400000aa302200197000500000002001d000000040020008c0000241f0000c13d0000000004000031000000200040008c0000002004008039000024490000013d0000001f0220003900000ba7022001970000000a040000290000000001410049000000000121001900000a9e0010009c00000a9e01008041000000600110021000000a9e0040009c00000a9e0200004100000000020440190000004002200210000000000121019f00000a9e0030009c00000a9e03008041000000c002300210000000000112019f00000008020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a057000290000209c0000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b000020980000c13d000000000006004b000020a90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000005000415000000100550008a000000050550021000000001002001900000218f0000613d0000001f01400039000000600110018f0000000a02100029000000000012004b0000000001000039000000010100403900000aa10020009c000000840000213d0000000100100190000000840000c13d0000000004020019000000400020043f000000200030008c0000006f0000413d0000000a01000029000000000101043300000b38001001980000006f0000c13d0000000502500270000000000201001f00000b390110019700000b910010009c00000f210000613d00000ab401000041000b00000004001d000000000014043500000004014000392a7529190000040f000021d90000013d000000400100043d00000aa80010009c000000840000213d0000004002100039000000400020043f00000020021000390000000a03000029000000000032043500000001020000390000000000210435000000400100043d00000aa80010009c000000840000213d0000004002100039000000400020043f00000020021000390000000903000029000000000032043500000001020000390000000000210435000000400100043d00000b6a0010009c000000840000213d0000002002100039000000400020043f00000000000104350000000a01000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a00080009001000740000255f0000813d000000400100043d000000640210003900000b84030000410000000000320435000000440210003900000b8503000041000000000032043500000024021000390000002403000039000019050000013d000000090200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000ab5011001c700000005020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000905700029000021270000613d000000000801034f0000000909000029000000008a08043c0000000009a90436000000000059004b000021230000c13d000000000006004b000021340000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000022a90000613d0000001f01400039000000600110018f0000000903100029000000000013004b00000000020000390000000102004039000400000003001d00000aa10030009c000000840000213d0000000100200190000000840000c13d0000000402000029000000400020043f000000200040008c0000006f0000413d00000009020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b000024610000613d000000070300002900000008023000290000001703000039000000000303041a00000004050000290000004404500039000000000024043500000aa3023001970000002403500039000000000023043500000b4502000041000000000025043500000004025000390000000a03000029000000000032043500000000020004140000000503000029000000040030008c000024cc0000c13d000000040110002900000aa10010009c000000840000213d000000400010043f00000004020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001ae20000613d00000000010004110000000b0200002900000006030000292a7528290000040f000000000100001900002a760001042e000000040230008c000021d30000413d000000000400043d00000b3804400197000000000501043b00000b3905500197000000000445019f000000000040043f00000b390440019700000ab40040009c000021d30000c13d000000440030008c000021d30000413d000000040510037000000ba7062001980000001f0720018f000000400400043d0000000001640019000021a80000613d000000000805034f0000000009040019000000008a08043c0000000009a90436000000000019004b0000218a0000c13d000021a80000013d000000040230008c000021d30000413d000000000400043d00000b3804400197000000000501043b00000b3905500197000000000445019f000000000040043f000000440030008c000021d30000413d00000b390440019700000ab40040009c000021d30000c13d000000040510037000000ba7062001980000001f0720018f000000400400043d0000000001640019000021a80000613d000000000805034f0000000009040019000000008a08043c0000000009a90436000000000019004b000021a40000c13d000000000007004b000021b50000613d000000000565034f0000000306700210000000000701043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f0000000000510435000000000504043300000aa10050009c000021d30000213d0000002401500039000000000031004b000021d30000213d0000000001450019000000000301043300000aa10030009c000021d30000213d000000000224001900000000063100190000002006600039000000000026004b000021d30000213d00000000023500190000003f0220003900000ba7022001970000000004420019000000000024004b0000000002000039000000010200403900000aa10040009c000000840000213d0000000100200190000000840000c13d0000000003040019000000400040043f000000000001004b000025bc0000c13d000000400200043d000b00000002001d00000ab401000041000000000012043500000004012000392a7529260000040f0000000b02000029000000000121004900000a9e0010009c00000a9e01008041000000600110021000000a9e0020009c00000a9e020080410000004002200210000000000121019f00002a7700010430000000080300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000ab5011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000805700029000021fc0000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b000021f80000c13d000000000006004b000022090000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000024640000613d0000001f01400039000000600210018f0000000801200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200030008c0000006f0000413d00000008020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001ae20000613d000800000001001d0000001002000039000000000102041a0000000101100039000000000012041b000000080200002900000b480020009c000000840000213d00000008050000290000012002500039000000400020043f00000001020003670000000403200370000000000303043b00000000073504360000002403200370000000000303043b00000040065000390000000904000029000700000006001d0000000000460435000600000007001d0000000000370435000000e403200370000000000303043b0000006004500039000500000004001d00000000003404350000010403200370000000000303043b000000c0065000390000000b04000029000a00000006001d0000000000460435000000a0065000390000000004000411000400000006001d00000000004604350000008004500039000300000004001d00000000003404350000012402200370000000000202043b000000e003500039000900000003001d00000000002304350000010002500039000b00000002001d0000000000020435000000000010043f0000000801000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d00000008020000290000000002020433000000000101043b000000000021041b000000060200002900000000020204330000000103100039000000000023041b000000070200002900000000020204330000000203100039000000000023041b000000050200002900000000020204330000000303100039000000000023041b000000030200002900000000020204330000000403100039000000000023041b0000000402000029000000000202043300000aa3022001970000000503100039000000000403041a00000b4904400197000000000224019f0000000a040000290000000004040433000000000004004b00000b4a040000410000000004006019000000000242019f000000000023041b000000090200002900000000020204330000000603100039000000000023041b00000007011000390000000b020000290000000002020433000000000021041b0000001001000039000000000501041a00000024010000390000000101100367000000000101043b000000400200043d000000000012043500000a9e0020009c00000a9e020080410000004001200210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aa9011001c70000800d02000039000000030300003900000b4b04000041000b00000005001d00000000060004112a752a6b0000040f00000001002001900000006f0000613d00000001010003670000012402100370000000000202043b000000000002004b0000247c0000c13d0000001001000039000000000101041a000009b30000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000022b00000c13d000018950000013d000000080200002900000040022000390000000002020433000000ff032002700000001b03300039000000200030043f00000b4102200197000000600020043f000000000010043f00000007010000290000000001010433000000400010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b42011001c700000001020000392a752a700000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf000022d70000613d000000000701034f0000000108000039000000007907043c0000000008980436000000000048004b000022d30000c13d000000010220018f000000000005004b000022e50000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000000003001f0000000001020433000000600000043f0000000b02000029000000400020043f000000000003004b00001ed10000613d0000001102000039000000000202041a000000000112013f00000aa300100198000024140000c13d000000800100043d000000000001004b00000f210000613d000000000200041100050aa30020019b000b00000000001d0000000a0200002900000000020204330000000b0020006c0000240e0000a13d0000000b020000290000000503200210000700000003001d00000009023000290000000002020433000000000002004b000023660000613d0000001701000039000000000101041a000000400400043d0000004403400039000000000023043500000aa3011001970000002402400039000000000012043500000b45010000410000000000140435000800000004001d00000004014000390000000502000029000000000021043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c000023270000c13d0000000004000031000000200040008c00000020040080390000234f0000013d000000080300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000ab5011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c00000020040000390000000004034019000000200640019000000008056000290000233f0000613d000000000701034f0000000808000029000000007907043c0000000008980436000000000058004b0000233b0000c13d0000001f074001900000234c0000613d000000000661034f0000000307700210000000000805043300000000087801cf000000000878022f000000000606043b0000010007700089000000000676022f00000000067601cf000000000686019f0000000000650435000000000003001f0000000100200190000025db0000613d0000001f01400039000000600210018f0000000801200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200040008c0000006f0000413d00000008020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001ae20000613d000000800100043d0000000b0010006c0000240e0000a13d0000000701000029000000a001100039000700000001001d0000000001010433000000000010043f0000000c01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000201041a000000010220003a000016cc0000613d000000000021041b000000800100043d0000000b0010006c0000240e0000a13d0000000001000411000000000001004b00001fef0000613d000000400100043d00000aa80010009c000000840000213d000000070200002900000000030204330000004002100039000000400020043f0000002002100039000800000003001d000000000032043500000001020000390000000000210435000000400100043d00000aa80010009c000000840000213d0000004002100039000000400020043f0000002002100039000000010300003900000000003204350000000000310435000000400100043d00000b6a0010009c000000840000213d0000002002100039000000400020043f00000000000104350000000801000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b000000000101041a000600000001001d000000000001004b000021030000613d0000000801000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000602000029000000010220008a000000000021041b000000400100043d0000002002100039000000010300003900000000003204350000000802000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000040300003900000b36040000410000000005000411000000000605001900000000070000192a752a6b0000040f00000001002001900000006f0000613d000000400100043d00000b6a0010009c000000840000213d0000002002100039000000400020043f0000000000010435000000800100043d0000000b0010006c0000240e0000a13d00000007010000290000000005010433000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000aac011001c70000800d02000039000000030300003900000b6b0400004100000000060004112a752a6b0000040f00000001002001900000006f0000613d0000000b02000029000b00010020003d000000800100043d0000000b0010006b000022f70000413d00000f210000013d00000b8d01000041000000000010043f0000003201000039000000040010043f00000b2d0100004100002a770001043000000b43010000410000000b02000029000000000012043500000a9e0020009c00000a9e02008041000000400120021000000b34011001c700002a7700010430000000400100043d00000b82020000410000117c0000013d000000080200002900000a9e0020009c00000a9e02008041000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000ab5011001c700000005020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000805700029000024390000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b000024350000c13d000000000006004b000024460000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000024700000613d0000001f01400039000000600110018f0000000803100029000000000013004b00000000020000390000000102004039000400000003001d00000aa10030009c000000840000213d0000000100200190000000840000c13d0000000402000029000000400020043f000000200040008c0000006f0000413d00000008020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b000024ff0000c13d00000b46010000410000000402000029000024160000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000246b0000c13d000018950000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000024770000c13d000018950000013d000000400300043d000a00000003001d00000b4c0030009c000000840000213d0000001303000039000000000303041a0000001404000039000000000404041a0000000a060000290000010005600039000000400050043f00000000052604360000002401100370000000000101043b000000e002600039000900000002001d0000000000420435000000c002600039000800000002001d0000000000320435000600000005001d0000000000150435000000a001600039000700000001001d00000000000104350000008001600039000500000001001d00000000000104350000006001600039000400000001001d00000000000104350000004001600039000300000001001d00000000000104350000000b01000029000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d0000000a020000290000000002020433000000000101043b000000000021041b000000060200002900000000020204330000000103100039000000000023041b000000030200002900000000020204330000000203100039000000000023041b000000040200002900000000020204330000000303100039000000000023041b000000050200002900000000020204330000000403100039000000000023041b000000070200002900000000020204330000000503100039000000000023041b000000080200002900000000020204330000000603100039000000000023041b000000070110003900000009020000290000000002020433000000000021041b000022a60000013d000000040100002900000a9e0010009c00000a9e01008041000000400110021000000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000ab5011001c700000005020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000405700029000024e60000613d000000000801034f0000000409000029000000008a08043c0000000009a90436000000000059004b000024e20000c13d000000000006004b000024f30000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000025200000613d0000001f01400039000000600110018f000000040110002900000aa10010009c000000840000213d000000400010043f000000200030008c000021660000813d0000006f0000013d000000060300002900000007023000290000001703000039000000000303041a00000004050000290000004404500039000000000024043500000aa3023001970000002403500039000000000023043500000b4502000041000000000025043500000004025000390000000a03000029000000000032043500000000020004140000000503000029000000040030008c0000252c0000c13d000000040110002900000aa10010009c000000840000213d000000400010043f00000004020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001ae20000613d00001dd80000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000025270000c13d000018950000013d000000040100002900000a9e0010009c00000a9e01008041000000400110021000000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000ab5011001c700000005020000292a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000405700029000025460000613d000000000801034f0000000409000029000000008a08043c0000000009a90436000000000059004b000025420000c13d000000000006004b000025530000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000025cf0000613d0000001f01400039000000600110018f000000040110002900000aa10010009c000000840000213d000000400010043f000000200030008c000025160000813d0000006f0000013d0000000a01000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000002000411000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f00000001002001900000006f0000613d000000000101043b0000000802000029000000000021041b000000400100043d0000002002100039000000090300002900000000003204350000000a02000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000040300003900000b36040000410000000005000411000000000605001900000000070000192a752a6b0000040f00000001002001900000006f0000613d000000400100043d00000b6a0010009c000000840000213d0000002002100039000000400020043f0000000000010435000000400300043d00000024013000390000000b02000029000000000021043500000b2e010000410000000000130435000000000100041100000aa301100197000800000003001d0000000402300039000000000012043500000b2a010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b2b011001c700008005020000392a752a700000040f0000000100200190000025bb0000613d000000000201043b000000000100041400000aa302200197000000040020008c000025e70000c13d0000000004000031000000200040008c0000002004008039000026100000013d000000000001042f00000ab4020000410000000004030019000b00000003001d000000000023043500000004023000390000002003000039000000000032043500000024024000392a7526640000040f0000000b02000029000000000121004900000a9e0010009c00000a9e0100804100000a9e0020009c00000a9e0200804100000060011002100000004002200210000000000121019f00002a77000104300000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000025d60000c13d000018950000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000025e20000c13d000018950000013d000000080300002900000a9e0030009c00000a9e03008041000000400330021000000a9e0010009c00000a9e01008041000000c001100210000000000131019f00000b27011001c72a752a6b0000040f000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000805700029000026000000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b000025fc0000c13d000000000006004b0000260d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000100200190000026390000613d0000001f01400039000000600210018f0000000801200029000000000021004b0000000002000039000000010200403900000aa10010009c000000840000213d0000000100200190000000840000c13d000000400010043f000000200040008c0000006f0000413d00000008020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b0000006f0000c13d000000000002004b00001b2f0000613d00000020021000390000000b0300002900000000003204350000000902000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000030300003900000b83040000410000000a0500002900001d6a0000013d0000001f0530018f00000aa006300198000000400200043d0000000004620019000018950000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000026400000c13d000018950000013d0000001f0220003900000ba7022001970000000001120019000000000021004b0000000002000039000000010200403900000aa10010009c000026510000213d0000000100200190000026510000c13d000000400010043f000000000001042d00000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a7700010430000000000003004b000026610000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000034004b0000265a0000413d00000000012300190000000000010435000000000001042d00000000430104340000000001320436000000000003004b000026700000613d000000000200001900000000051200190000000006240019000000000606043300000000006504350000002002200039000000000032004b000026690000413d000000000213001900000000000204350000001f0230003900000ba7022001970000000001210019000000000001042d00000020030000390000000004310436000000000302043300000000003404350000004001100039000000000003004b000026850000613d00000000040000190000002002200039000000000502043300000aa30550019700000000015104360000000104400039000000000034004b0000267e0000413d000000000001042d000000000301001900000000040104330000000001420436000000000004004b000026920000613d00000000020000190000002003300039000000000503043300000000015104360000000102200039000000000042004b0000268c0000413d000000000001042d00000024010000390000000101100367000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b0000269c0000c13d000000000001042d000000000100001900002a7700010430000100000000000200010aa30010019c000026be0000613d000000000020043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000026bc0000613d000000000101043b0000000102000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000026bc0000613d000000000101043b000000000101041a000000000001042d000000000100001900002a7700010430000000400100043d000000640210003900000b7d030000410000000000320435000000440210003900000b7e03000041000000000032043500000024021000390000002a03000039000000000032043500000ab402000041000000000021043500000004021000390000002003000039000000000032043500000a9e0010009c00000a9e01008041000000400110021000000ab8011001c700002a7700010430000000000212004900000b410020009c000026de0000213d0000001f0020008c000026de0000a13d0000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000026de0000c13d000000000001042d000000000100001900002a7700010430000400000000000200000aab02000041000000000202041a00000aa3032001970000000002000411000000000032004b000027780000c13d00000b24020000410000000000200443000200000001001d0000000400100443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f00000001002001900000277b0000613d0000000102000039000000020300002900000aa305300197000000000101043b000000000001004b000200000005001d000027540000613d000000400b00043d00000b6e0100004100000000001b04350000000401b0003900000000000104350000000001000414000000040050008c0000270b0000c13d0000000001000415000000040110008a00000005011002100000000003000031000000200030008c000000200400003900000000040340190000273c0000013d00000a9e00b0009c00000a9e0200004100000000020b4019000000400220021000000a9e0010009c00000a9e01008041000000c001100210000000000121019f00000b2d011001c7000000000205001900010000000b001d2a752a700000040f000000010b000029000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000027270000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000027230000c13d000000000006004b000027340000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f0000000000150435000000000003001f0000000001000415000000030110008a0000000501100210000000010020019000000002050000290000000102000039000027540000613d0000001f02400039000000600420018f0000000002b40019000000000042004b0000000004000039000000010400403900000aa10020009c000027830000213d0000000100400190000027830000c13d000000400020043f0000001f0030008c000027760000a13d00000000020b0433000000000002004b0000000003000039000000010300c039000000000032004b000027760000c13d0000000501100270000000000102001f000000000002004b00000000020000390000000102006039000000400100043d000000000005004b000027590000613d00000001002001900000277c0000c13d0000000302000039000000000302041a00000020021000390000000000520435000100000003001d00000aa302300197000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000010300003900000b6f040000412a752a6b0000040f00000002030000290000000100200190000027760000613d000000010100002900000ab101100197000000000131019f0000000302000039000000000012041b000000000001042d000000000100001900002a7700010430000000400100043d00000b44020000410000277d0000013d000000000001042f00000b7002000041000000000021043500000a9e0010009c00000a9e01008041000000400110021000000b34011001c700002a770001043000000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a77000104300006000000000002000500000002001d000600000001001d000000000010043f0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028170000613d000000400400043d00000bad0040009c000028190000813d000000000101043b0000010002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a0000006003400039000400000003001d00000000002304350000000402100039000000000202041a0000008003400039000100000003001d00000000002304350000000502100039000000000202041a000000a003400039000200000003001d00000000002304350000000602100039000000000202041a000000c0034000390000000000230435000300000004001d000000e0024000390000000701100039000000000101041a00000000001204350000000601000029000000000010043f0000000701000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028170000613d000000000101043b000000050200002900000aa302200197000600000002001d000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028170000613d000000000101043b000000000101041a000000ff00100190000028130000613d00000004010000290000000002010433000000000002004b000028130000613d0000000301000029000000000301043300000002010000290000000001010433000000000031004b0000000001000019000028140000813d00000001010000290000000001010433000000000031004b000028150000a13d000400000001001d000500000003001d000000400100043d00000040031000390000000604000029000000000043043500000040030000390000000003310436000000000023043500000b720010009c000028190000213d0000006002100039000000400020043f00000a9e0030009c00000a9e030080410000004002300210000000000101043300000a9e0010009c00000a9e010080410000006001100210000000000121019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f0000000100200190000028170000613d000000000101043b00000004101000fa000000050010006c00000000010000390000000101004039000000000001042d0000000001000019000000000001042d0000000101000039000000000001042d000000000100001900002a770001043000000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a770001043000000aab01000041000000000101041a0000000002000411000000000012004b000028250000c13d000000000001042d00000ba101000041000000000010043f00000b300100004100002a77000104300005000000000002000300000003001d000200000001001d000500000002001d000000000020043f0000000901000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028ed0000613d000000000101043b000000000101041a000000ff00100190000028fb0000c13d0000000601000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028ed0000613d00000003030000290000000502300039000000000202041a00000b5d00200198000028530000613d0000000701300039000000000201041a000000010220003a000028ef0000613d000000000021041b000028690000013d0000000602300039000000000202041a000000000101043b0000000401100039000000000101041a000000000112004b0000000001004019000000000203041a000000000021001a000028ef0000413d000000000121001900000003020000290000000702200039000000000302041a000000000013004b000028ef0000213d00000bab0030009c000028ef0000613d0000000104300039000000000042041b000000000031004b000029110000613d0000000501000029000000000010043f0000000a01000039000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028ed0000613d000000000101043b000000000201041a000000010220003a000028ef0000613d000000000021041b000000400400043d00000bae0040009c000028f50000813d0000002001400039000000400010043f0000000000040435000000400100043d000000020200002900040aa30020019c000028fe0000613d00000aa80010009c000028f50000213d0000004002100039000000400020043f00000020021000390000000503000029000000000032043500000001030000390000000000310435000000400100043d00000aa80010009c000028f50000213d000100000004001d0000004002100039000000400020043f0000002002100039000000000032043500000000003104350000000501000029000000000010043f000000200000043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028ed0000613d000000000101043b0000000402000029000000000020043f000000200010043f000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b32011001c700008010020000392a752a700000040f0000000100200190000028ed0000613d000000000101043b000000000201041a000000010220003a000028ef0000613d000000000021041b000000400100043d0000002002100039000000010300003900000000003204350000000502000029000000000021043500000a9e0010009c00000a9e010080410000004001100210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d020000390000000403000039000000000500041100000b3604000041000000000600001900000004070000292a752a6b0000040f0000000100200190000028ed0000613d00000000010004110000000202000029000000050300002900000001040000292a7529330000040f00000003010000290000000101100039000000000101041a0000001202000039000000000202041a000000400300043d00000020043000390000000000240435000000000013043500000a9e0030009c00000a9e030080410000004001300210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000b32011001c70000800d02000039000000030300003900000b7404000041000000050500002900000004060000292a752a6b0000040f0000000100200190000028ed0000613d000000000001042d000000000100001900002a770001043000000b8d01000041000000000010043f0000001101000039000000040010043f00000b2d0100004100002a770001043000000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a7700010430000000400100043d00000b7302000041000029130000013d000000640210003900000b75030000410000000000320435000000440210003900000b7603000041000000000032043500000024021000390000002103000039000000000032043500000ab402000041000000000021043500000004021000390000002003000039000000000032043500000a9e0010009c00000a9e01008041000000400110021000000ab8011001c700002a7700010430000000400100043d00000b7702000041000000000021043500000a9e0010009c00000a9e01008041000000400110021000000b34011001c700002a7700010430000000600210003900000baf030000410000000000320435000000400210003900000bb0030000410000000000320435000000200210003900000028030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d000000600210003900000bb1030000410000000000320435000000400210003900000bb2030000410000000000320435000000200210003900000034030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d0006000000000002000300000004001d000100000003001d000200000001001d00000b24010000410000000000100443000400000002001d0000000400200443000000000100041400000a9e0010009c00000a9e01008041000000c00110021000000b25011001c700008002020000392a752a700000040f0000000100200190000029c30000613d000000000101043b000000000001004b000029c00000613d000000400b00043d0000008401b00039000000a00200003900000000002104350000006401b00039000000010200003900000000002104350000004401b000390000000102000029000000000021043500000b370100004100000000001b0435000000020100002900000aa3011001970000000402b0003900000000001204350000002401b000390000000000010435000000a403b00039000000030100002900000000210104340000000000130435000000c403b00039000000000001004b000029680000613d000000000400001900000000053400190000000006420019000000000606043300000000006504350000002004400039000000000014004b000029610000413d000000000231001900000000000204350000000003000414000000040200002900000aa302200197000000040020008c000029770000c13d0000000005000415000000060550008a00000005055002100000000003000031000000200030008c00000020040000390000000004034019000029ab0000013d0000001f0110003900000ba701100197000000c40110003900000a9e0010009c00000a9e01008041000000600110021000000a9e00b0009c00000a9e0400004100000000040b40190000004004400210000000000141019f00000a9e0030009c00000a9e03008041000000c003300210000000000113019f00040000000b001d2a752a6b0000040f000000040b000029000000600310027000000a9e03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000029980000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000029940000c13d000000000006004b000029a50000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0000000005000415000000050550008a00000005055002100000000100200190000029ca0000613d0000001f01400039000000600110018f0000000004b10019000000000014004b0000000001000039000000010100403900000aa10040009c00002a310000213d000000010010019000002a310000c13d000000400040043f0000001f0030008c000029c10000a13d00000000010b043300000b3800100198000029c10000c13d0000000502500270000000000201001f00000b390110019700000b370010009c000029c40000c13d000000000001042d000000000100001900002a7700010430000000000001042f00000ab40100004100000000001404350000000401400039000400000004001d2a7529190000040f00002a050000013d000000040230008c000029ff0000413d000000000400043d00000b3804400197000000000501043b00000b3905500197000000000445019f000000000040043f000000440030008c000029ff0000413d00000b390440019700000ab40040009c000029ff0000c13d000000040510037000000ba7062001980000001f0720018f000000400400043d0000000001640019000029e30000613d000000000805034f0000000009040019000000008a08043c0000000009a90436000000000019004b000029df0000c13d000000000007004b000029f00000613d000000000565034f0000000306700210000000000701043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f0000000000510435000000000504043300000aa10050009c000029ff0000213d0000002401500039000000000031004b000029ff0000213d0000000001450019000000000301043300000aa10030009c000029ff0000213d000000000224001900000000063100190000002006600039000000000026004b00002a0f0000a13d000000400200043d000400000002001d00000ab401000041000000000012043500000004012000392a7529260000040f0000000402000029000000000121004900000a9e0010009c00000a9e01008041000000600110021000000a9e0020009c00000a9e020080410000004002200210000000000121019f00002a770001043000000000023500190000003f0220003900000ba7022001970000000004420019000000000024004b0000000002000039000000010200403900000aa10040009c00002a310000213d000000010020019000002a310000c13d0000000003040019000000400040043f000000000001004b000029ff0000613d00000ab4020000410000000004030019000400000003001d000000000023043500000004023000390000002003000039000000000032043500000024024000392a7526640000040f0000000402000029000000000121004900000a9e0010009c00000a9e0100804100000a9e0020009c00000a9e0200804100000060011002100000004002200210000000000121019f00002a770001043000000b8d01000041000000000010043f0000004101000039000000040010043f00000b2d0100004100002a7700010430000000000001042f00000a9e0010009c00000a9e01008041000000400110021000000a9e0020009c00000a9e020080410000006002200210000000000112019f000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000aac011001c700008010020000392a752a700000040f000000010020019000002a4b0000613d000000000101043b000000000001042d000000000100001900002a770001043000000000050100190000000000200443000000050030008c00002a5b0000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b00002a530000413d00000a9e0030009c00000a9e030080410000006001300210000000000200041400000a9e0020009c00000a9e02008041000000c002200210000000000112019f00000bb3011001c700000000020500192a752a700000040f000000010020019000002a6a0000613d000000000101043b000000000001042d000000000001042f00002a6e002104210000000102000039000000000001042d0000000002000019000000000001042d00002a73002104230000000102000039000000000001042d0000000002000019000000000001042d00002a750000043200002a760001042e00002a770001043000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000000000000000000000000000ffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000ffffffffffffffffffffffffbfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a532405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acebfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a531000000000000000000000000000000000000000000000000ffffffffffffffbf02000000000000000000000000000000000000200000000000000000000000008a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76efffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392702000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e027cceb82823caa45ba60387709961a73050623da2232f8fd178296384aedbd77d833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428927cceb82823caa45ba60387709961a73050623da2232f8fd178296384aedbd76ffffffffffffffffffffffff00000000000000000000000000000000000000000000000200000000000000000000000000000080000001000000000000000000455243323938313a20696e76616c69642072656365697665720000000000000008c379a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000002073616c65507269636500000000000000000000000000000000000000000000455243323938313a20726f79616c7479206665652077696c6c206578636565640000000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000000000000000000007d5c3ff000000000000000000000000000000000000000000000000000000000b4b5b48e00000000000000000000000000000000000000000000000000000000def25aca00000000000000000000000000000000000000000000000000000000f242432900000000000000000000000000000000000000000000000000000000fa914ed400000000000000000000000000000000000000000000000000000000fa914ed500000000000000000000000000000000000000000000000000000000fd762d9200000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000f242432a00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000e985e9c400000000000000000000000000000000000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000eefdc1df00000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000def25acb00000000000000000000000000000000000000000000000000000000e74b981b00000000000000000000000000000000000000000000000000000000d007af5b00000000000000000000000000000000000000000000000000000000d8d07ed900000000000000000000000000000000000000000000000000000000d8d07eda00000000000000000000000000000000000000000000000000000000ddca3f4300000000000000000000000000000000000000000000000000000000ddf0b00900000000000000000000000000000000000000000000000000000000d007af5c00000000000000000000000000000000000000000000000000000000d4f4ddaa00000000000000000000000000000000000000000000000000000000c0bc62f600000000000000000000000000000000000000000000000000000000c0bc62f700000000000000000000000000000000000000000000000000000000c6af66b900000000000000000000000000000000000000000000000000000000b4b5b48f00000000000000000000000000000000000000000000000000000000be537f430000000000000000000000000000000000000000000000000000000091eb290d000000000000000000000000000000000000000000000000000000009d7f4ebe00000000000000000000000000000000000000000000000000000000a9fc664d00000000000000000000000000000000000000000000000000000000a9fc664e00000000000000000000000000000000000000000000000000000000ae796ab300000000000000000000000000000000000000000000000000000000b2db919b000000000000000000000000000000000000000000000000000000009d7f4ebf00000000000000000000000000000000000000000000000000000000a22cb465000000000000000000000000000000000000000000000000000000009694941f0000000000000000000000000000000000000000000000000000000096949420000000000000000000000000000000000000000000000000000000009d645a440000000000000000000000000000000000000000000000000000000091eb290e0000000000000000000000000000000000000000000000000000000095d89b4100000000000000000000000000000000000000000000000000000000809a619d0000000000000000000000000000000000000000000000000000000089a302700000000000000000000000000000000000000000000000000000000089a30271000000000000000000000000000000000000000000000000000000008d1d9520000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000809a619e0000000000000000000000000000000000000000000000000000000083e096ce000000000000000000000000000000000000000000000000000000007f58b4be000000000000000000000000000000000000000000000000000000007f58b4bf000000000000000000000000000000000000000000000000000000007f631e47000000000000000000000000000000000000000000000000000000007d5c3ff1000000000000000000000000000000000000000000000000000000007ecebe00000000000000000000000000000000000000000000000000000000002e8da828000000000000000000000000000000000000000000000000000000005d4c1d45000000000000000000000000000000000000000000000000000000006c0360ea000000000000000000000000000000000000000000000000000000006c3b8698000000000000000000000000000000000000000000000000000000006c3b8699000000000000000000000000000000000000000000000000000000006e85a0d900000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000006c0360eb000000000000000000000000000000000000000000000000000000006c19e783000000000000000000000000000000000000000000000000000000006291484800000000000000000000000000000000000000000000000000000000629148490000000000000000000000000000000000000000000000000000000069fe0e2d000000000000000000000000000000000000000000000000000000005d4c1d46000000000000000000000000000000000000000000000000000000006134716200000000000000000000000000000000000000000000000000000000495c8bf80000000000000000000000000000000000000000000000000000000054d1f13c0000000000000000000000000000000000000000000000000000000054d1f13d000000000000000000000000000000000000000000000000000000005b7633d0000000000000000000000000000000000000000000000000000000005beaa04900000000000000000000000000000000000000000000000000000000495c8bf9000000000000000000000000000000000000000000000000000000004e1273f4000000000000000000000000000000000000000000000000000000002fc47b23000000000000000000000000000000000000000000000000000000002fc47b240000000000000000000000000000000000000000000000000000000042d96dd7000000000000000000000000000000000000000000000000000000002e8da829000000000000000000000000000000000000000000000000000000002eb2c2d6000000000000000000000000000000000000000000000000000000000e89341b000000000000000000000000000000000000000000000000000000001c33b32700000000000000000000000000000000000000000000000000000000256929610000000000000000000000000000000000000000000000000000000025692962000000000000000000000000000000000000000000000000000000002a55205a000000000000000000000000000000000000000000000000000000002e1a7d4d000000000000000000000000000000000000000000000000000000001c33b328000000000000000000000000000000000000000000000000000000001ed74928000000000000000000000000000000000000000000000000000000001647795d000000000000000000000000000000000000000000000000000000001647795e000000000000000000000000000000000000000000000000000000001b25b077000000000000000000000000000000000000000000000000000000000e89341c000000000000000000000000000000000000000000000000000000000fa7b7b30000000000000000000000000000000000000000000000000000000002fe53040000000000000000000000000000000000000000000000000000000006fdde020000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000098144d4000000000000000000000000000000000000000000000000000000000dce83c70000000000000000000000000000000000000000000000000000000002fe53050000000000000000000000000000000000000000000000000000000004845e3e000000000000000000000000000000000000000000000000000000000146354500000000000000000000000000000000000000000000000000000000014635460000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000009a9b7b0000000000000000000000000000000000000000000000000000000000fdd58e00000000000000000000000000000000000000000000000000000000389a75e100000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000da0194c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000002304aa02000000000000000000000000000000000000000000000000000000008d74431400000000000000000000000000000000000000000000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e020000020000000000000000000000000000004400000000000000000000000070a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c0000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f02000000000000000000000000000000000000400000000000000000000000008ee600cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000285fb8c800000000000000000000000000000000000000000000000000000000c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62f23a6e610000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000006f5e8818000000000000000000000000000000000000000000000000ffffffffffffff3f0000000019457468657265756d205369676e6564204d6573736167653a0a3332020000000000000000000000000000000000003c0000000400000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000800000000000000000000000008baa579f000000000000000000000000000000000000000000000000000000002d0a346e0000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000f499da2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffe9f000000000000000000000000000000000000000000000000fffffffffffffedfffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000d8e6d657f706eb987a687ae78b967b4b1cf806551ebeb3a85471d9b8cf6c04a0000000000000000000000000000000000000000000000000fffffffffffffeff0000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010000000080000000000000000048b6e6df0000000000000000000000000000000000000000000000000000000042cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd180b41246c05cbb406f874e82aa2faf7db11bba9792fe09929e56ef1eee2c2da3c212ef7d00000000000000000000000000000000000000000000000000000000feea0d9900000000000000000000000000000000000000000000000000000000bd8c6ccc00000000000000000000000000000000000000000000000000000000b955455200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000080000000000000000017e94a6c000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe02f34bba70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008000000000000000000000000000000000000000000000000000000024000000e0000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000001200000008000000000000000007820c10a00000000000000000000000000000000000000000000000000000000321aa27e9c5c4ca98453ba7da9a1af4aa7bfed3bab5098e02fee58ce3cafe6b7cbe4e8c30000000000000000000000000000000000000000000000000000000017307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31455243313135353a2073657474696e6720617070726f76616c2073746174757320666f722073656c66000000000000000000000000000000000000000000000000000000000000000000000000000000000000840000008000000000000000009445f53000000000000000000000000000000000000000000000000000000000f91d7f9b00000000000000000000000000000000000000000000000000000000ad3d6587006c45fb2f92060267e172188795374f8f5bdf4187d50c571cce287fc19c461c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdfecb0813fff72f72d5c424535fe69f97316a856e5cd5830226c189a4a8662e2c10bd8a3eb000000000000000000000000000000000000000000000000000000000000000000000000000000000000721c310194ccfc01e523fc93c9cccfa2a0ac01ffc9a700000000000000000000000000000000000000000000000000000000cc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac32483afb0000000000000000000000000000000000000000000000000000000039ffc7ba00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f48c460c80000000000000000000000000000000000000000000000000000000081fd5f457056a8b19e623dc52551a385bfcafd0914d3942446ecab71d19b123b7300000000000000000000000000000000000000000000000000000000000000455243313135353a206d696e7420746f20746865207a65726f20616464726573d76288d70000000000000000000000000000000000000000000000000000000038685a6b00000000000000000000000000000000000000000000000000000000fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92206d69736d617463680000000000000000000000000000000000000000000000455243313135353a206163636f756e747320616e6420696473206c656e67746800000000000000000000000000000000000000000000003fffffffffffffffe0616c6964206f776e657200000000000000000000000000000000000000000000455243313135353a2061646472657373207a65726f206973206e6f74206120763fe5df9900000000000000000000000000000000000000000000000000000000756688fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff5fbf7c9c2f00000000000000000000000000000000000000000000000000000000ed7318a9455ec161085222a6e508a46debace6235bba0202c768d3840f809c85616e636500000000000000000000000000000000000000000000000000000000455243313135353a206275726e20616d6f756e7420657863656564732062616c6573730000000000000000000000000000000000000000000000000000000000455243313135353a206275726e2066726f6d20746865207a65726f2061646472000000000000000000000000000000000000000000000000000000008baa579f6572206f7220617070726f766564000000000000000000000000000000000000455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e6d69736d61746368000000000000000000000000000000000000000000000000455243313135353a2069647320616e6420616d6f756e7473206c656e677468204e487b710000000000000000000000000000000000000000000000000000000072207472616e7366657200000000000000000000000000000000000000000000455243313135353a20696e73756666696369656e742062616c616e636520666f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fbbc197c81000000000000000000000000000000000000000000000000000000006472657373000000000000000000000000000000000000000000000000000000455243313135353a207472616e7366657220746f20746865207a65726f206164d72dde5e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000008000000000000000000000000000000000000000000000000000000040000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff30000000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002b8acba10000000000000000000000000000000000000000000000000000000075e52f4f000000000000000000000000000000000000000000000000000000004b092bc80000000000000000000000000000000000000000000000000000000044594c49000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000082b429002a552059ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2a55205a00000000000000000000000000000000000000000000000000000000d9b67a260000000000000000000000000000000000000000000000000000000086455d28000000000000000000000000000000000000000000000000000000000e89341c00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeff000000000000000000000000000000000000000000000000ffffffffffffff00000000000000000000000000000000000000000000000000ffffffffffffffe06420746f6b656e73000000000000000000000000000000000000000000000000455243313135353a204552433131353552656365697665722072656a65637465526563656976657220696d706c656d656e746572000000000000000000000000455243313135353a207472616e7366657220746f206e6f6e2d4552433131353502000002000000000000000000000000000000000000000000000000000000001cd0d39b6d14160d637403115c38dc55015fde58c75aee42b9a772dd1ee20fc2
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000012000000000000000000000000084a71ccd554cc1b02749b35d22f684cc8ec987e1000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c647807000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c64780700000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c4b4000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000000000000000000000000000000000000000002068747470733a2f2f7777772e64796c692e696f2f6170692f6d65746164617461
-----Decoded View---------------
Arg [0] : _baseURI (string): https://www.dyli.io/api/metadata
Arg [1] : usdc_ (address): 0x84A71ccD554Cc1b02749b35d22F684CC8ec987e1
Arg [2] : signerAddress_ (address): 0xfB1302F5D6c5F107a0715b8Ce7303D1e3C647807
Arg [3] : feeRecipient_ (address): 0xfB1302F5D6c5F107a0715b8Ce7303D1e3C647807
Arg [4] : royaltyFeeNumerator_ (uint96): 500
Arg [5] : initialQueueFee (uint256): 2000000
Arg [6] : initialLoseQueueRefund (uint256): 0
Arg [7] : initialCreateFee (uint256): 5000000
Arg [8] : initialFee (uint256): 2000000
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [1] : 00000000000000000000000084a71ccd554cc1b02749b35d22f684cc8ec987e1
Arg [2] : 000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c647807
Arg [3] : 000000000000000000000000fb1302f5d6c5f107a0715b8ce7303d1e3c647807
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [5] : 00000000000000000000000000000000000000000000000000000000001e8480
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 00000000000000000000000000000000000000000000000000000000004c4b40
Arg [8] : 00000000000000000000000000000000000000000000000000000000001e8480
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [10] : 68747470733a2f2f7777772e64796c692e696f2f6170692f6d65746164617461
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1,322.52
Net Worth in ETH
0.451293
Token Allocations
USDC.E
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ABSTRACT | 100.00% | $0.999607 | 1,323.04 | $1,322.52 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.