Overview
APE Balance
APE Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Multichain Info
Latest 25 from a total of 425 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 32730423 | 32 hrs ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32729753 | 32 hrs ago | IN | 0 APE | 0.00470201 | ||||
| Set Approval For... | 32727972 | 34 hrs ago | IN | 0 APE | 0.00470079 | ||||
| Safe Transfer Fr... | 32727770 | 34 hrs ago | IN | 0 APE | 0.00715297 | ||||
| Safe Transfer Fr... | 32727769 | 34 hrs ago | IN | 0 APE | 0.00715297 | ||||
| Safe Transfer Fr... | 32727768 | 34 hrs ago | IN | 0 APE | 0.00715297 | ||||
| Safe Transfer Fr... | 32727765 | 34 hrs ago | IN | 0 APE | 0.00715297 | ||||
| Set Approval For... | 32706805 | 47 hrs ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32706778 | 47 hrs ago | IN | 0 APE | 0.00470933 | ||||
| Set Approval For... | 32704464 | 2 days ago | IN | 0 APE | 0.00470933 | ||||
| Set Approval For... | 32689676 | 2 days ago | IN | 0 APE | 0.00470933 | ||||
| Set Approval For... | 32645259 | 3 days ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32643961 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32643952 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32643945 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32643845 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32643830 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32643815 | 3 days ago | IN | 0 APE | 0.00267852 | ||||
| Set Approval For... | 32620054 | 4 days ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32582920 | 4 days ago | IN | 0 APE | 0.00470933 | ||||
| Set Approval For... | 32582917 | 4 days ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32576901 | 5 days ago | IN | 0 APE | 0.00470079 | ||||
| Set Approval For... | 32554096 | 5 days ago | IN | 0 APE | 0.00470079 | ||||
| Safe Transfer Fr... | 32554003 | 5 days ago | IN | 0 APE | 0.00764105 | ||||
| Set Approval For... | 32552999 | 5 days ago | IN | 0 APE | 0.00470079 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {ERC1155} from "solady/tokens/ERC1155.sol";
import {ERC2981} from "solady/tokens/ERC2981.sol";
import {LibString} from "solady/utils/LibString.sol";
import {ITransferValidator} from "./interfaces/ITransferValidator.sol";
import {ICreatorToken} from "./interfaces/ICreatorToken.sol";
contract BAYCFeels is OwnableRoles, ERC1155, ERC2981, ICreatorToken {
using LibString for uint256;
using LibString for string;
error ZeroAmount();
error ArrayLengthZero();
error ArrayLengthMismatch();
error TransferValidatorNotSet();
error TokenNotEnabled(uint256 tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
string public baseURI;
address public santaCurtis;
mapping(uint256 tokenId => uint256 supply) public totalSupply;
mapping(uint256 tokenId => bool isEnabled) public isEnabled;
uint256 public constant ADMIN_ROLE = _ROLE_42;
uint256 public constant MINTER_ROLE = _ROLE_69;
ITransferValidator private _transferValidator;
constructor(address transferValidator, address royaltyRecipient, string memory _baseURI, address _santaCurtis) {
_initializeOwner(tx.origin);
_grantRoles(tx.origin, MINTER_ROLE);
if (transferValidator == address(0)) revert TransferValidatorNotSet();
baseURI = _baseURI;
_setDefaultRoyalty(royaltyRecipient, 500);
santaCurtis = _santaCurtis;
_transferValidator = ITransferValidator(transferValidator);
emit TransferValidatorUpdated(address(0), transferValidator);
}
/**
* @notice Redeems a redemption code for a token.
* @param tokenId The ID of the token to mint.
* @param amount The amount of tokens to mint.
*/
function mint(uint64 tokenId, uint256 amount) public onlyRoles(MINTER_ROLE) {
if (amount == 0) revert ZeroAmount();
if (!isEnabled[tokenId]) revert TokenNotEnabled(tokenId);
totalSupply[tokenId] += amount;
_mint(santaCurtis, tokenId, amount, "");
}
function airdrop(address[] calldata to, uint256[][] calldata tokenIds, uint256[][] calldata amounts)
external
onlyRoles(MINTER_ROLE)
{
if (to.length != tokenIds.length || to.length != amounts.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < to.length; i++) {
if (tokenIds[i].length != amounts[i].length) revert ArrayLengthMismatch();
if (tokenIds.length == 1) {
mint(uint64(tokenIds[i][0]), amounts[i][0]);
} else {
batchMint(to[i], tokenIds[i], amounts[i]);
}
}
}
/**
* @notice Mints a batch of tokens.
* @param tokenIds The IDs of the tokens to mint.
* @param amounts The amounts of tokens to mint.
*/
function batchMint(address to, uint256[] calldata tokenIds, uint256[] calldata amounts)
public
onlyRoles(MINTER_ROLE)
{
if (tokenIds.length == 0) revert ArrayLengthZero();
for (uint256 i = 0; i < tokenIds.length; i++) {
if (!isEnabled[tokenIds[i]]) revert TokenNotEnabled(tokenIds[i]);
totalSupply[tokenIds[i]] += amounts[i];
}
_batchMint(to, tokenIds, amounts, "");
}
/**
* @dev Sets the royalty information for the token collection.
* @param receiver The address of the royalty recipient.
* @param feeNumerator The royalty fee numerator.
*/
function setRoyaltyInfo(address receiver, uint96 feeNumerator) external onlyRolesOrOwner(ADMIN_ROLE) {
_setDefaultRoyalty(receiver, feeNumerator);
}
/**
* @notice Sets the base URI for the token collection.
* @param _baseURI The new base URI.
*/
function setBaseURI(string memory _baseURI) external onlyRolesOrOwner(ADMIN_ROLE) {
baseURI = _baseURI;
emit BatchMetadataUpdate(0, type(uint256).max);
}
/**
* @notice Sets the transfer validator for the collection.
*/
function setTransferValidator(address transferValidator) external onlyRolesOrOwner(ADMIN_ROLE) {
address oldValidator = address(_transferValidator);
_transferValidator = ITransferValidator(transferValidator);
emit TransferValidatorUpdated(oldValidator, transferValidator);
}
/**
* @notice Sets the santa Curtis address.
*/
function setSantaCurtis(address _santaCurtis) external onlyRolesOrOwner(ADMIN_ROLE) {
santaCurtis = _santaCurtis;
}
/**
* @notice Sets the enabled status for a token.
* @param tokenIds The IDs of the tokens to set the enabled status for.
* @param _isEnabled The new enabled status.
*/
function setEnabledBatch(uint64[] calldata tokenIds, bool[] calldata _isEnabled)
external
onlyRolesOrOwner(ADMIN_ROLE)
{
if (tokenIds.length != _isEnabled.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < tokenIds.length; i++) {
isEnabled[tokenIds[i]] = _isEnabled[i];
}
}
/**
* @notice Returns the transfer validator for the collection.
*/
function getTransferValidator() external view returns (address validator) {
return address(_transferValidator);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256,uint256)"));
isViewFunction = false;
}
function uri(uint256 tokenId) public view virtual override returns (string memory) {
return baseURI.concat(tokenId.toString());
}
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
return baseURI.concat(tokenId.toString());
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC2981) returns (bool) {
return ERC1155.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId)
|| interfaceId == type(ICreatorToken).interfaceId || super.supportsInterface(interfaceId);
}
function name() public view virtual returns (string memory) {
return "BAYC Feels";
}
function symbol() public view virtual returns (string memory) {
return "BAYCFEELS";
}
function _useBeforeTokenTransfer() internal pure override returns (bool) {
return true;
}
/// @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 `id` and `amount` arrays are 1.
function _beforeTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory
) internal override {
if (from != address(0) && to != address(0)) {
for (uint256 i = 0; i < ids.length; i++) {
_transferValidator.validateTransfer(msg.sender, from, to, ids[i], amounts[i]);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Ownable} from "./Ownable.sol";
/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.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 OwnableRoles is Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `user`'s roles is updated to `roles`.
/// Each bit of `roles` represents whether the role is set.
event RolesUpdated(address indexed user, uint256 indexed roles);
/// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The role slot of `user` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
/// let roleSlot := keccak256(0x00, 0x20)
/// ```
/// This automatically ignores the upper bits of the `user` in case
/// they are not clean, as well as keep the `keccak256` under 32-bytes.
///
/// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Overwrite the roles directly without authorization guard.
function _setRoles(address user, uint256 roles) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Store the new value.
sstore(keccak256(0x0c, 0x20), roles)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
}
}
/// @dev Updates the roles directly without authorization guard.
/// If `on` is true, each set bit of `roles` will be turned on,
/// otherwise, each set bit of `roles` will be turned off.
function _updateRoles(address user, uint256 roles, bool on) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
let roleSlot := keccak256(0x0c, 0x20)
// Load the current value.
let current := sload(roleSlot)
// Compute the updated roles if `on` is true.
let updated := or(current, roles)
// Compute the updated roles if `on` is false.
// Use `and` to compute the intersection of `current` and `roles`,
// `xor` it with `current` to flip the bits in the intersection.
if iszero(on) { updated := xor(current, and(current, roles)) }
// Then, store the new value.
sstore(roleSlot, updated)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
}
}
/// @dev Grants the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn on.
function _grantRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, true);
}
/// @dev Removes the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn off.
function _removeRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, false);
}
/// @dev Throws if the sender does not have any of the `roles`.
function _checkRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Throws if the sender is not the owner,
/// and does not have any of the `roles`.
/// Checks for ownership first, then lazily checks for roles.
function _checkOwnerOrRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Throws if the sender does not have any of the `roles`,
/// and is not the owner.
/// Checks for roles first, then lazily checks for ownership.
function _checkRolesOrOwner(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
// We don't need to mask the values of `ordinals`, as Solidity
// cleans dirty upper bits when storing variables into memory.
roles := or(shl(mload(add(ordinals, i)), 1), roles)
}
}
}
/// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
/// @solidity memory-safe-assembly
assembly {
// Grab the pointer to the free memory.
ordinals := mload(0x40)
let ptr := add(ordinals, 0x20)
let o := 0
// The absence of lookup tables, De Bruijn, etc., here is intentional for
// smaller bytecode, as this function is not meant to be called on-chain.
for { let t := roles } 1 {} {
mstore(ptr, o)
// `shr` 5 is equivalent to multiplying by 0x20.
// Push back into the ordinals array if the bit is set.
ptr := add(ptr, shl(5, and(t, 1)))
o := add(o, 1)
t := shr(o, roles)
if iszero(t) { break }
}
// Store the length of `ordinals`.
mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
// Allocate the memory.
mstore(0x40, ptr)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to grant `user` `roles`.
/// If the `user` already has a role, then it will be an no-op for the role.
function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
_grantRoles(user, roles);
}
/// @dev Allows the owner to remove `user` `roles`.
/// If the `user` does not have a role, then it will be an no-op for the role.
function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
_removeRoles(user, roles);
}
/// @dev Allow the caller to remove their own roles.
/// If the caller does not have a role, then it will be an no-op for the role.
function renounceRoles(uint256 roles) public payable virtual {
_removeRoles(msg.sender, roles);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the roles of `user`.
function rolesOf(address user) public view virtual returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Load the stored value.
roles := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns whether `user` has any of `roles`.
function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles != 0;
}
/// @dev Returns whether `user` has all of `roles`.
function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles == roles;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by an account with `roles`.
modifier onlyRoles(uint256 roles) virtual {
_checkRoles(roles);
_;
}
/// @dev Marks a function as only callable by the owner or by an account
/// with `roles`. Checks for ownership first, then lazily checks for roles.
modifier onlyOwnerOrRoles(uint256 roles) virtual {
_checkOwnerOrRoles(roles);
_;
}
/// @dev Marks a function as only callable by an account with `roles`
/// or the owner. Checks for roles first, then lazily checks for ownership.
modifier onlyRolesOrOwner(uint256 roles) virtual {
_checkRolesOrOwner(roles);
_;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ROLE CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// IYKYK
uint256 internal constant _ROLE_0 = 1 << 0;
uint256 internal constant _ROLE_1 = 1 << 1;
uint256 internal constant _ROLE_2 = 1 << 2;
uint256 internal constant _ROLE_3 = 1 << 3;
uint256 internal constant _ROLE_4 = 1 << 4;
uint256 internal constant _ROLE_5 = 1 << 5;
uint256 internal constant _ROLE_6 = 1 << 6;
uint256 internal constant _ROLE_7 = 1 << 7;
uint256 internal constant _ROLE_8 = 1 << 8;
uint256 internal constant _ROLE_9 = 1 << 9;
uint256 internal constant _ROLE_10 = 1 << 10;
uint256 internal constant _ROLE_11 = 1 << 11;
uint256 internal constant _ROLE_12 = 1 << 12;
uint256 internal constant _ROLE_13 = 1 << 13;
uint256 internal constant _ROLE_14 = 1 << 14;
uint256 internal constant _ROLE_15 = 1 << 15;
uint256 internal constant _ROLE_16 = 1 << 16;
uint256 internal constant _ROLE_17 = 1 << 17;
uint256 internal constant _ROLE_18 = 1 << 18;
uint256 internal constant _ROLE_19 = 1 << 19;
uint256 internal constant _ROLE_20 = 1 << 20;
uint256 internal constant _ROLE_21 = 1 << 21;
uint256 internal constant _ROLE_22 = 1 << 22;
uint256 internal constant _ROLE_23 = 1 << 23;
uint256 internal constant _ROLE_24 = 1 << 24;
uint256 internal constant _ROLE_25 = 1 << 25;
uint256 internal constant _ROLE_26 = 1 << 26;
uint256 internal constant _ROLE_27 = 1 << 27;
uint256 internal constant _ROLE_28 = 1 << 28;
uint256 internal constant _ROLE_29 = 1 << 29;
uint256 internal constant _ROLE_30 = 1 << 30;
uint256 internal constant _ROLE_31 = 1 << 31;
uint256 internal constant _ROLE_32 = 1 << 32;
uint256 internal constant _ROLE_33 = 1 << 33;
uint256 internal constant _ROLE_34 = 1 << 34;
uint256 internal constant _ROLE_35 = 1 << 35;
uint256 internal constant _ROLE_36 = 1 << 36;
uint256 internal constant _ROLE_37 = 1 << 37;
uint256 internal constant _ROLE_38 = 1 << 38;
uint256 internal constant _ROLE_39 = 1 << 39;
uint256 internal constant _ROLE_40 = 1 << 40;
uint256 internal constant _ROLE_41 = 1 << 41;
uint256 internal constant _ROLE_42 = 1 << 42;
uint256 internal constant _ROLE_43 = 1 << 43;
uint256 internal constant _ROLE_44 = 1 << 44;
uint256 internal constant _ROLE_45 = 1 << 45;
uint256 internal constant _ROLE_46 = 1 << 46;
uint256 internal constant _ROLE_47 = 1 << 47;
uint256 internal constant _ROLE_48 = 1 << 48;
uint256 internal constant _ROLE_49 = 1 << 49;
uint256 internal constant _ROLE_50 = 1 << 50;
uint256 internal constant _ROLE_51 = 1 << 51;
uint256 internal constant _ROLE_52 = 1 << 52;
uint256 internal constant _ROLE_53 = 1 << 53;
uint256 internal constant _ROLE_54 = 1 << 54;
uint256 internal constant _ROLE_55 = 1 << 55;
uint256 internal constant _ROLE_56 = 1 << 56;
uint256 internal constant _ROLE_57 = 1 << 57;
uint256 internal constant _ROLE_58 = 1 << 58;
uint256 internal constant _ROLE_59 = 1 << 59;
uint256 internal constant _ROLE_60 = 1 << 60;
uint256 internal constant _ROLE_61 = 1 << 61;
uint256 internal constant _ROLE_62 = 1 << 62;
uint256 internal constant _ROLE_63 = 1 << 63;
uint256 internal constant _ROLE_64 = 1 << 64;
uint256 internal constant _ROLE_65 = 1 << 65;
uint256 internal constant _ROLE_66 = 1 << 66;
uint256 internal constant _ROLE_67 = 1 << 67;
uint256 internal constant _ROLE_68 = 1 << 68;
uint256 internal constant _ROLE_69 = 1 << 69;
uint256 internal constant _ROLE_70 = 1 << 70;
uint256 internal constant _ROLE_71 = 1 << 71;
uint256 internal constant _ROLE_72 = 1 << 72;
uint256 internal constant _ROLE_73 = 1 << 73;
uint256 internal constant _ROLE_74 = 1 << 74;
uint256 internal constant _ROLE_75 = 1 << 75;
uint256 internal constant _ROLE_76 = 1 << 76;
uint256 internal constant _ROLE_77 = 1 << 77;
uint256 internal constant _ROLE_78 = 1 << 78;
uint256 internal constant _ROLE_79 = 1 << 79;
uint256 internal constant _ROLE_80 = 1 << 80;
uint256 internal constant _ROLE_81 = 1 << 81;
uint256 internal constant _ROLE_82 = 1 << 82;
uint256 internal constant _ROLE_83 = 1 << 83;
uint256 internal constant _ROLE_84 = 1 << 84;
uint256 internal constant _ROLE_85 = 1 << 85;
uint256 internal constant _ROLE_86 = 1 << 86;
uint256 internal constant _ROLE_87 = 1 << 87;
uint256 internal constant _ROLE_88 = 1 << 88;
uint256 internal constant _ROLE_89 = 1 << 89;
uint256 internal constant _ROLE_90 = 1 << 90;
uint256 internal constant _ROLE_91 = 1 << 91;
uint256 internal constant _ROLE_92 = 1 << 92;
uint256 internal constant _ROLE_93 = 1 << 93;
uint256 internal constant _ROLE_94 = 1 << 94;
uint256 internal constant _ROLE_95 = 1 << 95;
uint256 internal constant _ROLE_96 = 1 << 96;
uint256 internal constant _ROLE_97 = 1 << 97;
uint256 internal constant _ROLE_98 = 1 << 98;
uint256 internal constant _ROLE_99 = 1 << 99;
uint256 internal constant _ROLE_100 = 1 << 100;
uint256 internal constant _ROLE_101 = 1 << 101;
uint256 internal constant _ROLE_102 = 1 << 102;
uint256 internal constant _ROLE_103 = 1 << 103;
uint256 internal constant _ROLE_104 = 1 << 104;
uint256 internal constant _ROLE_105 = 1 << 105;
uint256 internal constant _ROLE_106 = 1 << 106;
uint256 internal constant _ROLE_107 = 1 << 107;
uint256 internal constant _ROLE_108 = 1 << 108;
uint256 internal constant _ROLE_109 = 1 << 109;
uint256 internal constant _ROLE_110 = 1 << 110;
uint256 internal constant _ROLE_111 = 1 << 111;
uint256 internal constant _ROLE_112 = 1 << 112;
uint256 internal constant _ROLE_113 = 1 << 113;
uint256 internal constant _ROLE_114 = 1 << 114;
uint256 internal constant _ROLE_115 = 1 << 115;
uint256 internal constant _ROLE_116 = 1 << 116;
uint256 internal constant _ROLE_117 = 1 << 117;
uint256 internal constant _ROLE_118 = 1 << 118;
uint256 internal constant _ROLE_119 = 1 << 119;
uint256 internal constant _ROLE_120 = 1 << 120;
uint256 internal constant _ROLE_121 = 1 << 121;
uint256 internal constant _ROLE_122 = 1 << 122;
uint256 internal constant _ROLE_123 = 1 << 123;
uint256 internal constant _ROLE_124 = 1 << 124;
uint256 internal constant _ROLE_125 = 1 << 125;
uint256 internal constant _ROLE_126 = 1 << 126;
uint256 internal constant _ROLE_127 = 1 << 127;
uint256 internal constant _ROLE_128 = 1 << 128;
uint256 internal constant _ROLE_129 = 1 << 129;
uint256 internal constant _ROLE_130 = 1 << 130;
uint256 internal constant _ROLE_131 = 1 << 131;
uint256 internal constant _ROLE_132 = 1 << 132;
uint256 internal constant _ROLE_133 = 1 << 133;
uint256 internal constant _ROLE_134 = 1 << 134;
uint256 internal constant _ROLE_135 = 1 << 135;
uint256 internal constant _ROLE_136 = 1 << 136;
uint256 internal constant _ROLE_137 = 1 << 137;
uint256 internal constant _ROLE_138 = 1 << 138;
uint256 internal constant _ROLE_139 = 1 << 139;
uint256 internal constant _ROLE_140 = 1 << 140;
uint256 internal constant _ROLE_141 = 1 << 141;
uint256 internal constant _ROLE_142 = 1 << 142;
uint256 internal constant _ROLE_143 = 1 << 143;
uint256 internal constant _ROLE_144 = 1 << 144;
uint256 internal constant _ROLE_145 = 1 << 145;
uint256 internal constant _ROLE_146 = 1 << 146;
uint256 internal constant _ROLE_147 = 1 << 147;
uint256 internal constant _ROLE_148 = 1 << 148;
uint256 internal constant _ROLE_149 = 1 << 149;
uint256 internal constant _ROLE_150 = 1 << 150;
uint256 internal constant _ROLE_151 = 1 << 151;
uint256 internal constant _ROLE_152 = 1 << 152;
uint256 internal constant _ROLE_153 = 1 << 153;
uint256 internal constant _ROLE_154 = 1 << 154;
uint256 internal constant _ROLE_155 = 1 << 155;
uint256 internal constant _ROLE_156 = 1 << 156;
uint256 internal constant _ROLE_157 = 1 << 157;
uint256 internal constant _ROLE_158 = 1 << 158;
uint256 internal constant _ROLE_159 = 1 << 159;
uint256 internal constant _ROLE_160 = 1 << 160;
uint256 internal constant _ROLE_161 = 1 << 161;
uint256 internal constant _ROLE_162 = 1 << 162;
uint256 internal constant _ROLE_163 = 1 << 163;
uint256 internal constant _ROLE_164 = 1 << 164;
uint256 internal constant _ROLE_165 = 1 << 165;
uint256 internal constant _ROLE_166 = 1 << 166;
uint256 internal constant _ROLE_167 = 1 << 167;
uint256 internal constant _ROLE_168 = 1 << 168;
uint256 internal constant _ROLE_169 = 1 << 169;
uint256 internal constant _ROLE_170 = 1 << 170;
uint256 internal constant _ROLE_171 = 1 << 171;
uint256 internal constant _ROLE_172 = 1 << 172;
uint256 internal constant _ROLE_173 = 1 << 173;
uint256 internal constant _ROLE_174 = 1 << 174;
uint256 internal constant _ROLE_175 = 1 << 175;
uint256 internal constant _ROLE_176 = 1 << 176;
uint256 internal constant _ROLE_177 = 1 << 177;
uint256 internal constant _ROLE_178 = 1 << 178;
uint256 internal constant _ROLE_179 = 1 << 179;
uint256 internal constant _ROLE_180 = 1 << 180;
uint256 internal constant _ROLE_181 = 1 << 181;
uint256 internal constant _ROLE_182 = 1 << 182;
uint256 internal constant _ROLE_183 = 1 << 183;
uint256 internal constant _ROLE_184 = 1 << 184;
uint256 internal constant _ROLE_185 = 1 << 185;
uint256 internal constant _ROLE_186 = 1 << 186;
uint256 internal constant _ROLE_187 = 1 << 187;
uint256 internal constant _ROLE_188 = 1 << 188;
uint256 internal constant _ROLE_189 = 1 << 189;
uint256 internal constant _ROLE_190 = 1 << 190;
uint256 internal constant _ROLE_191 = 1 << 191;
uint256 internal constant _ROLE_192 = 1 << 192;
uint256 internal constant _ROLE_193 = 1 << 193;
uint256 internal constant _ROLE_194 = 1 << 194;
uint256 internal constant _ROLE_195 = 1 << 195;
uint256 internal constant _ROLE_196 = 1 << 196;
uint256 internal constant _ROLE_197 = 1 << 197;
uint256 internal constant _ROLE_198 = 1 << 198;
uint256 internal constant _ROLE_199 = 1 << 199;
uint256 internal constant _ROLE_200 = 1 << 200;
uint256 internal constant _ROLE_201 = 1 << 201;
uint256 internal constant _ROLE_202 = 1 << 202;
uint256 internal constant _ROLE_203 = 1 << 203;
uint256 internal constant _ROLE_204 = 1 << 204;
uint256 internal constant _ROLE_205 = 1 << 205;
uint256 internal constant _ROLE_206 = 1 << 206;
uint256 internal constant _ROLE_207 = 1 << 207;
uint256 internal constant _ROLE_208 = 1 << 208;
uint256 internal constant _ROLE_209 = 1 << 209;
uint256 internal constant _ROLE_210 = 1 << 210;
uint256 internal constant _ROLE_211 = 1 << 211;
uint256 internal constant _ROLE_212 = 1 << 212;
uint256 internal constant _ROLE_213 = 1 << 213;
uint256 internal constant _ROLE_214 = 1 << 214;
uint256 internal constant _ROLE_215 = 1 << 215;
uint256 internal constant _ROLE_216 = 1 << 216;
uint256 internal constant _ROLE_217 = 1 << 217;
uint256 internal constant _ROLE_218 = 1 << 218;
uint256 internal constant _ROLE_219 = 1 << 219;
uint256 internal constant _ROLE_220 = 1 << 220;
uint256 internal constant _ROLE_221 = 1 << 221;
uint256 internal constant _ROLE_222 = 1 << 222;
uint256 internal constant _ROLE_223 = 1 << 223;
uint256 internal constant _ROLE_224 = 1 << 224;
uint256 internal constant _ROLE_225 = 1 << 225;
uint256 internal constant _ROLE_226 = 1 << 226;
uint256 internal constant _ROLE_227 = 1 << 227;
uint256 internal constant _ROLE_228 = 1 << 228;
uint256 internal constant _ROLE_229 = 1 << 229;
uint256 internal constant _ROLE_230 = 1 << 230;
uint256 internal constant _ROLE_231 = 1 << 231;
uint256 internal constant _ROLE_232 = 1 << 232;
uint256 internal constant _ROLE_233 = 1 << 233;
uint256 internal constant _ROLE_234 = 1 << 234;
uint256 internal constant _ROLE_235 = 1 << 235;
uint256 internal constant _ROLE_236 = 1 << 236;
uint256 internal constant _ROLE_237 = 1 << 237;
uint256 internal constant _ROLE_238 = 1 << 238;
uint256 internal constant _ROLE_239 = 1 << 239;
uint256 internal constant _ROLE_240 = 1 << 240;
uint256 internal constant _ROLE_241 = 1 << 241;
uint256 internal constant _ROLE_242 = 1 << 242;
uint256 internal constant _ROLE_243 = 1 << 243;
uint256 internal constant _ROLE_244 = 1 << 244;
uint256 internal constant _ROLE_245 = 1 << 245;
uint256 internal constant _ROLE_246 = 1 << 246;
uint256 internal constant _ROLE_247 = 1 << 247;
uint256 internal constant _ROLE_248 = 1 << 248;
uint256 internal constant _ROLE_249 = 1 << 249;
uint256 internal constant _ROLE_250 = 1 << 250;
uint256 internal constant _ROLE_251 = 1 << 251;
uint256 internal constant _ROLE_252 = 1 << 252;
uint256 internal constant _ROLE_253 = 1 << 253;
uint256 internal constant _ROLE_254 = 1 << 254;
uint256 internal constant _ROLE_255 = 1 << 255;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC1155 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol)
///
/// @dev Note:
/// - The ERC1155 standard allows for self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The transfer functions use the identity precompile (0x4)
/// to copy memory internally.
///
/// If you are overriding:
/// - Make sure all variables written to storage are properly cleaned
// (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC1155 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The lengths of the input arrays are not the same.
error ArrayLengthsMismatch();
/// @dev Cannot mint or transfer to the zero address.
error TransferToZeroAddress();
/// @dev The recipient's balance has overflowed.
error AccountBalanceOverflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Only the token owner or an approved account can manage the tokens.
error NotOwnerNorApproved();
/// @dev Cannot safely transfer to a contract that does not implement
/// the ERC1155Receiver interface.
error TransferToNonERC1155ReceiverImplementer();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` of token `id` is transferred
/// from `from` to `to` by `operator`.
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 amount
);
/// @dev Emitted when `amounts` of token `ids` are transferred
/// from `from` to `to` by `operator`.
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] amounts
);
/// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);
/// @dev Emitted when the Uniform Resource Identifier (URI) for token `id`
/// is updated to `value`. This event is not used in the base contract.
/// You may need to emit this event depending on your URI logic.
///
/// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
event URI(string value, uint256 indexed id);
/// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`.
uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE =
0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62;
/// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`.
uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE =
0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb;
/// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `ownerSlotSeed` of a given owner is given by.
/// ```
/// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))
/// ```
///
/// The balance slot of `owner` is given by.
/// ```
/// mstore(0x20, ownerSlotSeed)
/// mstore(0x00, id)
/// let balanceSlot := keccak256(0x00, 0x40)
/// ```
///
/// The operator approval slot of `owner` is given by.
/// ```
/// mstore(0x20, ownerSlotSeed)
/// mstore(0x00, operator)
/// let operatorApprovalSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1155 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the URI for token `id`.
///
/// You can either return the same templated URI for all token IDs,
/// (e.g. "https://example.com/api/{id}.json"),
/// or return a unique URI for each `id`.
///
/// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
function uri(uint256 id) public view virtual returns (string memory);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1155 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of `id` owned by `owner`.
function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, owner)
mstore(0x00, id)
result := sload(keccak256(0x00, 0x40))
}
}
/// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
function isApprovedForAll(address owner, address operator)
public
view
virtual
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, owner)
mstore(0x00, operator)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets whether `operator` is approved to manage the tokens of the caller.
///
/// Emits a {ApprovalForAll} event.
function setApprovalForAll(address operator, bool isApproved) public virtual {
/// @solidity memory-safe-assembly
assembly {
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`msg.sender`, `operator`).
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, caller())
mstore(0x00, operator)
sstore(keccak256(0x0c, 0x34), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
// forgefmt: disable-next-line
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
}
}
/// @dev Transfers `amount` of `id` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - If the caller is not `from`,
/// it must be approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) public virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
mstore(0x20, fromSlotSeed)
// Clear the upper 96 bits.
from := shr(96, fromSlotSeed)
to := shr(96, toSlotSeed)
// Revert if `to` is the zero address.
if iszero(to) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// If the caller is not `from`, do the authorization check.
if iszero(eq(caller(), from)) {
mstore(0x00, caller())
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Subtract and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to)
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
// Do the {onERC1155Received} check if `to` is a smart contract.
if extcodesize(to) {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155Received(address,address,uint256,uint256,bytes)`.
mstore(m, 0xf23a6e61)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), from)
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), amount)
mstore(add(m, 0xa0), 0xa0)
mstore(add(m, 0xc0), data.length)
calldatacopy(add(m, 0xe0), data.offset, data.length)
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Transfers `amounts` of `ids` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - `ids` and `amounts` must have the same length.
/// - If the caller is not `from`,
/// it must be approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(ids.length, amounts.length)) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
mstore(0x20, fromSlotSeed)
// Clear the upper 96 bits.
from := shr(96, fromSlotSeed)
to := shr(96, toSlotSeed)
// Revert if `to` is the zero address.
if iszero(to) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// If the caller is not `from`, do the authorization check.
if iszero(eq(caller(), from)) {
mstore(0x00, caller())
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, ids.length) } i {} {
i := sub(i, 0x20)
let amount := calldataload(add(amounts.offset, i))
// Subtract and store the updated balance of `from`.
{
mstore(0x20, fromSlotSeed)
mstore(0x00, calldataload(add(ids.offset, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := shl(5, ids.length)
mstore(add(m, 0x40), ids.length)
calldatacopy(add(m, 0x60), ids.offset, n)
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x60, n))
let o := add(add(m, n), 0x60)
mstore(o, ids.length)
calldatacopy(add(o, 0x20), amounts.offset, n)
// Do the emit.
log4(m, add(add(n, n), 0x80), _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to)
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransferCalldata(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
// Do the {onERC1155BatchReceived} check if `to` is a smart contract.
if extcodesize(to) {
mstore(0x00, to) // Cache `to` to prevent stack too deep.
let m := mload(0x40)
// Prepare the calldata.
// `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
mstore(m, 0xbc197c81)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), from)
// Copy the `ids`.
mstore(add(m, 0x60), 0xa0)
let n := shl(5, ids.length)
mstore(add(m, 0xc0), ids.length)
calldatacopy(add(m, 0xe0), ids.offset, n)
// Copy the `amounts`.
mstore(add(m, 0x80), add(0xc0, n))
let o := add(add(m, n), 0xe0)
mstore(o, ids.length)
calldatacopy(add(o, 0x20), amounts.offset, n)
// Copy the `data`.
mstore(add(m, 0xa0), add(add(0xe0, n), n))
o := add(add(o, n), 0x20)
mstore(o, data.length)
calldatacopy(add(o, 0x20), data.offset, data.length)
let nAll := add(0x104, add(data.length, add(n, n)))
// Revert if the call reverts.
if iszero(call(gas(), mload(0x00), 0, add(mload(0x40), 0x1c), nAll, m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns the amounts of `ids` for `owners.
///
/// Requirements:
/// - `owners` and `ids` must have the same length.
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
public
view
virtual
returns (uint256[] memory balances)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(ids.length, owners.length)) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
balances := mload(0x40)
mstore(balances, ids.length)
let o := add(balances, 0x20)
let i := shl(5, ids.length)
mstore(0x40, add(i, o))
// Loop through all the `ids` and load the balances.
for {} i {} {
i := sub(i, 0x20)
let owner := calldataload(add(owners.offset, i))
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)))
mstore(0x00, calldataload(add(ids.offset, i)))
mstore(add(o, i), sload(keccak256(0x00, 0x40)))
}
}
}
/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
/// See: https://eips.ethereum.org/EIPS/eip-165
/// This function call must use less than 30000 gas.
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let s := shr(224, interfaceId)
// ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c.
result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` of `id` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(address(0), to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, to)
mstore(0x00, id)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(address(0), to, _single(id), _single(amount), data);
}
if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data);
}
/// @dev Mints `amounts` of `ids` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `ids` and `amounts` must have the same length.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function _batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(address(0), to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// Loop through all the `ids` and update the balances.
{
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Increase and store the updated balance of `to`.
{
mstore(0x00, mload(add(ids, i)))
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(address(0), to, ids, amounts, data);
}
if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_burn(address(0), from, id, amount)`.
function _burn(address from, uint256 id, uint256 amount) internal virtual {
_burn(address(0), from, id, amount);
}
/// @dev Destroys `amount` of `id` from `from`.
///
/// Requirements:
/// - `from` must have at least `amount` of `id`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
///
/// Emits a {TransferSingle} event.
function _burn(address by, address from, uint256 id, uint256 amount) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, address(0), _single(id), _single(amount), "");
}
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Decrease and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, address(0), _single(id), _single(amount), "");
}
}
/// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`.
function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
{
_batchBurn(address(0), from, ids, amounts);
}
/// @dev Destroys `amounts` of `ids` from `from`.
///
/// Requirements:
/// - `ids` and `amounts` must have the same length.
/// - `from` must have at least `amounts` of `ids`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
///
/// Emits a {TransferBatch} event.
function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
{
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, address(0), ids, amounts, "");
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let from_ := shl(96, from)
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Decrease and store the updated balance of `from`.
{
mstore(0x00, mload(add(ids, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, address(0), ids, amounts, "");
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL APPROVAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Approve or remove the `operator` as an operator for `by`,
/// without authorization checks.
///
/// Emits a {ApprovalForAll} event.
function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`by`, `operator`).
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, by)
mstore(0x00, operator)
sstore(keccak256(0x0c, 0x34), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
let m := shr(96, not(0))
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`.
function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data)
internal
virtual
{
_safeTransfer(address(0), from, to, id, amount, data);
}
/// @dev Transfers `amount` of `id` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function _safeTransfer(
address by,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Subtract and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
// forgefmt: disable-next-line
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, _single(id), _single(amount), data);
}
if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data);
}
/// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`.
function _safeBatchTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
_safeBatchTransfer(address(0), from, to, ids, amounts, data);
}
/// @dev Transfers `amounts` of `ids` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `ids` and `amounts` must have the same length.
/// - `from` must have at least `amounts` of `ids`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function _safeBatchTransfer(
address by,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let from_ := shl(96, from)
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_)
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_)
mstore(0x20, fromSlotSeed)
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Subtract and store the updated balance of `from`.
{
mstore(0x20, fromSlotSeed)
mstore(0x00, mload(add(ids, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, ids, amounts, data);
}
if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS FOR OVERRIDING */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override this function to return true if `_beforeTokenTransfer` is used.
/// This is to help the compiler avoid producing dead bytecode.
function _useBeforeTokenTransfer() internal view virtual returns (bool) {
return false;
}
/// @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 `id` and `amount` arrays are 1.
function _beforeTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/// @dev Override this function to return true if `_afterTokenTransfer` is used.
/// This is to help the compiler avoid producing dead bytecode.
function _useAfterTokenTransfer() internal view virtual returns (bool) {
return false;
}
/// @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 are 1.
function _afterTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper for calling the `_afterTokenTransfer` hook.
/// This is to help the compiler avoid producing dead bytecode.
function _afterTokenTransferCalldata(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) private {
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, ids, amounts, data);
}
}
/// @dev Returns if `a` has bytecode of non-zero length.
function _hasCode(address a) private view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := extcodesize(a) // Can handle dirty upper bits.
}
}
/// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC1155Received(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155Received(address,address,uint256,uint256,bytes)`.
mstore(m, 0xf23a6e61)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), amount)
mstore(add(m, 0xa0), 0xa0)
let n := mload(data)
mstore(add(m, 0xc0), n)
if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) }
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC1155BatchReceived(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
mstore(m, 0xbc197c81)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
// Copy the `ids`.
mstore(add(m, 0x60), 0xa0)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0xc0)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
let s := add(0xa0, returndatasize())
mstore(add(m, 0x80), s)
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
// Copy the `data`.
mstore(add(m, 0xa0), add(s, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, mload(data))
pop(staticcall(gas(), 4, data, n, o, n))
n := sub(add(o, returndatasize()), add(m, 0x1c))
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns `x` in an array with a single element.
function _single(uint256 x) private pure returns (uint256[] memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(0x40, add(result, 0x40))
mstore(result, 1)
mstore(add(result, 0x20), x)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC2981 NFT Royalty Standard implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol)
abstract contract ERC2981 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The royalty fee numerator exceeds the fee denominator.
error RoyaltyOverflow();
/// @dev The royalty receiver cannot be the zero address.
error RoyaltyReceiverIsZeroAddress();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default royalty info is given by:
/// ```
/// let packed := sload(_ERC2981_MASTER_SLOT_SEED)
/// let receiver := shr(96, packed)
/// let royaltyFraction := xor(packed, shl(96, receiver))
/// ```
///
/// The per token royalty info is given by.
/// ```
/// mstore(0x00, tokenId)
/// mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
/// let packed := sload(keccak256(0x00, 0x40))
/// let receiver := shr(96, packed)
/// let royaltyFraction := xor(packed, shl(96, receiver))
/// ```
uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC2981 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Checks that `_feeDenominator` is non-zero.
constructor() {
require(_feeDenominator() != 0, "Fee denominator cannot be zero.");
}
/// @dev Returns the denominator for the royalty amount.
/// Defaults to 10000, which represents fees in basis points.
/// Override this function to return a custom amount if needed.
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
/// See: https://eips.ethereum.org/EIPS/eip-165
/// This function call must use less than 30000 gas.
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let s := shr(224, interfaceId)
// ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a.
result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a))
}
}
/// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`.
function royaltyInfo(uint256 tokenId, uint256 salePrice)
public
view
virtual
returns (address receiver, uint256 royaltyAmount)
{
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
let packed := sload(keccak256(0x00, 0x40))
receiver := shr(96, packed)
if iszero(receiver) {
packed := sload(mload(0x20))
receiver := shr(96, packed)
}
let x := salePrice
let y := xor(packed, shl(96, receiver)) // `feeNumerator`.
// Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
// Out-of-gas revert. Should not be triggered in practice, but included for safety.
returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y))))
royaltyAmount := div(mul(x, y), feeDenominator)
}
}
/// @dev Sets the default royalty `receiver` and `feeNumerator`.
///
/// Requirements:
/// - `receiver` must not be the zero address.
/// - `feeNumerator` must not be greater than the fee denominator.
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
feeNumerator := shr(160, shl(160, feeNumerator))
if gt(feeNumerator, feeDenominator) {
mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
revert(0x1c, 0x04)
}
let packed := shl(96, receiver)
if iszero(packed) {
mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
revert(0x1c, 0x04)
}
sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator))
}
}
/// @dev Sets the default royalty `receiver` and `feeNumerator` to zero.
function _deleteDefaultRoyalty() internal virtual {
/// @solidity memory-safe-assembly
assembly {
sstore(_ERC2981_MASTER_SLOT_SEED, 0)
}
}
/// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`.
///
/// Requirements:
/// - `receiver` must not be the zero address.
/// - `feeNumerator` must not be greater than the fee denominator.
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
internal
virtual
{
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
feeNumerator := shr(160, shl(160, feeNumerator))
if gt(feeNumerator, feeDenominator) {
mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
revert(0x1c, 0x04)
}
let packed := shl(96, receiver)
if iszero(packed) {
mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
revert(0x1c, 0x04)
}
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
sstore(keccak256(0x00, 0x40), or(packed, feeNumerator))
}
}
/// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero.
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
sstore(keccak256(0x00, 0x40), 0)
}
}
}// 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 Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(StringStorage storage $, uint256 i) internal view returns (uint8) {
return LibBytes.uint8At(bytesStorage($), i);
}
/// @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 an 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 {
/// @solidity memory-safe-assembly
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
pragma solidity ^0.8.4;
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external;
function afterAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransfer(address operator, address token) external;
function afterAuthorizedTransfer(address token) external;
function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction);
}// 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;
/// @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.
}
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
for { let packed := sload($.slot) } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
if iszero(gt(i, 0x1e)) {
result := byte(i, packed)
break
}
if iszero(gt(i, and(0xff, packed))) {
mstore(0x00, $.slot)
let j := sub(i, 0x1f)
result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j))))
}
break
}
if iszero(gt(i, shr(8, packed))) {
mstore(0x00, $.slot)
result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i))))
}
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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, starting from `from`. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
if gt(mload(subject), from) {
let start := add(subject, 0x20)
let end := add(start, mload(subject))
let m := div(not(0), 255) // `0x0101 ... `.
let h := mul(byte(0, needle), m) // Replicating needle mask.
m := not(shl(7, m)) // `0x7f7f ... `.
for { let i := add(start, from) } 1 {} {
let c := xor(mload(i), h) // Load 32-byte chunk and xor with mask.
c := not(or(or(add(and(c, m), m), c), m)) // Each needle byte will be `0x80`.
if c {
c := and(not(shr(shl(3, sub(end, i)), not(0))), c) // Truncate bytes past the end.
if c {
let r := shl(7, lt(0x8421084210842108cc6318c6db6d54be, c)) // Save bytecode.
r := or(shl(6, lt(0xffffffffffffffff, shr(r, c))), r)
// forgefmt: disable-next-item
result := add(sub(i, start), shr(3, xor(byte(and(0x1f, shr(byte(24,
mul(0x02040810204081, shr(r, c))), 0x8421084210842108cc6318c6db6d54be)),
0xc0c8c8d0c8e8d0d8c8e8e0e8d0d8e0f0c8d0e8d0e0e0d8f0d0d0e0d8f8f8f8f8), r)))
break
}
}
i := add(i, 0x20)
if iszero(lt(i, end)) { break }
}
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle)
internal
pure
returns (uint256 result)
{
return indexOfByte(subject, needle, 0);
}
/// @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 an 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 {
/// @solidity memory-safe-assembly
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 {
/// @solidity memory-safe-assembly
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.
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.
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 a slice representing a static struct in the calldata. Performs bounds checks.
function staticStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
result.offset := add(a.offset, offset)
result.length := sub(a.length, offset)
if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
function dynamicStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(a.offset, s)
result.length := sub(a.length, s)
if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns bytes in calldata. Performs bounds checks.
function bytesInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(add(a.offset, s), 0x20)
result.length := calldataload(add(a.offset, s))
// forgefmt: disable-next-item
if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
}
}
/// @dev Checks if `x` is in `a`. Assumes `a` has been checked.
function checkInCalldata(bytes calldata x, bytes calldata a) internal pure {
/// @solidity memory-safe-assembly
assembly {
if or(
or(lt(x.offset, a.offset), gt(add(x.offset, x.length), add(a.length, a.offset))),
shr(64, or(x.length, x.offset))
) { revert(0x00, 0x00) }
}
}
/// @dev Checks if `x` is in `a`. Assumes `a` has been checked.
function checkInCalldata(bytes[] calldata x, bytes calldata a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let e := sub(add(a.length, a.offset), 0x20)
if or(lt(x.offset, a.offset), shr(64, x.offset)) { revert(0x00, 0x00) }
for { let i := 0 } iszero(eq(x.length, i)) { i := add(i, 1) } {
let o := calldataload(add(x.offset, shl(5, i)))
let t := add(o, x.offset)
let l := calldataload(t)
if or(shr(64, or(l, o)), gt(add(t, l), e)) { revert(0x00, 0x00) }
}
}
}
/// @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
}
}
/// @dev Returns the most significant 20 bytes as an address.
function msbToAddress(bytes32 x) internal pure returns (address) {
return address(bytes20(x));
}
/// @dev Returns the least significant 20 bytes as an address.
function lsbToAddress(bytes32 x) internal pure returns (address) {
return address(uint160(uint256(x)));
}
}{
"remappings": [
"solady/=lib/solady/src/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"transferValidator","type":"address"},{"internalType":"address","name":"royaltyRecipient","type":"address"},{"internalType":"string","name":"_baseURI","type":"string"},{"internalType":"address","name":"_santaCurtis","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"ArrayLengthZero","type":"error"},{"inputs":[],"name":"ArrayLengthsMismatch","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenNotEnabled","type":"error"},{"inputs":[],"name":"TransferToNonERC1155ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"TransferValidatorNotSet","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","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":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","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":"amounts","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":"amount","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":"ADMIN_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"},{"internalType":"uint256[][]","name":"tokenIds","type":"uint256[][]"},{"internalType":"uint256[][]","name":"amounts","type":"uint256[][]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isEnabled","outputs":[{"internalType":"bool","name":"isEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"tokenId","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","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":[],"name":"santaCurtis","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"tokenIds","type":"uint64[]"},{"internalType":"bool[]","name":"_isEnabled","type":"bool[]"}],"name":"setEnabledBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_santaCurtis","type":"address"}],"name":"setSantaCurtis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"supply","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"}]Contract Creation Code
608060405234801561000f575f5ffd5b5060405161429938038061429983398181016040528101906100319190610563565b5f6100406101fe60201b60201c565b6bffffffffffffffffffffffff160361008e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100859061063d565b60405180910390fd5b61009d3261020760201b60201c565b6100b632682000000000000000006102e360201b60201c565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361011b576040517fd5de14f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f9081610129919061086b565b5061013c836101f46102f960201b60201c565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac5f856040516101ed929190610949565b60405180910390a150505050610970565b5f612710905090565b61021561036060201b60201c565b1561028d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392780541561024f57630dc149f05f526004601cfd5b8160601b60601c9150811560ff1b82178155815f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa3506102e0565b8060601b60601c9050807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392755805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa35b50565b6102f58282600161036460201b60201c565b5050565b5f6103086101fe60201b60201c565b6bffffffffffffffffffffffff1690508160a01b60a01c9150808211156103365763350a88b35f526004601cfd5b8260601b8061034c5763b4457eaa5f526004601cfd5b82811768aa4ec00224afccfdb75550505050565b5f90565b638b78c6d8600c52825f526020600c2080548381178361038657848216821890505b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103f6826103cd565b9050919050565b610406816103ec565b8114610410575f5ffd5b50565b5f81519050610421816103fd565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6104758261042f565b810181811067ffffffffffffffff821117156104945761049361043f565b5b80604052505050565b5f6104a66103bc565b90506104b2828261046c565b919050565b5f67ffffffffffffffff8211156104d1576104d061043f565b5b6104da8261042f565b9050602081019050919050565b8281835e5f83830152505050565b5f610507610502846104b7565b61049d565b9050828152602081018484840111156105235761052261042b565b5b61052e8482856104e7565b509392505050565b5f82601f83011261054a57610549610427565b5b815161055a8482602086016104f5565b91505092915050565b5f5f5f5f6080858703121561057b5761057a6103c5565b5b5f61058887828801610413565b945050602061059987828801610413565b935050604085015167ffffffffffffffff8111156105ba576105b96103c9565b5b6105c687828801610536565b92505060606105d787828801610413565b91505092959194509250565b5f82825260208201905092915050565b7f4665652064656e6f6d696e61746f722063616e6e6f74206265207a65726f2e005f82015250565b5f610627601f836105e3565b9150610632826105f3565b602082019050919050565b5f6020820190508181035f8301526106548161061b565b9050919050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806106a957607f821691505b6020821081036106bc576106bb610665565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f6008830261071e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826106e3565b61072886836106e3565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f61076c61076761076284610740565b610749565b610740565b9050919050565b5f819050919050565b61078583610752565b61079961079182610773565b8484546106ef565b825550505050565b5f5f905090565b6107b06107a1565b6107bb81848461077c565b505050565b5b818110156107de576107d35f826107a8565b6001810190506107c1565b5050565b601f821115610823576107f4816106c2565b6107fd846106d4565b8101602085101561080c578190505b610820610818856106d4565b8301826107c0565b50505b505050565b5f82821c905092915050565b5f6108435f1984600802610828565b1980831691505092915050565b5f61085b8383610834565b9150826002028217905092915050565b6108748261065b565b67ffffffffffffffff81111561088d5761088c61043f565b5b6108978254610692565b6108a28282856107e2565b5f60209050601f8311600181146108d3575f84156108c1578287015190505b6108cb8582610850565b865550610932565b601f1984166108e1866106c2565b5f5b82811015610908578489015182556001820191506020850194506020810190506108e3565b868310156109255784890151610921601f891682610834565b8355505b6001600288020188555050505b505050505050565b610943816103ec565b82525050565b5f60408201905061095c5f83018561093a565b610969602083018461093a565b9392505050565b61391c8061097d5f395ff3fe608060405260043610610244575f3560e01c80636c0360eb11610138578063a9fc664e116100b5578063d539139311610079578063d539139314610830578063e985e9c51461085a578063f04e283e14610896578063f242432a146108b2578063f2fde38b146108da578063fee81cf4146108f657610244565b8063a9fc664e1461072c578063bd85b03914610754578063c376a0a514610790578063c783034c146107b8578063c87b56dd146107f457610244565b806387ff33a9116100fc57806387ff33a9146106605780638da5cb5b1461068857806395d89b41146106b257806396377e29146106dc578063a22cb4651461070457610244565b80636c0360eb146105b05780636ecf0ee1146105da578063715018a61461060457806372d056fd1461060e57806375b238fc1461063657610244565b80631cd64df4116101c65780634a4ee7b11161018a5780634a4ee7b1146104ea5780634e1273f414610506578063514e62fc1461054257806354d1f13d1461057e57806355f804b31461058857610244565b80631cd64df414610403578063256929621461043f5780632a55205a146104495780632de94807146104865780632eb2c2d6146104c257610244565b80630ca834801161020d5780630ca834801461033c5780630d705df6146103645780630e89341c1461038f578063183a4f6e146103cb5780631c10893f146103e757610244565b8062fdd58e1461024857806301ffc9a71461028457806302fa7c47146102c057806306fdde03146102e8578063098144d414610312575b5f5ffd5b348015610253575f5ffd5b5061026e6004803603810190610269919061274c565b610932565b60405161027b9190612799565b60405180910390f35b34801561028f575f5ffd5b506102aa60048036038101906102a59190612807565b610953565b6040516102b7919061284c565b60405180910390f35b3480156102cb575f5ffd5b506102e660048036038101906102e191906128a6565b6109ec565b005b3480156102f3575f5ffd5b506102fc610a0b565b6040516103099190612954565b60405180910390f35b34801561031d575f5ffd5b50610326610a48565b6040516103339190612983565b60405180910390f35b348015610347575f5ffd5b50610362600480360381019061035d91906129fd565b610a70565b005b34801561036f575f5ffd5b50610378610c69565b604051610386929190612a9d565b60405180910390f35b34801561039a575f5ffd5b506103b560048036038101906103b09190612ac4565b610c95565b6040516103c29190612954565b60405180910390f35b6103e560048036038101906103e09190612ac4565b610d40565b005b61040160048036038101906103fc919061274c565b610d4d565b005b34801561040e575f5ffd5b506104296004803603810190610424919061274c565b610d63565b604051610436919061284c565b60405180910390f35b610447610d79565b005b348015610454575f5ffd5b5061046f600480360381019061046a9190612aef565b610dca565b60405161047d929190612b2d565b60405180910390f35b348015610491575f5ffd5b506104ac60048036038101906104a79190612b54565b610e36565b6040516104b99190612799565b60405180910390f35b3480156104cd575f5ffd5b506104e860048036038101906104e39190612bd4565b610e4f565b005b61050460048036038101906104ff919061274c565b611155565b005b348015610511575f5ffd5b5061052c60048036038101906105279190612d00565b61116b565b6040516105399190612e35565b60405180910390f35b34801561054d575f5ffd5b506105686004803603810190610563919061274c565b6111d8565b604051610575919061284c565b60405180910390f35b6105866111ef565b005b348015610593575f5ffd5b506105ae60048036038101906105a99190612f7d565b611228565b005b3480156105bb575f5ffd5b506105c46112a4565b6040516105d19190612954565b60405180910390f35b3480156105e5575f5ffd5b506105ee61132f565b6040516105fb9190612983565b60405180910390f35b61060c611354565b005b348015610619575f5ffd5b50610634600480360381019061062f9190613001565b611367565b005b348015610641575f5ffd5b5061064a611497565b6040516106579190612799565b60405180910390f35b34801561066b575f5ffd5b5061068660048036038101906106819190612b54565b6114a1565b005b348015610693575f5ffd5b5061069c6114f5565b6040516106a99190612983565b60405180910390f35b3480156106bd575f5ffd5b506106c661151d565b6040516106d39190612954565b60405180910390f35b3480156106e7575f5ffd5b5061070260048036038101906106fd9190613094565b61155a565b005b34801561070f575f5ffd5b5061072a6004803603810190610725919061316e565b611778565b005b348015610737575f5ffd5b50610752600480360381019061074d9190612b54565b6117cb565b005b34801561075f575f5ffd5b5061077a60048036038101906107759190612ac4565b61187e565b6040516107879190612799565b60405180910390f35b34801561079b575f5ffd5b506107b660048036038101906107b19190613256565b611893565b005b3480156107c3575f5ffd5b506107de60048036038101906107d99190612ac4565b611987565b6040516107eb919061284c565b60405180910390f35b3480156107ff575f5ffd5b5061081a60048036038101906108159190612ac4565b6119a4565b6040516108279190612954565b60405180910390f35b34801561083b575f5ffd5b50610844611a4f565b6040516108519190612799565b60405180910390f35b348015610865575f5ffd5b50610880600480360381019061087b91906132d4565b611a5c565b60405161088d919061284c565b60405180910390f35b6108b060048036038101906108ab9190612b54565b611a7e565b005b3480156108bd575f5ffd5b506108d860048036038101906108d39190613312565b611abc565b005b6108f460048036038101906108ef9190612b54565b611cf7565b005b348015610901575f5ffd5b5061091c60048036038101906109179190612b54565b611d20565b6040516109299190612799565b60405180910390f35b5f679a31110384e0b0c960205282601452815f5260405f2054905092915050565b5f61095d82611d39565b8061096d575061096c82611d5d565b5b806109d557507fad0d7f6c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109e557506109e482611d5d565b5b9050919050565b650400000000006109fc81611d79565b610a068383611dae565b505050565b60606040518060400160405280600a81526020017f42415943204665656c7300000000000000000000000000000000000000000000815250905090565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b68200000000000000000610a8381611e0f565b5f8585905003610abf576040517fe806f59d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b85859050811015610bc65760035f878784818110610ae557610ae46133a8565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff16610b6057858582818110610b1d57610b1c6133a8565b5b905060200201356040517faac7aeed000000000000000000000000000000000000000000000000000000008152600401610b579190612799565b60405180910390fd5b838382818110610b7357610b726133a8565b5b9050602002013560025f888885818110610b9057610b8f6133a8565b5b9050602002013581526020019081526020015f205f828254610bb29190613402565b925050819055508080600101915050610ac4565b50610c61868686808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508585808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505060405180602001604052805f815250611e36565b505050505050565b5f5f7f1854b24168de2a3561e8caaa0770d8257ca046fb64fc845e3cd163acfc66770c91505f90509091565b6060610d39610ca383611f81565b5f8054610caf90613462565b80601f0160208091040260200160405190810160405280929190818152602001828054610cdb90613462565b8015610d265780601f10610cfd57610100808354040283529160200191610d26565b820191905f5260205f20905b815481529060010190602001808311610d0957829003601f168201915b5050505050611fd090919063ffffffff16565b9050919050565b610d4a3382611fe4565b50565b610d55611ff3565b610d5f828261202a565b5050565b5f8182610d6f85610e36565b1614905092915050565b5f610d8261203a565b67ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f5f5f610dd5612044565b6bffffffffffffffffffffffff169050845f5268aa4ec00224afccfdb760205260405f20548060601c935083610e12576020515490508060601c93505b848460601b8218805f1904821181023d3d3e83818302049450505050509250929050565b5f638b78c6d8600c52815f526020600c20549050919050565b610e5761204d565b15610f2d57610f2c88888888808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508787808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612055565b5b828514610f4157633b800a465f526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c985088610f7f5763ea553b345f526004601cfd5b893314610fa157335f526034600c2054610fa057634b6e7f185f526004601cfd5b5b8660051b5b8015611010576020810390508087013583602052818a01355f5260405f20805480831115610fdb5763f4d678b85f526004601cfd5b828103825550508260205260405f20805482810181811015611004576301336cea5f526004601cfd5b80835550505050610fa6565b50604051604081528760051b886040830152808a6060840137806060016020830152606081830101898152818960208301378b8d337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60808687010187a4505050505061107b6121a9565b156110915761109088888888888888886121b0565b5b863b1561114b57865f5260405163bc197c81815233602082015288604082015260a060608201528560051b8660c0830152808860e08401378060c001608083015260e08183010187815281876020830137818260e0010160a084015260208282010190508381528385602083013781820184016101040160208482601c604051015f5f515af161112a573d15611129573d5f853e3d84fd5b5b63bc197c8160e01b84511461114657639c05499b5f526004601cfd5b505050505b5050505050505050565b61115d611ff3565b6111678282611fe4565b5050565b606083821461118157633b800a465f526004601cfd5b6040519050818152602081018260051b8181016040525b80156111ce57602081039050808701358060601b679a31110384e0b0c917602052818601355f5260405f20548284015250611198565b5050949350505050565b5f5f826111e485610e36565b161415905092915050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b6504000000000061123881611d79565b815f90816112469190613632565b507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60405161129892919061373a565b60405180910390a15050565b5f80546112b090613462565b80601f01602080910402602001604051908101604052809291908181526020018280546112dc90613462565b80156113275780601f106112fe57610100808354040283529160200191611327565b820191905f5260205f20905b81548152906001019060200180831161130a57829003601f168201915b505050505081565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61135c611ff3565b6113655f612298565b565b6820000000000000000061137a81611e0f565b5f82036113b3576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60035f8467ffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1661141c57826040517faac7aeed0000000000000000000000000000000000000000000000000000000081526004016114139190613791565b60405180910390fd5b8160025f8567ffffffffffffffff1681526020019081526020015f205f8282546114469190613402565b9250508190555061149260015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168467ffffffffffffffff168460405180602001604052805f81525061235e565b505050565b6504000000000081565b650400000000006114b181611d79565b8160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754905090565b60606040518060400160405280600981526020017f424159434645454c530000000000000000000000000000000000000000000000815250905090565b6820000000000000000061156d81611e0f565b84849050878790501415806115885750828290508787905014155b156115bf576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b8787905081101561176e578383828181106115e2576115e16133a8565b5b90506020028101906115f491906137b6565b9050868683818110611609576116086133a8565b5b905060200281019061161b91906137b6565b905014611654576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186869050036116e6576116e1868683818110611675576116746133a8565b5b905060200281019061168791906137b6565b5f818110611698576116976133a8565b5b905060200201358585848181106116b2576116b16133a8565b5b90506020028101906116c491906137b6565b5f8181106116d5576116d46133a8565b5b90506020020135611367565b611761565b6117608888838181106116fc576116fb6133a8565b5b90506020020160208101906117119190612b54565b878784818110611724576117236133a8565b5b905060200281019061173691906137b6565b878786818110611749576117486133a8565b5b905060200281019061175b91906137b6565b610a70565b5b80806001019150506115c4565b5050505050505050565b8015159050679a31110384e0b0c960205233601452815f52806034600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b650400000000006117db81611d79565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508260045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac8184604051611871929190613818565b60405180910390a1505050565b6002602052805f5260405f205f915090505481565b650400000000006118a381611d79565b8282905085859050146118e2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b8585905081101561197f57838382818110611905576119046133a8565b5b905060200201602081019061191a919061383f565b60035f8888858181106119305761192f6133a8565b5b9050602002016020810190611945919061386a565b67ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555080806001019150506118e7565b505050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6060611a486119b283611f81565b5f80546119be90613462565b80601f01602080910402602001604051908101604052809291908181526020018280546119ea90613462565b8015611a355780601f10611a0c57610100808354040283529160200191611a35565b820191905f5260205f20905b815481529060010190602001808311611a1857829003601f168201915b5050505050611fd090919063ffffffff16565b9050919050565b6820000000000000000081565b5f679a31110384e0b0c960205282601452815f526034600c2054905092915050565b611a86611ff3565b63389a75e1600c52805f526020600c208054421115611aac57636f5e88185f526004601cfd5b5f815550611ab981612298565b50565b611ac461204d565b15611b2a57611b298686611ad787612453565b611ae087612453565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612055565b5b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c965086611b685763ea553b345f526004601cfd5b873314611b8a57335f526034600c2054611b8957634b6e7f185f526004601cfd5b5b855f5260405f20805480871115611ba85763f4d678b85f526004601cfd5b868103825550508060205260405f20805486810181811015611bd1576301336cea5f526004601cfd5b808355505050846020528688337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa45050611c0d6121a9565b15611c7357611c728686611c2087612453565b611c2987612453565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612470565b5b843b15611cef5760405163f23a6e61815233602082015286604082015284606082015283608082015260a0808201528160c0820152818360e08301376020818360c401601c84015f8a5af1611cd1573d15611cd0573d5f823e3d81fd5b5b63f23a6e6160e01b815114611ced57639c05499b5f526004601cfd5b505b505050505050565b611cff611ff3565b8060601b611d1457637448fbae5f526004601cfd5b611d1d81612298565b50565b5f63389a75e1600c52815f526020600c20549050919050565b5f8160e01c630e89341c811463d9b67a2682146301ffc9a783141717915050919050565b5f8160e01c632a55205a81146301ffc9a7821417915050919050565b638b78c6d8600c52335f52806020600c205416611dab57638b78c6d819543314611daa576382b429005f526004601cfd5b5b50565b5f611db7612044565b6bffffffffffffffffffffffff1690508160a01b60a01c915080821115611de55763350a88b35f526004601cfd5b8260601b80611dfb5763b4457eaa5f526004601cfd5b82811768aa4ec00224afccfdb75550505050565b638b78c6d8600c52335f52806020600c205416611e33576382b429005f526004601cfd5b50565b611e3e61204d565b15611e5157611e505f85858585612055565b5b8151835114611e6757633b800a465f526004601cfd5b8360601b80611e7d5763ea553b345f526004601cfd5b80679a31110384e0b0c917602052835160051b5b8015611ed15780840151818601515f5260405f20805482810181811015611ebf576301336cea5f526004601cfd5b80835550505050602081039050611e91565b5060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d82010391508360601c5f337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8587a450505050611f4c6121a9565b15611f5f57611f5e5f85858585612470565b5b611f6884612477565b15611f7b57611f7a5f85858585612481565b5b50505050565b60606080604051019050602081016040525f8152805f19835b600115611fbb578184019350600a81066030018453600a8104905080611f9a575b50828203602084039350808452505050919050565b6060611fdc8383612548565b905092915050565b611fef82825f6125bf565b5050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314612028576382b429005f526004601cfd5b565b612036828260016125bf565b5050565b5f6202a300905090565b5f612710905090565b5f6001905090565b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141580156120bd57505f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b156121a2575f5f90505b83518110156121a05760045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631854b241338888888681518110612123576121226133a8565b5b602002602001015188878151811061213e5761213d6133a8565b5b60200260200101516040518663ffffffff1660e01b8152600401612166959493929190613895565b5f604051808303815f87803b15801561217d575f5ffd5b505af115801561218f573d5f5f3e3d5ffd5b5050505080806001019150506120c7565b505b5050505050565b5f5f905090565b6121b86121a9565b1561228e5761228d88888888808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508787808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612470565b5b5050505050505050565b6122a0612617565b15612305577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa3811560ff1b821781555061235b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa3818155505b50565b61236661204d565b15612389576123885f8561237986612453565b61238286612453565b85612055565b5b8360601b8061239f5763ea553b345f526004601cfd5b679a31110384e0b0c960205284601452835f5260405f208054848101818110156123d0576301336cea5f526004601cfd5b808355505050826020528060601c5f337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa45061240e6121a9565b15612431576124305f8561242186612453565b61242a86612453565b85612470565b5b61243a84612477565b1561244d5761244c5f8585858561261b565b5b50505050565b606060405190506040810160405260018152816020820152919050565b5050505050565b5f813b9050919050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d810160a08501523d82019150845160200192508282848760045afa50601c84013d830103925060208484601c87015f8c5af1612521573d15612520573d5f853e3d84fd5b5b63bc197c8160e01b84511461253d57639c05499b5f526004601cfd5b505050505050505050565b60606040519050601f1983518160208201165b60011561257557808601518185015282810190508061255b575b5083518184018360208301165b60011561259c578087015181830152848101905080612582575b508183018060208701015f81528187526020810160405250505050505092915050565b638b78c6d8600c52825f526020600c208054838117836125e157848216821890505b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f90565b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c08301528015612667578060e08301826020860160045afa505b6020828260c401601c85015f8a5af1612689573d15612688573d5f833e3d82fd5b5b63f23a6e6160e01b8251146126a557639c05499b5f526004601cfd5b50505050505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6126e8826126bf565b9050919050565b6126f8816126de565b8114612702575f5ffd5b50565b5f81359050612713816126ef565b92915050565b5f819050919050565b61272b81612719565b8114612735575f5ffd5b50565b5f8135905061274681612722565b92915050565b5f5f60408385031215612762576127616126b7565b5b5f61276f85828601612705565b925050602061278085828601612738565b9150509250929050565b61279381612719565b82525050565b5f6020820190506127ac5f83018461278a565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6127e6816127b2565b81146127f0575f5ffd5b50565b5f81359050612801816127dd565b92915050565b5f6020828403121561281c5761281b6126b7565b5b5f612829848285016127f3565b91505092915050565b5f8115159050919050565b61284681612832565b82525050565b5f60208201905061285f5f83018461283d565b92915050565b5f6bffffffffffffffffffffffff82169050919050565b61288581612865565b811461288f575f5ffd5b50565b5f813590506128a08161287c565b92915050565b5f5f604083850312156128bc576128bb6126b7565b5b5f6128c985828601612705565b92505060206128da85828601612892565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f612926826128e4565b61293081856128ee565b93506129408185602086016128fe565b6129498161290c565b840191505092915050565b5f6020820190508181035f83015261296c818461291c565b905092915050565b61297d816126de565b82525050565b5f6020820190506129965f830184612974565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126129bd576129bc61299c565b5b8235905067ffffffffffffffff8111156129da576129d96129a0565b5b6020830191508360208202830111156129f6576129f56129a4565b5b9250929050565b5f5f5f5f5f60608688031215612a1657612a156126b7565b5b5f612a2388828901612705565b955050602086013567ffffffffffffffff811115612a4457612a436126bb565b5b612a50888289016129a8565b9450945050604086013567ffffffffffffffff811115612a7357612a726126bb565b5b612a7f888289016129a8565b92509250509295509295909350565b612a97816127b2565b82525050565b5f604082019050612ab05f830185612a8e565b612abd602083018461283d565b9392505050565b5f60208284031215612ad957612ad86126b7565b5b5f612ae684828501612738565b91505092915050565b5f5f60408385031215612b0557612b046126b7565b5b5f612b1285828601612738565b9250506020612b2385828601612738565b9150509250929050565b5f604082019050612b405f830185612974565b612b4d602083018461278a565b9392505050565b5f60208284031215612b6957612b686126b7565b5b5f612b7684828501612705565b91505092915050565b5f5f83601f840112612b9457612b9361299c565b5b8235905067ffffffffffffffff811115612bb157612bb06129a0565b5b602083019150836001820283011115612bcd57612bcc6129a4565b5b9250929050565b5f5f5f5f5f5f5f5f60a0898b031215612bf057612bef6126b7565b5b5f612bfd8b828c01612705565b9850506020612c0e8b828c01612705565b975050604089013567ffffffffffffffff811115612c2f57612c2e6126bb565b5b612c3b8b828c016129a8565b9650965050606089013567ffffffffffffffff811115612c5e57612c5d6126bb565b5b612c6a8b828c016129a8565b9450945050608089013567ffffffffffffffff811115612c8d57612c8c6126bb565b5b612c998b828c01612b7f565b92509250509295985092959890939650565b5f5f83601f840112612cc057612cbf61299c565b5b8235905067ffffffffffffffff811115612cdd57612cdc6129a0565b5b602083019150836020820283011115612cf957612cf86129a4565b5b9250929050565b5f5f5f5f60408587031215612d1857612d176126b7565b5b5f85013567ffffffffffffffff811115612d3557612d346126bb565b5b612d4187828801612cab565b9450945050602085013567ffffffffffffffff811115612d6457612d636126bb565b5b612d70878288016129a8565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b612db081612719565b82525050565b5f612dc18383612da7565b60208301905092915050565b5f602082019050919050565b5f612de382612d7e565b612ded8185612d88565b9350612df883612d98565b805f5b83811015612e28578151612e0f8882612db6565b9750612e1a83612dcd565b925050600181019050612dfb565b5085935050505092915050565b5f6020820190508181035f830152612e4d8184612dd9565b905092915050565b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612e8f8261290c565b810181811067ffffffffffffffff82111715612eae57612ead612e59565b5b80604052505050565b5f612ec06126ae565b9050612ecc8282612e86565b919050565b5f67ffffffffffffffff821115612eeb57612eea612e59565b5b612ef48261290c565b9050602081019050919050565b828183375f83830152505050565b5f612f21612f1c84612ed1565b612eb7565b905082815260208101848484011115612f3d57612f3c612e55565b5b612f48848285612f01565b509392505050565b5f82601f830112612f6457612f6361299c565b5b8135612f74848260208601612f0f565b91505092915050565b5f60208284031215612f9257612f916126b7565b5b5f82013567ffffffffffffffff811115612faf57612fae6126bb565b5b612fbb84828501612f50565b91505092915050565b5f67ffffffffffffffff82169050919050565b612fe081612fc4565b8114612fea575f5ffd5b50565b5f81359050612ffb81612fd7565b92915050565b5f5f60408385031215613017576130166126b7565b5b5f61302485828601612fed565b925050602061303585828601612738565b9150509250929050565b5f5f83601f8401126130545761305361299c565b5b8235905067ffffffffffffffff811115613071576130706129a0565b5b60208301915083602082028301111561308d5761308c6129a4565b5b9250929050565b5f5f5f5f5f5f606087890312156130ae576130ad6126b7565b5b5f87013567ffffffffffffffff8111156130cb576130ca6126bb565b5b6130d789828a01612cab565b9650965050602087013567ffffffffffffffff8111156130fa576130f96126bb565b5b61310689828a0161303f565b9450945050604087013567ffffffffffffffff811115613129576131286126bb565b5b61313589828a0161303f565b92509250509295509295509295565b61314d81612832565b8114613157575f5ffd5b50565b5f8135905061316881613144565b92915050565b5f5f60408385031215613184576131836126b7565b5b5f61319185828601612705565b92505060206131a28582860161315a565b9150509250929050565b5f5f83601f8401126131c1576131c061299c565b5b8235905067ffffffffffffffff8111156131de576131dd6129a0565b5b6020830191508360208202830111156131fa576131f96129a4565b5b9250929050565b5f5f83601f8401126132165761321561299c565b5b8235905067ffffffffffffffff811115613233576132326129a0565b5b60208301915083602082028301111561324f5761324e6129a4565b5b9250929050565b5f5f5f5f6040858703121561326e5761326d6126b7565b5b5f85013567ffffffffffffffff81111561328b5761328a6126bb565b5b613297878288016131ac565b9450945050602085013567ffffffffffffffff8111156132ba576132b96126bb565b5b6132c687828801613201565b925092505092959194509250565b5f5f604083850312156132ea576132e96126b7565b5b5f6132f785828601612705565b925050602061330885828601612705565b9150509250929050565b5f5f5f5f5f5f60a0878903121561332c5761332b6126b7565b5b5f61333989828a01612705565b965050602061334a89828a01612705565b955050604061335b89828a01612738565b945050606061336c89828a01612738565b935050608087013567ffffffffffffffff81111561338d5761338c6126bb565b5b61339989828a01612b7f565b92509250509295509295509295565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61340c82612719565b915061341783612719565b925082820190508082111561342f5761342e6133d5565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061347957607f821691505b60208210810361348c5761348b613435565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026134ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826134b3565b6134f886836134b3565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61353361352e61352984612719565b613510565b612719565b9050919050565b5f819050919050565b61354c83613519565b6135606135588261353a565b8484546134bf565b825550505050565b5f5f905090565b613577613568565b613582818484613543565b505050565b5b818110156135a55761359a5f8261356f565b600181019050613588565b5050565b601f8211156135ea576135bb81613492565b6135c4846134a4565b810160208510156135d3578190505b6135e76135df856134a4565b830182613587565b50505b505050565b5f82821c905092915050565b5f61360a5f19846008026135ef565b1980831691505092915050565b5f61362283836135fb565b9150826002028217905092915050565b61363b826128e4565b67ffffffffffffffff81111561365457613653612e59565b5b61365e8254613462565b6136698282856135a9565b5f60209050601f83116001811461369a575f8415613688578287015190505b6136928582613617565b8655506136f9565b601f1984166136a886613492565b5f5b828110156136cf578489015182556001820191506020850194506020810190506136aa565b868310156136ec57848901516136e8601f8916826135fb565b8355505b6001600288020188555050505b505050505050565b5f819050919050565b5f61372461371f61371a84613701565b613510565b612719565b9050919050565b6137348161370a565b82525050565b5f60408201905061374d5f83018561372b565b61375a602083018461278a565b9392505050565b5f61377b61377661377184612fc4565b613510565b612719565b9050919050565b61378b81613761565b82525050565b5f6020820190506137a45f830184613782565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126137d2576137d16137aa565b5b80840192508235915067ffffffffffffffff8211156137f4576137f36137ae565b5b6020830192506020820236038313156138105761380f6137b2565b5b509250929050565b5f60408201905061382b5f830185612974565b6138386020830184612974565b9392505050565b5f60208284031215613854576138536126b7565b5b5f6138618482850161315a565b91505092915050565b5f6020828403121561387f5761387e6126b7565b5b5f61388c84828501612fed565b91505092915050565b5f60a0820190506138a85f830188612974565b6138b56020830187612974565b6138c26040830186612974565b6138cf606083018561278a565b6138dc608083018461278a565b969550505050505056fea26469706673582212202857b8cef0ba7104a8a3a9b72d981e7ea2a6a93333c8853f199523e30040733b64736f6c634300081c0033000000000000000000000000721c008fdff27bf06e7e123956e2fe03b63342e300000000000000000000000006dd843b78e6cc34744473176d8a61743eefaa9a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000a66e65b4ed40aced74d28775abe4ee6537cd7a40000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656965336332653736733469727a767935736d707176616d6b78636273626a6b616f68637878656b62653366367237647834777079792f0000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405260043610610244575f3560e01c80636c0360eb11610138578063a9fc664e116100b5578063d539139311610079578063d539139314610830578063e985e9c51461085a578063f04e283e14610896578063f242432a146108b2578063f2fde38b146108da578063fee81cf4146108f657610244565b8063a9fc664e1461072c578063bd85b03914610754578063c376a0a514610790578063c783034c146107b8578063c87b56dd146107f457610244565b806387ff33a9116100fc57806387ff33a9146106605780638da5cb5b1461068857806395d89b41146106b257806396377e29146106dc578063a22cb4651461070457610244565b80636c0360eb146105b05780636ecf0ee1146105da578063715018a61461060457806372d056fd1461060e57806375b238fc1461063657610244565b80631cd64df4116101c65780634a4ee7b11161018a5780634a4ee7b1146104ea5780634e1273f414610506578063514e62fc1461054257806354d1f13d1461057e57806355f804b31461058857610244565b80631cd64df414610403578063256929621461043f5780632a55205a146104495780632de94807146104865780632eb2c2d6146104c257610244565b80630ca834801161020d5780630ca834801461033c5780630d705df6146103645780630e89341c1461038f578063183a4f6e146103cb5780631c10893f146103e757610244565b8062fdd58e1461024857806301ffc9a71461028457806302fa7c47146102c057806306fdde03146102e8578063098144d414610312575b5f5ffd5b348015610253575f5ffd5b5061026e6004803603810190610269919061274c565b610932565b60405161027b9190612799565b60405180910390f35b34801561028f575f5ffd5b506102aa60048036038101906102a59190612807565b610953565b6040516102b7919061284c565b60405180910390f35b3480156102cb575f5ffd5b506102e660048036038101906102e191906128a6565b6109ec565b005b3480156102f3575f5ffd5b506102fc610a0b565b6040516103099190612954565b60405180910390f35b34801561031d575f5ffd5b50610326610a48565b6040516103339190612983565b60405180910390f35b348015610347575f5ffd5b50610362600480360381019061035d91906129fd565b610a70565b005b34801561036f575f5ffd5b50610378610c69565b604051610386929190612a9d565b60405180910390f35b34801561039a575f5ffd5b506103b560048036038101906103b09190612ac4565b610c95565b6040516103c29190612954565b60405180910390f35b6103e560048036038101906103e09190612ac4565b610d40565b005b61040160048036038101906103fc919061274c565b610d4d565b005b34801561040e575f5ffd5b506104296004803603810190610424919061274c565b610d63565b604051610436919061284c565b60405180910390f35b610447610d79565b005b348015610454575f5ffd5b5061046f600480360381019061046a9190612aef565b610dca565b60405161047d929190612b2d565b60405180910390f35b348015610491575f5ffd5b506104ac60048036038101906104a79190612b54565b610e36565b6040516104b99190612799565b60405180910390f35b3480156104cd575f5ffd5b506104e860048036038101906104e39190612bd4565b610e4f565b005b61050460048036038101906104ff919061274c565b611155565b005b348015610511575f5ffd5b5061052c60048036038101906105279190612d00565b61116b565b6040516105399190612e35565b60405180910390f35b34801561054d575f5ffd5b506105686004803603810190610563919061274c565b6111d8565b604051610575919061284c565b60405180910390f35b6105866111ef565b005b348015610593575f5ffd5b506105ae60048036038101906105a99190612f7d565b611228565b005b3480156105bb575f5ffd5b506105c46112a4565b6040516105d19190612954565b60405180910390f35b3480156105e5575f5ffd5b506105ee61132f565b6040516105fb9190612983565b60405180910390f35b61060c611354565b005b348015610619575f5ffd5b50610634600480360381019061062f9190613001565b611367565b005b348015610641575f5ffd5b5061064a611497565b6040516106579190612799565b60405180910390f35b34801561066b575f5ffd5b5061068660048036038101906106819190612b54565b6114a1565b005b348015610693575f5ffd5b5061069c6114f5565b6040516106a99190612983565b60405180910390f35b3480156106bd575f5ffd5b506106c661151d565b6040516106d39190612954565b60405180910390f35b3480156106e7575f5ffd5b5061070260048036038101906106fd9190613094565b61155a565b005b34801561070f575f5ffd5b5061072a6004803603810190610725919061316e565b611778565b005b348015610737575f5ffd5b50610752600480360381019061074d9190612b54565b6117cb565b005b34801561075f575f5ffd5b5061077a60048036038101906107759190612ac4565b61187e565b6040516107879190612799565b60405180910390f35b34801561079b575f5ffd5b506107b660048036038101906107b19190613256565b611893565b005b3480156107c3575f5ffd5b506107de60048036038101906107d99190612ac4565b611987565b6040516107eb919061284c565b60405180910390f35b3480156107ff575f5ffd5b5061081a60048036038101906108159190612ac4565b6119a4565b6040516108279190612954565b60405180910390f35b34801561083b575f5ffd5b50610844611a4f565b6040516108519190612799565b60405180910390f35b348015610865575f5ffd5b50610880600480360381019061087b91906132d4565b611a5c565b60405161088d919061284c565b60405180910390f35b6108b060048036038101906108ab9190612b54565b611a7e565b005b3480156108bd575f5ffd5b506108d860048036038101906108d39190613312565b611abc565b005b6108f460048036038101906108ef9190612b54565b611cf7565b005b348015610901575f5ffd5b5061091c60048036038101906109179190612b54565b611d20565b6040516109299190612799565b60405180910390f35b5f679a31110384e0b0c960205282601452815f5260405f2054905092915050565b5f61095d82611d39565b8061096d575061096c82611d5d565b5b806109d557507fad0d7f6c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109e557506109e482611d5d565b5b9050919050565b650400000000006109fc81611d79565b610a068383611dae565b505050565b60606040518060400160405280600a81526020017f42415943204665656c7300000000000000000000000000000000000000000000815250905090565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b68200000000000000000610a8381611e0f565b5f8585905003610abf576040517fe806f59d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b85859050811015610bc65760035f878784818110610ae557610ae46133a8565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff16610b6057858582818110610b1d57610b1c6133a8565b5b905060200201356040517faac7aeed000000000000000000000000000000000000000000000000000000008152600401610b579190612799565b60405180910390fd5b838382818110610b7357610b726133a8565b5b9050602002013560025f888885818110610b9057610b8f6133a8565b5b9050602002013581526020019081526020015f205f828254610bb29190613402565b925050819055508080600101915050610ac4565b50610c61868686808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508585808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505060405180602001604052805f815250611e36565b505050505050565b5f5f7f1854b24168de2a3561e8caaa0770d8257ca046fb64fc845e3cd163acfc66770c91505f90509091565b6060610d39610ca383611f81565b5f8054610caf90613462565b80601f0160208091040260200160405190810160405280929190818152602001828054610cdb90613462565b8015610d265780601f10610cfd57610100808354040283529160200191610d26565b820191905f5260205f20905b815481529060010190602001808311610d0957829003601f168201915b5050505050611fd090919063ffffffff16565b9050919050565b610d4a3382611fe4565b50565b610d55611ff3565b610d5f828261202a565b5050565b5f8182610d6f85610e36565b1614905092915050565b5f610d8261203a565b67ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f5f5f610dd5612044565b6bffffffffffffffffffffffff169050845f5268aa4ec00224afccfdb760205260405f20548060601c935083610e12576020515490508060601c93505b848460601b8218805f1904821181023d3d3e83818302049450505050509250929050565b5f638b78c6d8600c52815f526020600c20549050919050565b610e5761204d565b15610f2d57610f2c88888888808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508787808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612055565b5b828514610f4157633b800a465f526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c985088610f7f5763ea553b345f526004601cfd5b893314610fa157335f526034600c2054610fa057634b6e7f185f526004601cfd5b5b8660051b5b8015611010576020810390508087013583602052818a01355f5260405f20805480831115610fdb5763f4d678b85f526004601cfd5b828103825550508260205260405f20805482810181811015611004576301336cea5f526004601cfd5b80835550505050610fa6565b50604051604081528760051b886040830152808a6060840137806060016020830152606081830101898152818960208301378b8d337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60808687010187a4505050505061107b6121a9565b156110915761109088888888888888886121b0565b5b863b1561114b57865f5260405163bc197c81815233602082015288604082015260a060608201528560051b8660c0830152808860e08401378060c001608083015260e08183010187815281876020830137818260e0010160a084015260208282010190508381528385602083013781820184016101040160208482601c604051015f5f515af161112a573d15611129573d5f853e3d84fd5b5b63bc197c8160e01b84511461114657639c05499b5f526004601cfd5b505050505b5050505050505050565b61115d611ff3565b6111678282611fe4565b5050565b606083821461118157633b800a465f526004601cfd5b6040519050818152602081018260051b8181016040525b80156111ce57602081039050808701358060601b679a31110384e0b0c917602052818601355f5260405f20548284015250611198565b5050949350505050565b5f5f826111e485610e36565b161415905092915050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b6504000000000061123881611d79565b815f90816112469190613632565b507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60405161129892919061373a565b60405180910390a15050565b5f80546112b090613462565b80601f01602080910402602001604051908101604052809291908181526020018280546112dc90613462565b80156113275780601f106112fe57610100808354040283529160200191611327565b820191905f5260205f20905b81548152906001019060200180831161130a57829003601f168201915b505050505081565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61135c611ff3565b6113655f612298565b565b6820000000000000000061137a81611e0f565b5f82036113b3576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60035f8467ffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1661141c57826040517faac7aeed0000000000000000000000000000000000000000000000000000000081526004016114139190613791565b60405180910390fd5b8160025f8567ffffffffffffffff1681526020019081526020015f205f8282546114469190613402565b9250508190555061149260015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168467ffffffffffffffff168460405180602001604052805f81525061235e565b505050565b6504000000000081565b650400000000006114b181611d79565b8160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754905090565b60606040518060400160405280600981526020017f424159434645454c530000000000000000000000000000000000000000000000815250905090565b6820000000000000000061156d81611e0f565b84849050878790501415806115885750828290508787905014155b156115bf576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b8787905081101561176e578383828181106115e2576115e16133a8565b5b90506020028101906115f491906137b6565b9050868683818110611609576116086133a8565b5b905060200281019061161b91906137b6565b905014611654576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186869050036116e6576116e1868683818110611675576116746133a8565b5b905060200281019061168791906137b6565b5f818110611698576116976133a8565b5b905060200201358585848181106116b2576116b16133a8565b5b90506020028101906116c491906137b6565b5f8181106116d5576116d46133a8565b5b90506020020135611367565b611761565b6117608888838181106116fc576116fb6133a8565b5b90506020020160208101906117119190612b54565b878784818110611724576117236133a8565b5b905060200281019061173691906137b6565b878786818110611749576117486133a8565b5b905060200281019061175b91906137b6565b610a70565b5b80806001019150506115c4565b5050505050505050565b8015159050679a31110384e0b0c960205233601452815f52806034600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b650400000000006117db81611d79565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508260045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac8184604051611871929190613818565b60405180910390a1505050565b6002602052805f5260405f205f915090505481565b650400000000006118a381611d79565b8282905085859050146118e2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f90505b8585905081101561197f57838382818110611905576119046133a8565b5b905060200201602081019061191a919061383f565b60035f8888858181106119305761192f6133a8565b5b9050602002016020810190611945919061386a565b67ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555080806001019150506118e7565b505050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6060611a486119b283611f81565b5f80546119be90613462565b80601f01602080910402602001604051908101604052809291908181526020018280546119ea90613462565b8015611a355780601f10611a0c57610100808354040283529160200191611a35565b820191905f5260205f20905b815481529060010190602001808311611a1857829003601f168201915b5050505050611fd090919063ffffffff16565b9050919050565b6820000000000000000081565b5f679a31110384e0b0c960205282601452815f526034600c2054905092915050565b611a86611ff3565b63389a75e1600c52805f526020600c208054421115611aac57636f5e88185f526004601cfd5b5f815550611ab981612298565b50565b611ac461204d565b15611b2a57611b298686611ad787612453565b611ae087612453565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612055565b5b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c965086611b685763ea553b345f526004601cfd5b873314611b8a57335f526034600c2054611b8957634b6e7f185f526004601cfd5b5b855f5260405f20805480871115611ba85763f4d678b85f526004601cfd5b868103825550508060205260405f20805486810181811015611bd1576301336cea5f526004601cfd5b808355505050846020528688337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa45050611c0d6121a9565b15611c7357611c728686611c2087612453565b611c2987612453565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612470565b5b843b15611cef5760405163f23a6e61815233602082015286604082015284606082015283608082015260a0808201528160c0820152818360e08301376020818360c401601c84015f8a5af1611cd1573d15611cd0573d5f823e3d81fd5b5b63f23a6e6160e01b815114611ced57639c05499b5f526004601cfd5b505b505050505050565b611cff611ff3565b8060601b611d1457637448fbae5f526004601cfd5b611d1d81612298565b50565b5f63389a75e1600c52815f526020600c20549050919050565b5f8160e01c630e89341c811463d9b67a2682146301ffc9a783141717915050919050565b5f8160e01c632a55205a81146301ffc9a7821417915050919050565b638b78c6d8600c52335f52806020600c205416611dab57638b78c6d819543314611daa576382b429005f526004601cfd5b5b50565b5f611db7612044565b6bffffffffffffffffffffffff1690508160a01b60a01c915080821115611de55763350a88b35f526004601cfd5b8260601b80611dfb5763b4457eaa5f526004601cfd5b82811768aa4ec00224afccfdb75550505050565b638b78c6d8600c52335f52806020600c205416611e33576382b429005f526004601cfd5b50565b611e3e61204d565b15611e5157611e505f85858585612055565b5b8151835114611e6757633b800a465f526004601cfd5b8360601b80611e7d5763ea553b345f526004601cfd5b80679a31110384e0b0c917602052835160051b5b8015611ed15780840151818601515f5260405f20805482810181811015611ebf576301336cea5f526004601cfd5b80835550505050602081039050611e91565b5060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d82010391508360601c5f337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8587a450505050611f4c6121a9565b15611f5f57611f5e5f85858585612470565b5b611f6884612477565b15611f7b57611f7a5f85858585612481565b5b50505050565b60606080604051019050602081016040525f8152805f19835b600115611fbb578184019350600a81066030018453600a8104905080611f9a575b50828203602084039350808452505050919050565b6060611fdc8383612548565b905092915050565b611fef82825f6125bf565b5050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314612028576382b429005f526004601cfd5b565b612036828260016125bf565b5050565b5f6202a300905090565b5f612710905090565b5f6001905090565b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141580156120bd57505f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b156121a2575f5f90505b83518110156121a05760045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631854b241338888888681518110612123576121226133a8565b5b602002602001015188878151811061213e5761213d6133a8565b5b60200260200101516040518663ffffffff1660e01b8152600401612166959493929190613895565b5f604051808303815f87803b15801561217d575f5ffd5b505af115801561218f573d5f5f3e3d5ffd5b5050505080806001019150506120c7565b505b5050505050565b5f5f905090565b6121b86121a9565b1561228e5761228d88888888808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508787808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f8201169050808301925050505050505086868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612470565b5b5050505050505050565b6122a0612617565b15612305577fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa3811560ff1b821781555061235b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278160601b60601c91508181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f5fa3818155505b50565b61236661204d565b15612389576123885f8561237986612453565b61238286612453565b85612055565b5b8360601b8061239f5763ea553b345f526004601cfd5b679a31110384e0b0c960205284601452835f5260405f208054848101818110156123d0576301336cea5f526004601cfd5b808355505050826020528060601c5f337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa45061240e6121a9565b15612431576124305f8561242186612453565b61242a86612453565b85612470565b5b61243a84612477565b1561244d5761244c5f8585858561261b565b5b50505050565b606060405190506040810160405260018152816020820152919050565b5050505050565b5f813b9050919050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d810160a08501523d82019150845160200192508282848760045afa50601c84013d830103925060208484601c87015f8c5af1612521573d15612520573d5f853e3d84fd5b5b63bc197c8160e01b84511461253d57639c05499b5f526004601cfd5b505050505050505050565b60606040519050601f1983518160208201165b60011561257557808601518185015282810190508061255b575b5083518184018360208301165b60011561259c578087015181830152848101905080612582575b508183018060208701015f81528187526020810160405250505050505092915050565b638b78c6d8600c52825f526020600c208054838117836125e157848216821890505b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f90565b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c08301528015612667578060e08301826020860160045afa505b6020828260c401601c85015f8a5af1612689573d15612688573d5f833e3d82fd5b5b63f23a6e6160e01b8251146126a557639c05499b5f526004601cfd5b50505050505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6126e8826126bf565b9050919050565b6126f8816126de565b8114612702575f5ffd5b50565b5f81359050612713816126ef565b92915050565b5f819050919050565b61272b81612719565b8114612735575f5ffd5b50565b5f8135905061274681612722565b92915050565b5f5f60408385031215612762576127616126b7565b5b5f61276f85828601612705565b925050602061278085828601612738565b9150509250929050565b61279381612719565b82525050565b5f6020820190506127ac5f83018461278a565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6127e6816127b2565b81146127f0575f5ffd5b50565b5f81359050612801816127dd565b92915050565b5f6020828403121561281c5761281b6126b7565b5b5f612829848285016127f3565b91505092915050565b5f8115159050919050565b61284681612832565b82525050565b5f60208201905061285f5f83018461283d565b92915050565b5f6bffffffffffffffffffffffff82169050919050565b61288581612865565b811461288f575f5ffd5b50565b5f813590506128a08161287c565b92915050565b5f5f604083850312156128bc576128bb6126b7565b5b5f6128c985828601612705565b92505060206128da85828601612892565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f612926826128e4565b61293081856128ee565b93506129408185602086016128fe565b6129498161290c565b840191505092915050565b5f6020820190508181035f83015261296c818461291c565b905092915050565b61297d816126de565b82525050565b5f6020820190506129965f830184612974565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126129bd576129bc61299c565b5b8235905067ffffffffffffffff8111156129da576129d96129a0565b5b6020830191508360208202830111156129f6576129f56129a4565b5b9250929050565b5f5f5f5f5f60608688031215612a1657612a156126b7565b5b5f612a2388828901612705565b955050602086013567ffffffffffffffff811115612a4457612a436126bb565b5b612a50888289016129a8565b9450945050604086013567ffffffffffffffff811115612a7357612a726126bb565b5b612a7f888289016129a8565b92509250509295509295909350565b612a97816127b2565b82525050565b5f604082019050612ab05f830185612a8e565b612abd602083018461283d565b9392505050565b5f60208284031215612ad957612ad86126b7565b5b5f612ae684828501612738565b91505092915050565b5f5f60408385031215612b0557612b046126b7565b5b5f612b1285828601612738565b9250506020612b2385828601612738565b9150509250929050565b5f604082019050612b405f830185612974565b612b4d602083018461278a565b9392505050565b5f60208284031215612b6957612b686126b7565b5b5f612b7684828501612705565b91505092915050565b5f5f83601f840112612b9457612b9361299c565b5b8235905067ffffffffffffffff811115612bb157612bb06129a0565b5b602083019150836001820283011115612bcd57612bcc6129a4565b5b9250929050565b5f5f5f5f5f5f5f5f60a0898b031215612bf057612bef6126b7565b5b5f612bfd8b828c01612705565b9850506020612c0e8b828c01612705565b975050604089013567ffffffffffffffff811115612c2f57612c2e6126bb565b5b612c3b8b828c016129a8565b9650965050606089013567ffffffffffffffff811115612c5e57612c5d6126bb565b5b612c6a8b828c016129a8565b9450945050608089013567ffffffffffffffff811115612c8d57612c8c6126bb565b5b612c998b828c01612b7f565b92509250509295985092959890939650565b5f5f83601f840112612cc057612cbf61299c565b5b8235905067ffffffffffffffff811115612cdd57612cdc6129a0565b5b602083019150836020820283011115612cf957612cf86129a4565b5b9250929050565b5f5f5f5f60408587031215612d1857612d176126b7565b5b5f85013567ffffffffffffffff811115612d3557612d346126bb565b5b612d4187828801612cab565b9450945050602085013567ffffffffffffffff811115612d6457612d636126bb565b5b612d70878288016129a8565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b612db081612719565b82525050565b5f612dc18383612da7565b60208301905092915050565b5f602082019050919050565b5f612de382612d7e565b612ded8185612d88565b9350612df883612d98565b805f5b83811015612e28578151612e0f8882612db6565b9750612e1a83612dcd565b925050600181019050612dfb565b5085935050505092915050565b5f6020820190508181035f830152612e4d8184612dd9565b905092915050565b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612e8f8261290c565b810181811067ffffffffffffffff82111715612eae57612ead612e59565b5b80604052505050565b5f612ec06126ae565b9050612ecc8282612e86565b919050565b5f67ffffffffffffffff821115612eeb57612eea612e59565b5b612ef48261290c565b9050602081019050919050565b828183375f83830152505050565b5f612f21612f1c84612ed1565b612eb7565b905082815260208101848484011115612f3d57612f3c612e55565b5b612f48848285612f01565b509392505050565b5f82601f830112612f6457612f6361299c565b5b8135612f74848260208601612f0f565b91505092915050565b5f60208284031215612f9257612f916126b7565b5b5f82013567ffffffffffffffff811115612faf57612fae6126bb565b5b612fbb84828501612f50565b91505092915050565b5f67ffffffffffffffff82169050919050565b612fe081612fc4565b8114612fea575f5ffd5b50565b5f81359050612ffb81612fd7565b92915050565b5f5f60408385031215613017576130166126b7565b5b5f61302485828601612fed565b925050602061303585828601612738565b9150509250929050565b5f5f83601f8401126130545761305361299c565b5b8235905067ffffffffffffffff811115613071576130706129a0565b5b60208301915083602082028301111561308d5761308c6129a4565b5b9250929050565b5f5f5f5f5f5f606087890312156130ae576130ad6126b7565b5b5f87013567ffffffffffffffff8111156130cb576130ca6126bb565b5b6130d789828a01612cab565b9650965050602087013567ffffffffffffffff8111156130fa576130f96126bb565b5b61310689828a0161303f565b9450945050604087013567ffffffffffffffff811115613129576131286126bb565b5b61313589828a0161303f565b92509250509295509295509295565b61314d81612832565b8114613157575f5ffd5b50565b5f8135905061316881613144565b92915050565b5f5f60408385031215613184576131836126b7565b5b5f61319185828601612705565b92505060206131a28582860161315a565b9150509250929050565b5f5f83601f8401126131c1576131c061299c565b5b8235905067ffffffffffffffff8111156131de576131dd6129a0565b5b6020830191508360208202830111156131fa576131f96129a4565b5b9250929050565b5f5f83601f8401126132165761321561299c565b5b8235905067ffffffffffffffff811115613233576132326129a0565b5b60208301915083602082028301111561324f5761324e6129a4565b5b9250929050565b5f5f5f5f6040858703121561326e5761326d6126b7565b5b5f85013567ffffffffffffffff81111561328b5761328a6126bb565b5b613297878288016131ac565b9450945050602085013567ffffffffffffffff8111156132ba576132b96126bb565b5b6132c687828801613201565b925092505092959194509250565b5f5f604083850312156132ea576132e96126b7565b5b5f6132f785828601612705565b925050602061330885828601612705565b9150509250929050565b5f5f5f5f5f5f60a0878903121561332c5761332b6126b7565b5b5f61333989828a01612705565b965050602061334a89828a01612705565b955050604061335b89828a01612738565b945050606061336c89828a01612738565b935050608087013567ffffffffffffffff81111561338d5761338c6126bb565b5b61339989828a01612b7f565b92509250509295509295509295565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61340c82612719565b915061341783612719565b925082820190508082111561342f5761342e6133d5565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061347957607f821691505b60208210810361348c5761348b613435565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026134ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826134b3565b6134f886836134b3565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61353361352e61352984612719565b613510565b612719565b9050919050565b5f819050919050565b61354c83613519565b6135606135588261353a565b8484546134bf565b825550505050565b5f5f905090565b613577613568565b613582818484613543565b505050565b5b818110156135a55761359a5f8261356f565b600181019050613588565b5050565b601f8211156135ea576135bb81613492565b6135c4846134a4565b810160208510156135d3578190505b6135e76135df856134a4565b830182613587565b50505b505050565b5f82821c905092915050565b5f61360a5f19846008026135ef565b1980831691505092915050565b5f61362283836135fb565b9150826002028217905092915050565b61363b826128e4565b67ffffffffffffffff81111561365457613653612e59565b5b61365e8254613462565b6136698282856135a9565b5f60209050601f83116001811461369a575f8415613688578287015190505b6136928582613617565b8655506136f9565b601f1984166136a886613492565b5f5b828110156136cf578489015182556001820191506020850194506020810190506136aa565b868310156136ec57848901516136e8601f8916826135fb565b8355505b6001600288020188555050505b505050505050565b5f819050919050565b5f61372461371f61371a84613701565b613510565b612719565b9050919050565b6137348161370a565b82525050565b5f60408201905061374d5f83018561372b565b61375a602083018461278a565b9392505050565b5f61377b61377661377184612fc4565b613510565b612719565b9050919050565b61378b81613761565b82525050565b5f6020820190506137a45f830184613782565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126137d2576137d16137aa565b5b80840192508235915067ffffffffffffffff8211156137f4576137f36137ae565b5b6020830192506020820236038313156138105761380f6137b2565b5b509250929050565b5f60408201905061382b5f830185612974565b6138386020830184612974565b9392505050565b5f60208284031215613854576138536126b7565b5b5f6138618482850161315a565b91505092915050565b5f6020828403121561387f5761387e6126b7565b5b5f61388c84828501612fed565b91505092915050565b5f60a0820190506138a85f830188612974565b6138b56020830187612974565b6138c26040830186612974565b6138cf606083018561278a565b6138dc608083018461278a565b969550505050505056fea26469706673582212202857b8cef0ba7104a8a3a9b72d981e7ea2a6a93333c8853f199523e30040733b64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000721c008fdff27bf06e7e123956e2fe03b63342e300000000000000000000000006dd843b78e6cc34744473176d8a61743eefaa9a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000a66e65b4ed40aced74d28775abe4ee6537cd7a40000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656965336332653736733469727a767935736d707176616d6b78636273626a6b616f68637878656b62653366367237647834777079792f0000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : transferValidator (address): 0x721C008fdff27BF06E7E123956E2Fe03B63342e3
Arg [1] : royaltyRecipient (address): 0x06dd843B78E6Cc34744473176d8a61743eEfAa9a
Arg [2] : _baseURI (string): ipfs://bafybeie3c2e76s4irzvy5smpqvamkxcbsbjkaohcxxekbe3f6r7dx4wpyy/
Arg [3] : _santaCurtis (address): 0x0a66e65b4Ed40AcEd74D28775Abe4Ee6537cd7A4
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000721c008fdff27bf06e7e123956e2fe03b63342e3
Arg [1] : 00000000000000000000000006dd843b78e6cc34744473176d8a61743eefaa9a
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 0000000000000000000000000a66e65b4ed40aced74d28775abe4ee6537cd7a4
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000043
Arg [5] : 697066733a2f2f6261667962656965336332653736733469727a767935736d70
Arg [6] : 7176616d6b78636273626a6b616f68637878656b626533663672376478347770
Arg [7] : 79792f0000000000000000000000000000000000000000000000000000000000
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.