Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 2,123 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 34103574 | 16 days ago | IN | 0 ETH | 0.00000562 | ||||
| Set Approval For... | 33894601 | 17 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33894210 | 17 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33893842 | 17 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33893841 | 17 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33893839 | 17 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33433447 | 20 days ago | IN | 0 ETH | 0.00000674 | ||||
| Set Approval For... | 33341318 | 21 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33337918 | 21 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33337912 | 21 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 33331543 | 21 days ago | IN | 0 ETH | 0.00000473 | ||||
| Safe Transfer Fr... | 33071154 | 23 days ago | IN | 0 ETH | 0.00000691 | ||||
| Set Approval For... | 32505599 | 27 days ago | IN | 0 ETH | 0.0000043 | ||||
| Set Approval For... | 32428600 | 28 days ago | IN | 0 ETH | 0.00000438 | ||||
| Safe Transfer Fr... | 31774085 | 33 days ago | IN | 0 ETH | 0.00000862 | ||||
| Safe Transfer Fr... | 31708936 | 33 days ago | IN | 0 ETH | 0.00000783 | ||||
| Set Approval For... | 31256177 | 37 days ago | IN | 0 ETH | 0.00000486 | ||||
| Set Approval For... | 31161269 | 37 days ago | IN | 0 ETH | 0.00000409 | ||||
| Set Approval For... | 31094845 | 38 days ago | IN | 0 ETH | 0.00000559 | ||||
| Set Approval For... | 30831662 | 40 days ago | IN | 0 ETH | 0.0000044 | ||||
| Set Approval For... | 30801429 | 40 days ago | IN | 0 ETH | 0.00000559 | ||||
| Set Approval For... | 30567001 | 42 days ago | IN | 0 ETH | 0.00000559 | ||||
| Set Approval For... | 30365633 | 43 days ago | IN | 0 ETH | 0.00000438 | ||||
| Set Approval For... | 29559521 | 47 days ago | IN | 0 ETH | 0.00000561 | ||||
| Set Approval For... | 28948372 | 49 days ago | IN | 0 ETH | 0.00000559 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 20833226 | 108 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PenguBoard
Compiler Version
v0.8.28+commit.7893614a
ZkSolc Version
v1.5.15
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {ERC721} from "@animoca/ethereum-contracts/contracts/token/ERC721/ERC721.sol";
import {ERC721Base} from "@animoca/ethereum-contracts/contracts/token/ERC721/base/ERC721Base.sol";
import {ERC721Metadata} from "@animoca/ethereum-contracts/contracts/token/ERC721/ERC721Metadata.sol";
import {ERC2981} from "@animoca/ethereum-contracts/contracts/token/royalty/ERC2981.sol";
import {AccessControl} from "@animoca/ethereum-contracts/contracts/access/AccessControl.sol";
import {TokenRecovery} from "@animoca/ethereum-contracts/contracts/security/TokenRecovery.sol";
import {ContractOwnership} from "@animoca/ethereum-contracts/contracts/access/ContractOwnership.sol";
import {ERC721Storage} from "@animoca/ethereum-contracts/contracts/token/ERC721/libraries/ERC721Storage.sol";
import {AccessControlStorage} from "@animoca/ethereum-contracts/contracts/access/libraries/AccessControlStorage.sol";
import {ContractOwnershipStorage} from "@animoca/ethereum-contracts/contracts/access/libraries/ContractOwnershipStorage.sol";
import {ITokenMetadataResolver} from "@animoca/ethereum-contracts/contracts/token/metadata/interfaces/ITokenMetadataResolver.sol";
import {IPenguBoard} from "./../interfaces/IPenguBoard.sol";
import {IScratching} from "./../../game/interfaces/IScratching.sol";
import {ERC721NonExistingToken} from "@animoca/ethereum-contracts/contracts/token/ERC721/errors/ERC721Errors.sol";
import {Transfer} from "@animoca/ethereum-contracts/contracts/token/ERC721/events/ERC721Events.sol";
contract PenguBoard is ERC721, ERC721Metadata, ERC2981, IPenguBoard, AccessControl, TokenRecovery {
using ERC721Storage for ERC721Storage.Layout;
using AccessControlStorage for AccessControlStorage.Layout;
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
bytes32 public constant MINTER_ROLE = "minter";
uint256 public nextTokenId;
IScratching public scratchingContract;
event ScratchingContractSet(IScratching scratchingContract);
error PendingScratchRequest(uint256 tokenId, uint256 requestId);
constructor(
string memory tokenName,
string memory tokenSymbol,
ITokenMetadataResolver metadataResolver
) ContractOwnership(msg.sender) ERC721Metadata(tokenName, tokenSymbol, metadataResolver) {}
/// @notice Sets the scratching contract.
/// @dev Reverts with {NotContractOwner} if the caller is not the contract owner.
/// @param scratching the address of the scratching contract.
function setScratchingContract(IScratching scratching) external {
ContractOwnershipStorage.layout().enforceIsContractOwner(msg.sender);
scratchingContract = scratching;
emit ScratchingContractSet(scratching);
}
/// @notice Mints a new token with incremental token ID to the specified address.
/// @dev Reverts with {MissingRole} if the caller does not have the MINTER_ROLE.
/// @dev Emits a {Transfer} event from address 0.
/// @param to the address to mint the token to.
/// @return tokenId the ID of the minted token.
function mint(address to) external virtual returns (uint256 tokenId) {
AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, msg.sender);
tokenId = nextTokenId++;
ERC721Storage.layout().mint(to, tokenId);
}
/// @notice Burns a token.
/// @dev Reverts with {MissingRole} if the caller does not have the MINTER_ROLE.
/// @dev Reverts with {ERC721NonExistingToken} if the token does not exist.
/// @dev Emits a {Transfer} event to address 0.
/// @param tokenId the ID of the token to burn.
function burn(uint256 tokenId) external {
AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, _msgSender());
ERC721Storage.Layout storage s = ERC721Storage.layout();
address owner = address(uint160(s.owners[tokenId]));
if (owner == address(0)) revert ERC721NonExistingToken(tokenId);
s.owners[tokenId] = ERC721Storage.BURNT_TOKEN_OWNER_VALUE;
unchecked {
// cannot underflow as balance is verified through TOKEN ownership
--s.balances[owner];
}
emit Transfer(owner, address(0), tokenId);
}
/// @inheritdoc ERC721Base
/// @dev Reverts with {PendingScratchRequest} if there is a scratching contract and the token has a pending scratch request
function transferFrom(address from, address to, uint256 tokenId) external virtual override {
_requireNoPendingScratchRequest(tokenId);
ERC721Storage.layout().transferFrom(_msgSender(), from, to, tokenId);
}
/// @inheritdoc ERC721Base
/// @dev Reverts with {PendingScratchRequest} if there is a scratching contract and the token has a pending scratch request
function safeTransferFrom(address from, address to, uint256 tokenId) external virtual override {
_requireNoPendingScratchRequest(tokenId);
ERC721Storage.layout().safeTransferFrom(_msgSender(), from, to, tokenId);
}
/// @inheritdoc ERC721Base
/// @dev Reverts with {PendingScratchRequest} if there is a scratching contract and the token has a pending scratch request
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external virtual override {
_requireNoPendingScratchRequest(tokenId);
ERC721Storage.layout().safeTransferFrom(_msgSender(), from, to, tokenId, data);
}
function _requireNoPendingScratchRequest(uint256 tokenId) internal view {
IScratching scratchingContract_ = scratchingContract;
if (scratchingContract_ != IScratching(address(0))) {
uint256 pendingRequestId = scratchingContract_.pendingScratchRequest(tokenId);
require(pendingRequestId == 0, PendingScratchRequest(tokenId, pendingRequestId));
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPenguBoard {
function mint(address to) external returns (uint256 tokenId);
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IScratching {
/// @notice Returns the pending scratch request ID for a given token ID.
/// @param tokenId the token ID.
/// @return requestId the pending scratch request ID (0 if no pending request).
function pendingScratchRequest(uint256 tokenId) external view returns (uint256 requestId);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {TokenRecoveryBase} from "./base/TokenRecoveryBase.sol";
import {ContractOwnership} from "./../access/ContractOwnership.sol";
/// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract TokenRecovery is TokenRecoveryBase, ContractOwnership {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {AccessControlBase} from "./base/AccessControlBase.sol";
import {ContractOwnership} from "./ContractOwnership.sol";
/// @title Access control via roles management (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract AccessControl is AccessControlBase, ContractOwnership {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ERC721Storage} from "./libraries/ERC721Storage.sol";
import {ERC721Base} from "./base/ERC721Base.sol";
import {InterfaceDetection} from "./../../introspection/InterfaceDetection.sol";
/// @title ERC721 Non-Fungible Token Standard (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC721 is ERC721Base, InterfaceDetection {
/// @notice Marks the following ERC165 interfaces as supported: ERC721.
constructor() {
ERC721Storage.init();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {NotRoleHolder, NotTargetContractRoleHolder} from "./../errors/AccessControlErrors.sol";
import {TargetIsNotAContract} from "./../errors/Common.sol";
import {RoleGranted, RoleRevoked} from "./../events/AccessControlEvents.sol";
import {IAccessControl} from "./../interfaces/IAccessControl.sol";
import {Address} from "./../../utils/libraries/Address.sol";
library AccessControlStorage {
using Address for address;
using AccessControlStorage for AccessControlStorage.Layout;
struct Layout {
mapping(bytes32 => mapping(address => bool)) roles;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.AccessControl.storage")) - 1);
/// @notice Grants a role to an account.
/// @dev Note: Call to this function should be properly access controlled.
/// @dev Emits a {RoleGranted} event if the account did not previously have the role.
/// @param role The role to grant.
/// @param account The account to grant the role to.
/// @param operator The account requesting the role change.
function grantRole(Layout storage s, bytes32 role, address account, address operator) internal {
if (!s.hasRole(role, account)) {
s.roles[role][account] = true;
emit RoleGranted(role, account, operator);
}
}
/// @notice Revokes a role from an account.
/// @dev Note: Call to this function should be properly access controlled.
/// @dev Emits a {RoleRevoked} event if the account previously had the role.
/// @param role The role to revoke.
/// @param account The account to revoke the role from.
/// @param operator The account requesting the role change.
function revokeRole(Layout storage s, bytes32 role, address account, address operator) internal {
if (s.hasRole(role, account)) {
s.roles[role][account] = false;
emit RoleRevoked(role, account, operator);
}
}
/// @notice Renounces a role by the sender.
/// @dev Reverts with {NotRoleHolder} if `sender` does not have `role`.
/// @dev Emits a {RoleRevoked} event.
/// @param sender The message sender.
/// @param role The role to renounce.
function renounceRole(Layout storage s, address sender, bytes32 role) internal {
s.enforceHasRole(role, sender);
s.roles[role][sender] = false;
emit RoleRevoked(role, sender, sender);
}
/// @notice Retrieves whether an account has a role.
/// @param role The role.
/// @param account The account.
/// @return hasRole_ Whether `account` has `role`.
function hasRole(Layout storage s, bytes32 role, address account) internal view returns (bool hasRole_) {
return s.roles[role][account];
}
/// @notice Checks whether an account has a role in a target contract.
/// @param targetContract The contract to check.
/// @param role The role to check.
/// @param account The account to check.
/// @return hasTargetContractRole_ Whether `account` has `role` in `targetContract`.
function hasTargetContractRole(address targetContract, bytes32 role, address account) internal view returns (bool hasTargetContractRole_) {
if (!targetContract.hasBytecode()) revert TargetIsNotAContract(targetContract);
return IAccessControl(targetContract).hasRole(role, account);
}
/// @notice Ensures that an account has a role.
/// @dev Reverts with {NotRoleHolder} if `account` does not have `role`.
/// @param role The role.
/// @param account The account.
function enforceHasRole(Layout storage s, bytes32 role, address account) internal view {
if (!s.hasRole(role, account)) revert NotRoleHolder(role, account);
}
/// @notice Enforces that an account has a role in a target contract.
/// @dev Reverts with {NotTargetContractRoleHolder} if the account does not have the role.
/// @param targetContract The contract to check.
/// @param role The role to check.
/// @param account The account to check.
function enforceHasTargetContractRole(address targetContract, bytes32 role, address account) internal view {
if (!hasTargetContractRole(targetContract, role, account)) revert NotTargetContractRoleHolder(targetContract, role, account);
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ITokenMetadataResolver} from "./../metadata/interfaces/ITokenMetadataResolver.sol";
import {TokenMetadataStorage} from "./../metadata/libraries/TokenMetadataStorage.sol";
import {ERC721Storage} from "./libraries/ERC721Storage.sol";
import {ERC721MetadataBase} from "./base/ERC721MetadataBase.sol";
/// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata (immutable version).
/// @notice This contracts uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC721Metadata is ERC721MetadataBase {
using TokenMetadataStorage for TokenMetadataStorage.Layout;
/// @notice Marks the following ERC165 interfaces as supported: ERC721Metadata.
/// @param name The name of the token.
/// @param symbol The symbol of the token.
/// @param metadataResolver The address of the metadata resolver contract.
constructor(string memory name, string memory symbol, ITokenMetadataResolver metadataResolver) {
TokenMetadataStorage.layout().constructorInit(name, symbol, metadataResolver);
ERC721Storage.initERC721Metadata();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {NotContractOwner, NotTargetContractOwner} from "./../errors/ContractOwnershipErrors.sol";
import {TargetIsNotAContract} from "./../errors/Common.sol";
import {OwnershipTransferred} from "./../events/ERC173Events.sol";
import {IERC173} from "./../interfaces/IERC173.sol";
import {Address} from "./../../utils/libraries/Address.sol";
import {ProxyInitialization} from "./../../proxy/libraries/ProxyInitialization.sol";
import {InterfaceDetectionStorage} from "./../../introspection/libraries/InterfaceDetectionStorage.sol";
library ContractOwnershipStorage {
using Address for address;
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;
struct Layout {
address contractOwner;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.storage")) - 1);
bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.phase")) - 1);
/// @notice Initializes the storage with an initial contract owner (immutable version).
/// @notice Marks the following ERC165 interface(s) as supported: ERC173.
/// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract.
/// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
/// @param initialOwner The initial contract owner.
function constructorInit(Layout storage s, address initialOwner) internal {
if (initialOwner != address(0)) {
s.contractOwner = initialOwner;
emit OwnershipTransferred(address(0), initialOwner);
}
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC173).interfaceId, true);
}
/// @notice Initializes the storage with an initial contract owner (proxied version).
/// @notice Sets the proxy initialization phase to `1`.
/// @notice Marks the following ERC165 interface(s) as supported: ERC173.
/// @dev Note: This function should be called ONLY in the init function of a proxied contract.
/// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above.
/// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
/// @param initialOwner The initial contract owner.
function proxyInit(Layout storage s, address initialOwner) internal {
ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1);
s.constructorInit(initialOwner);
}
/// @notice Sets the address of the new contract owner.
/// @dev Reverts with {NotContractOwner} if `sender` is not the contract owner.
/// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner.
/// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership.
function transferOwnership(Layout storage s, address sender, address newOwner) internal {
address previousOwner = s.contractOwner;
if (sender != previousOwner) revert NotContractOwner(sender);
if (previousOwner != newOwner) {
s.contractOwner = newOwner;
emit OwnershipTransferred(previousOwner, newOwner);
}
}
/// @notice Gets the address of the contract owner.
/// @return contractOwner The address of the contract owner.
function owner(Layout storage s) internal view returns (address contractOwner) {
return s.contractOwner;
}
/// @notice Checks whether an account is the owner of a target contract.
/// @param targetContract The contract to check.
/// @param account The account to check.
/// @return isTargetContractOwner_ Whether `account` is the owner of `targetContract`.
function isTargetContractOwner(address targetContract, address account) internal view returns (bool isTargetContractOwner_) {
if (!targetContract.hasBytecode()) revert TargetIsNotAContract(targetContract);
return IERC173(targetContract).owner() == account;
}
/// @notice Ensures that an account is the contract owner.
/// @dev Reverts with {NotContractOwner} if `account` is not the contract owner.
/// @param account The account.
function enforceIsContractOwner(Layout storage s, address account) internal view {
if (account != s.contractOwner) revert NotContractOwner(account);
}
/// @notice Enforces that an account is the owner of a target contract.
/// @dev Reverts with {NotTheTargetContractOwner} if the account is not the owner.
/// @param targetContract The contract to check.
/// @param account The account to check.
function enforceIsTargetContractOwner(address targetContract, address account) internal view {
if (!isTargetContractOwner(targetContract, account)) revert NotTargetContractOwner(targetContract, account);
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC721} from "./../interfaces/IERC721.sol";
import {ERC721Storage} from "./../libraries/ERC721Storage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/// @title ERC721 Non-Fungible Token Standard (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
abstract contract ERC721Base is IERC721, Context {
using ERC721Storage for ERC721Storage.Layout;
/// @inheritdoc IERC721
function approve(address to, uint256 tokenId) external virtual {
ERC721Storage.layout().approve(_msgSender(), to, tokenId);
}
/// @inheritdoc IERC721
function setApprovalForAll(address operator, bool approved) external virtual {
ERC721Storage.layout().setApprovalForAll(_msgSender(), operator, approved);
}
/// @inheritdoc IERC721
function transferFrom(address from, address to, uint256 tokenId) external virtual {
ERC721Storage.layout().transferFrom(_msgSender(), from, to, tokenId);
}
/// @inheritdoc IERC721
function safeTransferFrom(address from, address to, uint256 tokenId) external virtual {
ERC721Storage.layout().safeTransferFrom(_msgSender(), from, to, tokenId);
}
/// @inheritdoc IERC721
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external virtual {
ERC721Storage.layout().safeTransferFrom(_msgSender(), from, to, tokenId, data);
}
/// @inheritdoc IERC721
function balanceOf(address owner) external view virtual returns (uint256 balance) {
return ERC721Storage.layout().balanceOf(owner);
}
/// @inheritdoc IERC721
function ownerOf(uint256 tokenId) external view virtual returns (address tokenOwner) {
return ERC721Storage.layout().ownerOf(tokenId);
}
/// @inheritdoc IERC721
function getApproved(uint256 tokenId) external view virtual returns (address approved) {
return ERC721Storage.layout().getApproved(tokenId);
}
/// @inheritdoc IERC721
function isApprovedForAll(address owner, address operator) external view virtual returns (bool approvedForAll) {
return ERC721Storage.layout().isApprovedForAll(owner, operator);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
// solhint-disable-next-line max-line-length
import {ERC721SelfApproval, ERC721SelfApprovalForAll, ERC721NonApprovedForApproval, ERC721TransferToAddressZero, ERC721NonExistingToken, ERC721NonApprovedForTransfer, ERC721NonOwnedToken, ERC721SafeTransferRejected, ERC721BalanceOfAddressZero} from "./../errors/ERC721Errors.sol";
import {ERC721MintToAddressZero, ERC721ExistingToken} from "./../errors/ERC721MintableErrors.sol";
import {ERC721BurntToken} from "./../errors/ERC721MintableOnceErrors.sol";
import {InconsistentArrayLengths} from "./../../../CommonErrors.sol";
import {Transfer, Approval, ApprovalForAll} from "./../events/ERC721Events.sol";
import {IERC721} from "./../interfaces/IERC721.sol";
import {IERC721BatchTransfer} from "./../interfaces/IERC721BatchTransfer.sol";
import {IERC721Metadata} from "./../interfaces/IERC721Metadata.sol";
import {IERC721Mintable} from "./../interfaces/IERC721Mintable.sol";
import {IERC721Deliverable} from "./../interfaces/IERC721Deliverable.sol";
import {IERC721Burnable} from "./../interfaces/IERC721Burnable.sol";
import {IERC721Receiver} from "./../interfaces/IERC721Receiver.sol";
import {Address} from "./../../../utils/libraries/Address.sol";
import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol";
library ERC721Storage {
using Address for address;
using ERC721Storage for ERC721Storage.Layout;
using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;
struct Layout {
mapping(uint256 => uint256) owners;
mapping(address => uint256) balances;
mapping(uint256 => address) approvals;
mapping(address => mapping(address => bool)) operators;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.ERC721.ERC721.storage")) - 1);
bytes4 internal constant ERC721_RECEIVED = IERC721Receiver.onERC721Received.selector;
// Single token approval flag
// This bit is set in the owner's value to indicate that there is an approval set for this token
uint256 internal constant TOKEN_APPROVAL_OWNER_FLAG = 1 << 160;
// Burnt token magic value
// This magic number is used as the owner's value to indicate that the token has been burnt
uint256 internal constant BURNT_TOKEN_OWNER_VALUE = 0xdead000000000000000000000000000000000000000000000000000000000000;
/// @notice Marks the following ERC165 interface(s) as supported: ERC721.
function init() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721).interfaceId, true);
}
/// @notice Marks the following ERC165 interface(s) as supported: ERC721BatchTransfer.
function initERC721BatchTransfer() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721BatchTransfer).interfaceId, true);
}
/// @notice Marks the following ERC165 interface(s) as supported: ERC721Metadata.
function initERC721Metadata() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Metadata).interfaceId, true);
}
/// @notice Marks the following ERC165 interface(s) as supported: ERC721Mintable.
function initERC721Mintable() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Mintable).interfaceId, true);
}
/// @notice Marks the following ERC165 interface(s) as supported: ERC721Deliverable.
function initERC721Deliverable() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Deliverable).interfaceId, true);
}
/// @notice Marks the following ERC165 interface(s) as supported: ERC721Burnable.
function initERC721Burnable() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC721Burnable).interfaceId, true);
}
/// @notice Sets or unsets an approval to transfer a single token on behalf of its owner.
/// @dev Note: This function implements {ERC721-approve(address,uint256)}.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @dev Reverts with {ERC721SelfApproval} if `to` is the token owner.
/// @dev Reverts with {ERC721NonApprovedForApproval} if `sender` is not the token owner and has not been approved by the token owner.
/// @dev Emits an {Approval} event.
/// @param sender The message sender.
/// @param to The address to approve, or the zero address to remove any existing approval.
/// @param tokenId The token identifier to give approval for.
function approve(Layout storage s, address sender, address to, uint256 tokenId) internal {
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
address ownerAddress = _tokenOwner(owner);
if (to == ownerAddress) revert ERC721SelfApproval(ownerAddress);
if (!_isOperatable(s, ownerAddress, sender)) revert ERC721NonApprovedForApproval(sender, ownerAddress, tokenId);
if (to == address(0)) {
if (_tokenHasApproval(owner)) {
// remove the approval bit if it is present
s.owners[tokenId] = uint256(uint160(ownerAddress));
}
} else {
uint256 ownerWithApprovalBit = owner | TOKEN_APPROVAL_OWNER_FLAG;
if (owner != ownerWithApprovalBit) {
// add the approval bit if it is not present
s.owners[tokenId] = ownerWithApprovalBit;
}
s.approvals[tokenId] = to;
}
emit Approval(ownerAddress, to, tokenId);
}
/// @notice Sets or unsets an approval to transfer all tokens on behalf of their owner.
/// @dev Note: This function implements {ERC721-setApprovalForAll(address,bool)}.
/// @dev Reverts with {ERC721SelfApprovalForAll} if `sender` is the same as `operator`.
/// @dev Emits an {ApprovalForAll} event.
/// @param sender The message sender.
/// @param operator The address to approve for all tokens.
/// @param approved True to set an approval for all tokens, false to unset it.
function setApprovalForAll(Layout storage s, address sender, address operator, bool approved) internal {
if (operator == sender) revert ERC721SelfApprovalForAll(sender);
s.operators[sender][operator] = approved;
emit ApprovalForAll(sender, operator, approved);
}
/// @notice Unsafely transfers the ownership of a token to a recipient by a sender.
/// @dev Note: This function implements {ERC721-transferFrom(address,address,uint256)}.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Emits a {Transfer} event.
/// @param sender The message sender.
/// @param from The current token owner.
/// @param to The recipient of the token transfer.
/// @param tokenId The identifier of the token to transfer.
function transferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId) internal {
if (to == address(0)) revert ERC721TransferToAddressZero();
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId);
if (!_isOperatable(s, from, sender)) {
if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId);
}
s.owners[tokenId] = uint256(uint160(to));
if (from != to) {
unchecked {
// cannot underflow as balance is verified through ownership
--s.balances[from];
// cannot overflow as supply cannot overflow
++s.balances[to];
}
}
emit Transfer(from, to, tokenId);
}
/// @notice Safely transfers the ownership of a token to a recipient by a sender.
/// @dev Note: This function implements {ERC721-safeTransferFrom(address,address,uint256)}.
/// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to
/// {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event.
/// @param sender The message sender.
/// @param from The current token owner.
/// @param to The recipient of the token transfer.
/// @param tokenId The identifier of the token to transfer.
function safeTransferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId) internal {
s.transferFrom(sender, from, to, tokenId);
if (to.hasBytecode()) {
_callOnERC721Received(sender, from, to, tokenId, "");
}
}
/// @notice Safely transfers the ownership of a token to a recipient by a sender.
/// @dev Note: This function implements {ERC721-safeTransferFrom(address,address,uint256,bytes)}.
/// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @dev Reverts with {ERC721NonOwnedToken} if `from` is not the owner of `tokenId`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to
/// {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event.
/// @param sender The message sender.
/// @param from The current token owner.
/// @param to The recipient of the token transfer.
/// @param tokenId The identifier of the token to transfer.
/// @param data Optional data to send along to a receiver contract.
function safeTransferFrom(Layout storage s, address sender, address from, address to, uint256 tokenId, bytes calldata data) internal {
s.transferFrom(sender, from, to, tokenId);
if (to.hasBytecode()) {
_callOnERC721Received(sender, from, to, tokenId, data);
}
}
/// @notice Unsafely transfers a batch of tokens to a recipient by a sender.
/// @dev Note: This function implements {ERC721BatchTransfer-batchTransferFrom(address,address,uint256[])}.
/// @dev Resets the token approval for each of `tokenIds`.
/// @dev Reverts with {ERC721TransferToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721NonExistingToken} if one of `tokenIds` does not exist.
/// @dev Reverts with {ERC721NonOwnedToken} if one of `tokenIds` is not owned by `from`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if the sender is not `from` and has not been approved by `from` for each of `tokenIds`.
/// @dev Emits a {Transfer} event for each of `tokenIds`.
/// @param sender The message sender.
/// @param from Current tokens owner.
/// @param to Address of the new token owner.
/// @param tokenIds Identifiers of the tokens to transfer.
function batchTransferFrom(Layout storage s, address sender, address from, address to, uint256[] calldata tokenIds) internal {
if (to == address(0)) revert ERC721TransferToAddressZero();
bool operatable = _isOperatable(s, from, sender);
uint256 length = tokenIds.length;
for (uint256 i; i < length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId);
if (!operatable) {
if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId);
}
s.owners[tokenId] = uint256(uint160(to));
emit Transfer(from, to, tokenId);
}
if (from != to && length != 0) {
unchecked {
// cannot underflow as balance is verified through ownership
s.balances[from] -= length;
// cannot overflow as supply cannot overflow
s.balances[to] += length;
}
}
}
/// @notice Unsafely mints a token.
/// @dev Note: This function implements {ERC721Mintable-mint(address,uint256)}.
/// @dev Note: Either `mint` or `mintOnce` should be used in a given contract, but not both.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists.
/// @dev Emits a {Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
function mint(Layout storage s, address to, uint256 tokenId) internal {
if (to == address(0)) revert ERC721MintToAddressZero();
if (_tokenExists(s.owners[tokenId])) revert ERC721ExistingToken(tokenId);
s.owners[tokenId] = uint256(uint160(to));
unchecked {
// cannot overflow due to the cost of minting individual tokens
++s.balances[to];
}
emit Transfer(address(0), to, tokenId);
}
/// @notice Safely mints a token.
/// @dev Note: This function implements {ERC721Mintable-safeMint(address,uint256,bytes)}.
/// @dev Note: Either `safeMint` or `safeMintOnce` should be used in a given contract, but not both.
/// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists.
/// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to
/// {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
/// @param data Optional data to pass along to the receiver call.
function safeMint(Layout storage s, address sender, address to, uint256 tokenId, bytes memory data) internal {
s.mint(to, tokenId);
if (to.hasBytecode()) {
_callOnERC721Received(sender, address(0), to, tokenId, data);
}
}
/// @notice Unsafely mints a batch of tokens.
/// @dev Note: This function implements {ERC721Mintable-batchMint(address,uint256[])}.
/// @dev Note: Either `batchMint` or `batchMintOnce` should be used in a given contract, but not both.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists.
/// @dev Emits a {Transfer} event from the zero address for each of `tokenIds`.
/// @param to Address of the new tokens owner.
/// @param tokenIds Identifiers of the tokens to mint.
function batchMint(Layout storage s, address to, uint256[] memory tokenIds) internal {
if (to == address(0)) revert ERC721MintToAddressZero();
uint256 length = tokenIds.length;
for (uint256 i; i < length; ++i) {
uint256 tokenId = tokenIds[i];
if (_tokenExists(s.owners[tokenId])) revert ERC721ExistingToken(tokenId);
s.owners[tokenId] = uint256(uint160(to));
emit Transfer(address(0), to, tokenId);
}
unchecked {
s.balances[to] += length;
}
}
/// @notice Unsafely mints tokens to multiple recipients.
/// @dev Note: This function implements {ERC721Deliverable-deliver(address[],uint256[])}.
/// @dev Note: Either `deliver` or `deliverOnce` should be used in a given contract, but not both.
/// @dev Reverts with {InconsistentArrayLengths} if `recipients` and `tokenIds` have different lengths.
/// @dev Reverts with {ERC721MintToAddressZero} if one of `recipients` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists.
/// @dev Emits a {Transfer} event from the zero address for each of `recipients` and `tokenIds`.
/// @param recipients Addresses of the new tokens owners.
/// @param tokenIds Identifiers of the tokens to mint.
function deliver(Layout storage s, address[] memory recipients, uint256[] memory tokenIds) internal {
uint256 length = recipients.length;
if (length != tokenIds.length) revert InconsistentArrayLengths();
for (uint256 i; i < length; ++i) {
s.mint(recipients[i], tokenIds[i]);
}
}
/// @notice Unsafely mints a token once.
/// @dev Note: This function implements {ERC721Mintable-mint(address,uint256)}.
/// @dev Note: Either `mint` or `mintOnce` should be used in a given contract, but not both.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists.
/// @dev Reverts with {ERC721BurntToken} if `tokenId` has been previously burnt.
/// @dev Emits a {Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
function mintOnce(Layout storage s, address to, uint256 tokenId) internal {
if (to == address(0)) revert ERC721MintToAddressZero();
uint256 owner = s.owners[tokenId];
if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId);
if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId);
s.owners[tokenId] = uint256(uint160(to));
unchecked {
// cannot overflow due to the cost of minting individual tokens
++s.balances[to];
}
emit Transfer(address(0), to, tokenId);
}
/// @notice Safely mints a token once.
/// @dev Note: This function implements {ERC721Mintable-safeMint(address,uint256,bytes)}.
/// @dev Note: Either `safeMint` or `safeMintOnce` should be used in a given contract, but not both.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if `tokenId` already exists.
/// @dev Reverts with {ERC721BurntToken} if `tokenId` has been previously burnt.
/// @dev Reverts with {ERC721SafeTransferRejected} if `to` is a contract and the call to
/// {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
/// @param data Optional data to pass along to the receiver call.
function safeMintOnce(Layout storage s, address sender, address to, uint256 tokenId, bytes memory data) internal {
s.mintOnce(to, tokenId);
if (to.hasBytecode()) {
_callOnERC721Received(sender, address(0), to, tokenId, data);
}
}
/// @notice Unsafely mints a batch of tokens once.
/// @dev Note: This function implements {ERC721Mintable-batchMint(address,uint256[])}.
/// @dev Note: Either `batchMint` or `batchMintOnce` should be used in a given contract, but not both.
/// @dev Reverts with {ERC721MintToAddressZero} if `to` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists.
/// @dev Reverts with {ERC721BurntToken} if one of `tokenIds` has been previously burnt.
/// @dev Emits a {Transfer} event from the zero address for each of `tokenIds`.
/// @param to Address of the new tokens owner.
/// @param tokenIds Identifiers of the tokens to mint.
function batchMintOnce(Layout storage s, address to, uint256[] memory tokenIds) internal {
if (to == address(0)) revert ERC721MintToAddressZero();
uint256 length = tokenIds.length;
for (uint256 i; i < length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 owner = s.owners[tokenId];
if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId);
if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId);
s.owners[tokenId] = uint256(uint160(to));
emit Transfer(address(0), to, tokenId);
}
unchecked {
s.balances[to] += length;
}
}
/// @notice Unsafely mints tokens to multiple recipients once.
/// @dev Note: This function implements {ERC721Deliverable-deliver(address[],uint256[])}.
/// @dev Note: Either `deliver` or `deliverOnce` should be used in a given contract, but not both.
/// @dev Reverts with {InconsistentArrayLengths} if `recipients` and `tokenIds` have different lengths.
/// @dev Reverts with {ERC721MintToAddressZero} if one of `recipients` is the zero address.
/// @dev Reverts with {ERC721ExistingToken} if one of `tokenIds` already exists.
/// @dev Reverts with {ERC721BurntToken} if one of `tokenIds` has been previously burnt.
/// @dev Emits a {Transfer} event from the zero address for each of `recipients` and `tokenIds`.
/// @param recipients Addresses of the new tokens owners.
/// @param tokenIds Identifiers of the tokens to mint.
function deliverOnce(Layout storage s, address[] memory recipients, uint256[] memory tokenIds) internal {
uint256 length = recipients.length;
if (length != tokenIds.length) revert InconsistentArrayLengths();
for (uint256 i; i < length; ++i) {
address to = recipients[i];
if (to == address(0)) revert ERC721MintToAddressZero();
uint256 tokenId = tokenIds[i];
uint256 owner = s.owners[tokenId];
if (_tokenExists(owner)) revert ERC721ExistingToken(tokenId);
if (_tokenWasBurnt(owner)) revert ERC721BurntToken(tokenId);
s.owners[tokenId] = uint256(uint160(to));
unchecked {
++s.balances[to];
}
emit Transfer(address(0), to, tokenId);
}
}
/// @notice Burns a token by a sender.
/// @dev Note: This function implements {ERC721Burnable-burnFrom(address,uint256)}.
/// @dev Reverts with {ERC721NonOwnedToken} if `tokenId` is not owned by `from`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Emits a {Transfer} event with `to` set to the zero address.
/// @param sender The message sender.
/// @param from The current token owner.
/// @param tokenId The identifier of the token to burn.
function burnFrom(Layout storage s, address sender, address from, uint256 tokenId) internal {
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId);
if (!_isOperatable(s, from, sender)) {
if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId);
}
s.owners[tokenId] = BURNT_TOKEN_OWNER_VALUE;
unchecked {
// cannot underflow as balance is verified through TOKEN ownership
--s.balances[from];
}
emit Transfer(from, address(0), tokenId);
}
/// @notice Burns a batch of tokens by a sender.
/// @dev Note: This function implements {ERC721Burnable-batchBurnFrom(address,uint256[])}.
/// @dev Reverts with {ERC721NonOwnedToken} if one of `tokenIds` is not owned by `from`.
/// @dev Reverts with {ERC721NonApprovedForTransfer} if `sender` is not `from` and has not been approved by `from` for each of `tokenIds`.
/// @dev Emits a {Transfer} event with `to` set to the zero address for each of `tokenIds`.
/// @param sender The message sender.
/// @param from The current tokens owner.
/// @param tokenIds The identifiers of the tokens to burn.
function batchBurnFrom(Layout storage s, address sender, address from, uint256[] calldata tokenIds) internal {
bool operatable = _isOperatable(s, from, sender);
uint256 length = tokenIds.length;
for (uint256 i; i < length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
if (_tokenOwner(owner) != from) revert ERC721NonOwnedToken(from, tokenId);
if (!operatable) {
if (!_tokenHasApproval(owner) || sender != s.approvals[tokenId]) revert ERC721NonApprovedForTransfer(sender, from, tokenId);
}
s.owners[tokenId] = BURNT_TOKEN_OWNER_VALUE;
emit Transfer(from, address(0), tokenId);
}
if (length != 0) {
unchecked {
s.balances[from] -= length;
}
}
}
/// @notice Gets the balance of an address.
/// @dev Note: This function implements {ERC721-balanceOf(address)}.
/// @dev Reverts with {ERC721BalanceOfAddressZero} if `owner` is the zero address.
/// @param owner The address to query the balance of.
/// @return balance The amount owned by the owner.
function balanceOf(Layout storage s, address owner) internal view returns (uint256 balance) {
if (owner == address(0)) revert ERC721BalanceOfAddressZero();
return s.balances[owner];
}
/// @notice Gets the owner of a token.
/// @dev Note: This function implements {ERC721-ownerOf(uint256)}.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @param tokenId The token identifier to query the owner of.
/// @return tokenOwner The owner of the token.
function ownerOf(Layout storage s, uint256 tokenId) internal view returns (address tokenOwner) {
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
return _tokenOwner(owner);
}
/// @notice Gets the approved address for a token.
/// @dev Note: This function implements {ERC721-getApproved(uint256)}.
/// @dev Reverts with {ERC721NonExistingToken} if `tokenId` does not exist.
/// @param tokenId The token identifier to query the approval of.
/// @return approved The approved address for the token identifier, or the zero address if no approval is set.
function getApproved(Layout storage s, uint256 tokenId) internal view returns (address approved) {
uint256 owner = s.owners[tokenId];
if (!_tokenExists(owner)) revert ERC721NonExistingToken(tokenId);
if (_tokenHasApproval(owner)) {
return s.approvals[tokenId];
} else {
return address(0);
}
}
/// @notice Gets whether an operator is approved for all tokens by an owner.
/// @dev Note: This function implements {ERC721-isApprovedForAll(address,address)}.
/// @param owner The address which gives the approval for all tokens.
/// @param operator The address which receives the approval for all tokens.
/// @return approvedForAll Whether the operator is approved for all tokens by the owner.
function isApprovedForAll(Layout storage s, address owner, address operator) internal view returns (bool approvedForAll) {
return s.operators[owner][operator];
}
/// @notice Gets whether a token was burnt.
/// @param tokenId The token identifier.
/// @return tokenWasBurnt Whether the token was burnt.
function wasBurnt(Layout storage s, uint256 tokenId) internal view returns (bool tokenWasBurnt) {
return _tokenWasBurnt(s.owners[tokenId]);
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
/// @notice Calls {IERC721Receiver-onERC721Received} on a target contract.
/// @dev Reverts with {ERC721SafeTransferRejected} if the call to the target fails, reverts or is rejected.
/// @param sender The message sender.
/// @param from Previous token owner.
/// @param to New token owner.
/// @param tokenId Identifier of the token transferred.
/// @param data Optional data to send along with the receiver contract call.
function _callOnERC721Received(address sender, address from, address to, uint256 tokenId, bytes memory data) private {
if (IERC721Receiver(to).onERC721Received(sender, from, tokenId, data) != ERC721_RECEIVED) revert ERC721SafeTransferRejected(to, tokenId);
}
/// @notice Returns whether an account is authorised to make a transfer on behalf of an owner.
/// @param owner The token owner.
/// @param account The account to check the operatability of.
/// @return operatable True if `account` is `owner` or is an operator for `owner`, false otherwise.
function _isOperatable(Layout storage s, address owner, address account) private view returns (bool operatable) {
return (owner == account) || s.operators[owner][account];
}
function _tokenOwner(uint256 owner) private pure returns (address tokenOwner) {
return address(uint160(owner));
}
function _tokenExists(uint256 owner) private pure returns (bool tokenExists) {
return uint160(owner) != 0;
}
function _tokenWasBurnt(uint256 owner) private pure returns (bool tokenWasBurnt) {
return owner == BURNT_TOKEN_OWNER_VALUE;
}
function _tokenHasApproval(uint256 owner) private pure returns (bool tokenHasApproval) {
return owner & TOKEN_APPROVAL_OWNER_FLAG != 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ITokenMetadataResolver
/// @notice Interface for Token Metadata Resolvers.
interface ITokenMetadataResolver {
/// @notice Gets the token metadata URI for a token.
/// @param tokenContract The token contract for which to retrieve the token URI.
/// @param tokenId The token identifier.
/// @return tokenURI The token metadata URI.
function tokenMetadataURI(address tokenContract, uint256 tokenId) external view returns (string memory tokenURI);
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when trying to approve oneself. /// @param account The account trying to approve itself. error ERC721SelfApproval(address account); /// @notice Thrown when trying to approveForAll oneself. /// @param account The account trying to approveForAll itself. error ERC721SelfApprovalForAll(address account); /// @notice Thrown when a sender tries to set a token approval but is neither the owner nor approvedForAll by the owner. /// @param sender The message sender. /// @param tokenId The identifier of the token. error ERC721NonApprovedForApproval(address sender, address owner, uint256 tokenId); /// @notice Thrown when transferring a token to the zero address. error ERC721TransferToAddressZero(); /// @notice Thrown when a token does not exist but is required to. /// @param tokenId The identifier of the token that was checked. error ERC721NonExistingToken(uint256 tokenId); /// @notice Thrown when a sender tries to transfer a token but is neither the owner nor approved by the owner. /// @param sender The message sender. /// @param tokenId The identifier of the token. error ERC721NonApprovedForTransfer(address sender, address owner, uint256 tokenId); /// @notice Thrown when a token is not owned by the expected account. /// @param account The account that was expected to own the token. /// @param tokenId The identifier of the token. error ERC721NonOwnedToken(address account, uint256 tokenId); /// @notice Thrown when a safe transfer is rejected by the recipient contract. /// @param recipient The recipient contract. /// @param tokenId The identifier of the token. error ERC721SafeTransferRejected(address recipient, uint256 tokenId); /// @notice Thrown when querying the balance of the zero address. error ERC721BalanceOfAddressZero();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ContractOwnershipStorage} from "./libraries/ContractOwnershipStorage.sol";
import {ContractOwnershipBase} from "./base/ContractOwnershipBase.sol";
import {InterfaceDetection} from "./../introspection/InterfaceDetection.sol";
/// @title ERC173 Contract Ownership Standard (immutable version).
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ContractOwnership is ContractOwnershipBase, InterfaceDetection {
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
/// @notice Initializes the storage with an initial contract owner.
/// @notice Marks the following ERC165 interface(s) as supported: ERC173.
/// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
/// @param initialOwner the initial contract owner.
constructor(address initialOwner) {
ContractOwnershipStorage.layout().constructorInit(initialOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ERC2981Storage} from "./libraries/ERC2981Storage.sol";
import {ERC2981Base} from "./base/ERC2981Base.sol";
import {ContractOwnership} from "./../../access/ContractOwnership.sol";
/// @title ERC2981 NFT Royalty Standard (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC2981 is ERC2981Base, ContractOwnership {
/// @notice Marks the following ERC165 interface(s) as supported: ERC2981.
constructor() {
ERC2981Storage.init();
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Emitted when a token is transferred. /// @param from The previous token owner. /// @param to The new token owner. /// @param tokenId The transferred token identifier. event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /// @notice Emitted when a single token approval is set. /// @param owner The token owner. /// @param approved The approved address. /// @param tokenId The approved token identifier. event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /// @notice Emitted when an approval for all tokens is set or unset. /// @param owner The tokens owner. /// @param operator The approved address. /// @param approved True when then approval is set, false when it is unset. event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when trying to transfer tokens without calldata to the contract. error EtherReceptionDisabled(); /// @notice Thrown when the multiple related arrays have different lengths. error InconsistentArrayLengths(); /// @notice Thrown when an ETH transfer has failed. error TransferFailed();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC165} from "./interfaces/IERC165.sol";
import {InterfaceDetectionStorage} from "./libraries/InterfaceDetectionStorage.sol";
/// @title ERC165 Interface Detection Standard (immutable or proxiable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) or proxied implementation.
abstract contract InterfaceDetection is IERC165 {
using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external view returns (bool) {
return InterfaceDetectionStorage.layout().supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "./../../token/ERC721/interfaces/IERC721.sol";
import {ITokenRecovery} from "./../interfaces/ITokenRecovery.sol";
import {ContractOwnershipStorage} from "./../../access/libraries/ContractOwnershipStorage.sol";
import {TokenRecoveryLibrary} from "./../libraries/TokenRecoveryLibrary.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract TokenRecoveryBase is ITokenRecovery, Context {
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
/// @inheritdoc ITokenRecovery
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Reverts with {InconsistentArrayLengths} `accounts` and `amounts` do not have the same length.
/// @dev Reverts if one of the ETH transfers fails for any reason.
function recoverETH(address payable[] calldata accounts, uint256[] calldata amounts) public virtual {
ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
TokenRecoveryLibrary.recoverETH(accounts, amounts);
}
/// @inheritdoc ITokenRecovery
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `tokens` and `amounts` do not have the same length.
/// @dev Reverts if one of the ERC20 transfers fails for any reason.
function recoverERC20s(address[] calldata accounts, IERC20[] calldata tokens, uint256[] calldata amounts) public virtual {
ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
TokenRecoveryLibrary.recoverERC20s(accounts, tokens, amounts);
}
/// @inheritdoc ITokenRecovery
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `contracts` and `amounts` do not have the same length.
/// @dev Reverts if one of the ERC721 transfers fails for any reason.
function recoverERC721s(address[] calldata accounts, IERC721[] calldata contracts, uint256[] calldata tokenIds) public virtual {
ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
TokenRecoveryLibrary.recoverERC721s(accounts, contracts, tokenIds);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IAccessControl} from "./../../access/interfaces/IAccessControl.sol";
import {AccessControlStorage} from "./../libraries/AccessControlStorage.sol";
import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/// @title Access control via roles management (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract AccessControlBase is IAccessControl, Context {
using AccessControlStorage for AccessControlStorage.Layout;
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
/// @notice Grants a role to an account.
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Emits a {RoleGranted} event if the account did not previously have the role.
/// @param role The role to grant.
/// @param account The account to grant the role to.
function grantRole(bytes32 role, address account) external virtual {
address operator = _msgSender();
ContractOwnershipStorage.layout().enforceIsContractOwner(operator);
AccessControlStorage.layout().grantRole(role, account, operator);
}
/// @notice Revokes a role from an account.
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Emits a {RoleRevoked} event if the account previously had the role.
/// @param role The role to revoke.
/// @param account The account to revoke the role from.
function revokeRole(bytes32 role, address account) external virtual {
address operator = _msgSender();
ContractOwnershipStorage.layout().enforceIsContractOwner(operator);
AccessControlStorage.layout().revokeRole(role, account, operator);
}
/// @inheritdoc IAccessControl
function renounceRole(bytes32 role) external virtual {
AccessControlStorage.layout().renounceRole(_msgSender(), role);
}
/// @inheritdoc IAccessControl
function hasRole(bytes32 role, address account) external view virtual returns (bool hasRole_) {
return AccessControlStorage.layout().hasRole(role, account);
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when the target contract is actually not a contract. /// @param targetContract The contract that was checked error TargetIsNotAContract(address targetContract);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title Access control via roles management (functions)
interface IAccessControl {
/// @notice Renounces a role by the sender.
/// @dev Reverts if `sender` does not have `role`.
/// @dev Emits a {RoleRevoked} event.
/// @param role The role to renounce.
function renounceRole(bytes32 role) external;
/// @notice Retrieves whether an account has a role.
/// @param role The role.
/// @param account The account.
/// @return hasRole_ Whether `account` has `role`.
function hasRole(bytes32 role, address account) external view returns (bool hasRole_);
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when an account does not have the required role. /// @param role The role the caller is missing. /// @param account The account that was checked. error NotRoleHolder(bytes32 role, address account); /// @notice Thrown when an account does not have the required role on a target contract. /// @param targetContract The contract that was checked. /// @param role The role that was checked. /// @param account The account that was checked. error NotTargetContractRoleHolder(address targetContract, bytes32 role, address account);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Emitted when the contract ownership changes. /// @param previousOwner the previous contract owner. /// @param newOwner the new contract owner. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @notice Emitted when a new contract owner is pending. /// @param pendingOwner the address of the new contract owner. event OwnershipTransferPending(address indexed pendingOwner);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when an account is not the contract owner but is required to. /// @param account The account that was checked. error NotContractOwner(address account); /// @notice Thrown when an account is not the pending contract owner but is required to. /// @param account The account that was checked. error NotPendingContractOwner(address account); /// @notice Thrown when an account is not the target contract owner but is required to. /// @param targetContract The contract that was checked. /// @param account The account that was checked. error NotTargetContractOwner(address targetContract, address account);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
library Address {
/// @notice Checks if the address is a deployed smart contract.
/// @param addr The address to check.
/// @return hasBytecode True if `addr` is a deployed smart contract, false otherwise.
function hasBytecode(address addr) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(addr)
}
return size != 0;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Emitted when `role` is granted to `account`. /// @param role The role that has been granted. /// @param account The account that has been granted the role. /// @param operator The account that granted the role. event RoleGranted(bytes32 role, address account, address operator); /// @notice Emitted when `role` is revoked from `account`. /// @param role The role that has been revoked. /// @param account The account that has been revoked the role. /// @param operator The account that revoked the role. event RoleRevoked(bytes32 role, address account, address operator);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {InitializationPhaseAlreadyReached} from "./../errors/ProxyInitializationErrors.sol";
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
/// @notice Multiple calls protection for storage-modifying proxy initialization functions.
library ProxyInitialization {
/// @notice Sets the initialization phase during a storage-modifying proxy initialization function.
/// @dev Reverts with {InitializationPhaseAlreadyReached} if `phase` has been reached already.
/// @param storageSlot the storage slot where `phase` is stored.
/// @param phase the initialization phase.
function setPhase(bytes32 storageSlot, uint256 phase) internal {
StorageSlot.Uint256Slot storage currentVersion = StorageSlot.getUint256Slot(storageSlot);
uint256 currentPhase = currentVersion.value;
if (currentPhase >= phase) revert InitializationPhaseAlreadyReached(currentPhase, phase);
currentVersion.value = phase;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC-173 Contract Ownership Standard (functions)
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev Note: the ERC-165 identifier for this interface is 0x7f5828d0
interface IERC173 {
/// @notice Sets the address of the new contract owner.
/// @dev Reverts if the sender is not the contract owner.
/// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner.
/// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership.
function transferOwnership(address newOwner) external;
/// @notice Gets the address of the contract owner.
/// @return contractOwner The address of the contract owner.
function owner() external view returns (address contractOwner);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IllegalInterfaceId} from "./../errors/InterfaceDetectionErrors.sol";
import {IERC165} from "./../interfaces/IERC165.sol";
library InterfaceDetectionStorage {
struct Layout {
mapping(bytes4 => bool) supportedInterfaces;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.introspection.InterfaceDetection.storage")) - 1);
bytes4 internal constant ILLEGAL_INTERFACE_ID = 0xffffffff;
/// @notice Sets or unsets an ERC165 interface.
/// @dev Revertswith {IllegalInterfaceId} if `interfaceId` is `0xffffffff`.
/// @param interfaceId the interface identifier.
/// @param supported True to set the interface, false to unset it.
function setSupportedInterface(Layout storage s, bytes4 interfaceId, bool supported) internal {
if (interfaceId == ILLEGAL_INTERFACE_ID) revert IllegalInterfaceId();
s.supportedInterfaces[interfaceId] = supported;
}
/// @notice Returns whether this contract implements a given interface.
/// @dev Note: This function call must use less than 30 000 gas.
/// @param interfaceId The interface identifier to test.
/// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported.
function supportsInterface(Layout storage s, bytes4 interfaceId) internal view returns (bool supported) {
if (interfaceId == ILLEGAL_INTERFACE_ID) {
return false;
}
if (interfaceId == type(IERC165).interfaceId) {
return true;
}
return s.supportedInterfaces[interfaceId];
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol";
import {ProxyInitialization} from "./../../../proxy/libraries/ProxyInitialization.sol";
library TokenMetadataStorage {
struct Layout {
string tokenName;
string tokenSymbol;
ITokenMetadataResolver tokenMetadataResolver;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.storage")) - 1);
bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.phase")) - 1);
/// @notice Initializes the metadata storage (immutable version).
/// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract.
/// @param tokenName The token name.
/// @param tokenSymbol The token symbol.
/// @param tokenMetadataResolver The address of the metadata resolver contract.
function constructorInit(
Layout storage s,
string memory tokenName,
string memory tokenSymbol,
ITokenMetadataResolver tokenMetadataResolver
) internal {
s.tokenName = tokenName;
s.tokenSymbol = tokenSymbol;
s.tokenMetadataResolver = tokenMetadataResolver;
}
/// @notice Initializes the metadata storage (proxied version).
/// @notice Sets the proxy initialization phase to `1`.
/// @dev Note: This function should be called ONLY in the init function of a proxied contract.
/// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above.
/// @param tokenName The token name.
/// @param tokenSymbol The token symbol.
/// @param tokenMetadataResolver The address of the metadata resolver contract.
function proxyInit(
Layout storage s,
string calldata tokenName,
string calldata tokenSymbol,
ITokenMetadataResolver tokenMetadataResolver
) internal {
ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1);
s.tokenName = tokenName;
s.tokenSymbol = tokenSymbol;
s.tokenMetadataResolver = tokenMetadataResolver;
}
/// @notice Gets the name of the token.
/// @return tokenName The name of the token contract.
function name(Layout storage s) internal view returns (string memory tokenName) {
return s.tokenName;
}
/// @notice Gets the symbol of the token.
/// @return tokenSymbol The symbol of the token contract.
function symbol(Layout storage s) internal view returns (string memory tokenSymbol) {
return s.tokenSymbol;
}
/// @notice Gets the address of the token metadata resolver.
/// @return tokenMetadataResolver The address of the token metadata resolver.
function metadataResolver(Layout storage s) internal view returns (ITokenMetadataResolver tokenMetadataResolver) {
return s.tokenMetadataResolver;
}
/// @notice Gets the token metadata URI retieved from the metadata resolver contract.
/// @param tokenContract The address of the token contract.
/// @param tokenId The ID of the token.
function tokenMetadataURI(Layout storage s, address tokenContract, uint256 tokenId) internal view returns (string memory) {
return s.tokenMetadataResolver.tokenMetadataURI(tokenContract, tokenId);
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when minting a token which has been burnt before (MintableOnce implementation). /// @param tokenId The identifier of the token that has been burnt before. error ERC721BurntToken(uint256 tokenId);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when minting a token to the zero address. error ERC721MintToAddressZero(); /// @notice Thrown when minting a token that already exists. /// @param tokenId The identifier of the token that already exists. error ERC721ExistingToken(uint256 tokenId);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, basic interface (functions).
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev This interface only contains the standard functions. See IERC721Events for the events.
/// @dev Note: The ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 {
/// @notice Sets or unsets an approval to transfer a single token on behalf of its owner.
/// @dev Note: There can only be one approved address per token at a given time.
/// @dev Note: A token approval gets reset when this token is transferred, including a self-transfer.
/// @dev Reverts if `tokenId` does not exist.
/// @dev Reverts if `to` is the token owner.
/// @dev Reverts if the sender is not the token owner and has not been approved by the token owner.
/// @dev Emits an {Approval} event.
/// @param to The address to approve, or the zero address to remove any existing approval.
/// @param tokenId The token identifier to give approval for.
function approve(address to, uint256 tokenId) external;
/// @notice Sets or unsets an approval to transfer all tokens on behalf of their owner.
/// @dev Reverts if the sender is the same as `operator`.
/// @dev Emits an {ApprovalForAll} event.
/// @param operator The address to approve for all tokens.
/// @param approved True to set an approval for all tokens, false to unset it.
function setApprovalForAll(address operator, bool approved) external;
/// @notice Unsafely transfers the ownership of a token to a recipient.
/// @dev Note: Usage of this method is discouraged, use `safeTransferFrom` whenever possible.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if `from` is not the owner of `tokenId`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Emits a {Transfer} event.
/// @param from The current token owner.
/// @param to The recipient of the token transfer. Self-transfers are possible.
/// @param tokenId The identifier of the token to transfer.
function transferFrom(address from, address to, uint256 tokenId) external;
/// @notice Safely transfers the ownership of a token to a recipient.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if `from` is not the owner of `tokenId`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event.
/// @param from The current token owner.
/// @param to The recipient of the token transfer.
/// @param tokenId The identifier of the token to transfer.
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/// @notice Safely transfers the ownership of a token to a recipient.
/// @dev Resets the token approval for `tokenId`.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if `from` is not the owner of `tokenId`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits a {Transfer} event.
/// @param from The current token owner.
/// @param to The recipient of the token transfer.
/// @param tokenId The identifier of the token to transfer.
/// @param data Optional data to send along to a receiver contract.
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/// @notice Gets the balance of an address.
/// @dev Reverts if `owner` is the zero address.
/// @param owner The address to query the balance of.
/// @return balance The amount owned by the owner.
function balanceOf(address owner) external view returns (uint256 balance);
/// @notice Gets the owner of a token.
/// @dev Reverts if `tokenId` does not exist.
/// @param tokenId The token identifier to query the owner of.
/// @return tokenOwner The owner of the token identifier.
function ownerOf(uint256 tokenId) external view returns (address tokenOwner);
/// @notice Gets the approved address for a token.
/// @dev Reverts if `tokenId` does not exist.
/// @param tokenId The token identifier to query the approval of.
/// @return approved The approved address for the token identifier, or the zero address if no approval is set.
function getApproved(uint256 tokenId) external view returns (address approved);
/// @notice Gets whether an operator is approved for all tokens by an owner.
/// @param owner The address which gives the approval for all tokens.
/// @param operator The address which receives the approval for all tokens.
/// @return approvedForAll Whether the operator is approved for all tokens by the owner.
function isApprovedForAll(address owner, address operator) external view returns (bool approvedForAll);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, optional extension: Batch Transfer.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0xf3993d11.
interface IERC721BatchTransfer {
/// @notice Unsafely transfers a batch of tokens to a recipient.
/// @dev Resets the token approval for each of `tokenIds`.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if one of `tokenIds` is not owned by `from`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for each of `tokenIds`.
/// @dev Emits an {IERC721-Transfer} event for each of `tokenIds`.
/// @param from Current tokens owner.
/// @param to Address of the new token owner.
/// @param tokenIds Identifiers of the tokens to transfer.
function batchTransferFrom(address from, address to, uint256[] calldata tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0x5b5e139f.
interface IERC721Metadata {
/// @notice Gets the name of the token. E.g. "My Token".
/// @return tokenName The name of the token.
function name() external view returns (string memory tokenName);
/// @notice Gets the symbol of the token. E.g. "TOK".
/// @return tokenSymbol The symbol of the token.
function symbol() external view returns (string memory tokenSymbol);
/// @notice Gets the metadata URI for a token identifier.
/// @dev Reverts if `tokenId` does not exist.
/// @param tokenId The token identifier.
/// @return uri The metadata URI for the token identifier.
function tokenURI(uint256 tokenId) external view returns (string memory uri);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC721Metadata} from "./../interfaces/IERC721Metadata.sol";
import {ERC721Storage} from "./../libraries/ERC721Storage.sol";
import {TokenMetadataStorage} from "./../../metadata/libraries/TokenMetadataStorage.sol";
import {TokenMetadataBase} from "./../../metadata/base/TokenMetadataBase.sol";
/// @title ERC721 Non-Fungible Token Standard, optional extension: Metadata (proxiable version).
/// @notice This contracts uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC721 (Non-Fungible Token Standard).
abstract contract ERC721MetadataBase is TokenMetadataBase, IERC721Metadata {
using ERC721Storage for ERC721Storage.Layout;
using TokenMetadataStorage for TokenMetadataStorage.Layout;
/// @inheritdoc IERC721Metadata
function name() public view virtual override(IERC721Metadata, TokenMetadataBase) returns (string memory tokenName) {
return TokenMetadataBase.name();
}
/// @inheritdoc IERC721Metadata
function symbol() public view virtual override(IERC721Metadata, TokenMetadataBase) returns (string memory tokenSymbol) {
return TokenMetadataBase.symbol();
}
/// @inheritdoc IERC721Metadata
function tokenURI(uint256 tokenId) external view virtual returns (string memory uri) {
ERC721Storage.layout().ownerOf(tokenId); // reverts if the token does not exist
return TokenMetadataStorage.layout().tokenMetadataURI(address(this), tokenId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, optional extension: Deliverable.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0x9da5e832.
interface IERC721Deliverable {
/// @notice Unsafely mints tokens to multiple recipients.
/// @dev Reverts if `recipients` and `tokenIds` have different lengths.
/// @dev Reverts if one of `recipients` is the zero address.
/// @dev Reverts if one of `tokenIds` already exists.
/// @dev Emits an {IERC721-Transfer} event from the zero address for each of `recipients` and `tokenIds`.
/// @param recipients Addresses of the new tokens owners.
/// @param tokenIds Identifiers of the tokens to mint.
function deliver(address[] calldata recipients, uint256[] calldata tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, optional extension: Burnable.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0x8b8b4ef5.
interface IERC721Burnable {
/// @notice Burns a token.
/// @dev Reverts if `tokenId` is not owned by `from`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
/// @dev Emits an {IERC721-Transfer} event with `to` set to the zero address.
/// @param from The current token owner.
/// @param tokenId The identifier of the token to burn.
function burnFrom(address from, uint256 tokenId) external;
/// @notice Burns a batch of tokens.
/// @dev Reverts if one of `tokenIds` is not owned by `from`.
/// @dev Reverts if the sender is not `from` and has not been approved by `from` for each of `tokenIds`.
/// @dev Emits an {IERC721-Transfer} event with `to` set to the zero address for each of `tokenIds`.
/// @param from The current tokens owner.
/// @param tokenIds The identifiers of the tokens to burn.
function batchBurnFrom(address from, uint256[] calldata tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, Tokens Receiver.
/// @notice Interface for supporting safe transfers from ERC721 contracts.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721Receiver {
/// @notice Handles the receipt of an ERC721 token.
/// @dev Note: This function is called by an ERC721 contract after a safe transfer.
/// @dev Note: The ERC721 contract address is always the message sender.
/// @param operator The initiator of the safe transfer.
/// @param from The previous token owner.
/// @param tokenId The token identifier.
/// @param data Optional additional data with no specified format.
/// @return magicValue `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` (`0x150b7a02`) to accept, any other value to refuse.
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC721 Non-Fungible Token Standard, optional extension: Mintable.
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev Note: The ERC-165 identifier for this interface is 0x8e773e13.
interface IERC721Mintable {
/// @notice Unsafely mints a token.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if `tokenId` already exists.
/// @dev Emits an {IERC721-Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
function mint(address to, uint256 tokenId) external;
/// @notice Safely mints a token.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if `tokenId` already exists.
/// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
/// @dev Emits an {IERC721-Transfer} event from the zero address.
/// @param to Address of the new token owner.
/// @param tokenId Identifier of the token to mint.
/// @param data Optional data to pass along to the receiver call.
function safeMint(address to, uint256 tokenId, bytes calldata data) external;
/// @notice Unsafely mints a batch of tokens.
/// @dev Reverts if `to` is the zero address.
/// @dev Reverts if one of `tokenIds` already exists.
/// @dev Emits an {IERC721-Transfer} event from the zero address for each of `tokenIds`.
/// @param to Address of the new tokens owner.
/// @param tokenIds Identifiers of the tokens to mint.
function batchMint(address to, uint256[] calldata tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC173} from "./../interfaces/IERC173.sol";
import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/// @title ERC173 Contract Ownership Standard (proxiable version).
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
abstract contract ContractOwnershipBase is IERC173, Context {
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
/// @inheritdoc IERC173
function owner() public view virtual returns (address) {
return ContractOwnershipStorage.layout().owner();
}
/// @inheritdoc IERC173
function transferOwnership(address newOwner) public virtual {
ContractOwnershipStorage.layout().transferOwnership(_msgSender(), newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC2981} from "./../interfaces/IERC2981.sol";
import {ERC2981Storage} from "./../libraries/ERC2981Storage.sol";
import {ContractOwnershipStorage} from "./../../../access/libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
/// @title ERC2981 NFT Royalty Standard (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract ERC2981Base is Context, IERC2981 {
using ERC2981Storage for ERC2981Storage.Layout;
using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
uint256 public constant ROYALTY_FEE_DENOMINATOR = ERC2981Storage.ROYALTY_FEE_DENOMINATOR;
/// @notice Sets the royalty percentage.
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Reverts with {IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR).
/// @param percentage The new percentage to set. For example 50000 sets 50% royalty.
function setRoyaltyPercentage(uint256 percentage) external virtual {
ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
ERC2981Storage.layout().setRoyaltyPercentage(percentage);
}
/// @notice Sets the royalty receiver.
/// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
/// @dev Reverts with {IncorrectRoyaltyReceiver} if `receiver` is the zero address.
/// @param receiver The new receiver to set.
function setRoyaltyReceiver(address receiver) external virtual {
ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
ERC2981Storage.layout().setRoyaltyReceiver(receiver);
}
/// @inheritdoc IERC2981
function royaltyInfo(uint256 tokenId, uint256 salePrice) external view virtual returns (address receiver, uint256 royaltyAmount) {
return ERC2981Storage.layout().royaltyInfo(tokenId, salePrice);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ERC2981IncorrectRoyaltyReceiver, ERC2981IncorrectRoyaltyPercentage} from "./../errors/ERC2981Errors.sol";
import {IERC2981} from "./../interfaces/IERC2981.sol";
import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol";
library ERC2981Storage {
using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;
struct Layout {
address royaltyReceiver;
uint96 royaltyPercentage;
}
bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.ERC2981.storage")) - 1);
uint256 internal constant ROYALTY_FEE_DENOMINATOR = 100000;
/// @notice Marks the following ERC165 interface(s) as supported: ERC2981.
function init() internal {
InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC2981).interfaceId, true);
}
/// @notice Sets the royalty percentage.
/// @dev Reverts with {ERC2981IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR).
/// @param percentage The new percentage to set. For example 50000 sets 50% royalty.
function setRoyaltyPercentage(Layout storage s, uint256 percentage) internal {
if (percentage > ROYALTY_FEE_DENOMINATOR) {
revert ERC2981IncorrectRoyaltyPercentage(percentage);
}
s.royaltyPercentage = uint96(percentage);
}
/// @notice Sets the royalty receiver.
/// @dev Reverts with {ERC2981IncorrectRoyaltyReceiver} if `receiver` is the zero address.
/// @param receiver The new receiver to set.
function setRoyaltyReceiver(Layout storage s, address receiver) internal {
if (receiver == address(0)) {
revert ERC2981IncorrectRoyaltyReceiver();
}
s.royaltyReceiver = receiver;
}
/// @notice Called with the sale price to determine how much royalty is owed and to whom.
// / @param tokenId The NFT asset queried for royalty information
/// @param salePrice The sale price of the NFT asset specified by `tokenId`
/// @return receiver Address of who should be sent the royalty payment
/// @return royaltyAmount The royalty payment amount for `salePrice`
function royaltyInfo(Layout storage s, uint256, uint256 salePrice) internal view returns (address receiver, uint256 royaltyAmount) {
receiver = s.royaltyReceiver;
uint256 royaltyPercentage = s.royaltyPercentage;
if (salePrice == 0 || royaltyPercentage == 0) {
royaltyAmount = 0;
} else {
if (salePrice < ROYALTY_FEE_DENOMINATOR) {
royaltyAmount = (salePrice * royaltyPercentage) / ROYALTY_FEE_DENOMINATOR;
} else {
royaltyAmount = (salePrice / ROYALTY_FEE_DENOMINATOR) * royaltyPercentage;
}
}
}
function layout() internal pure returns (Layout storage s) {
bytes32 position = LAYOUT_STORAGE_SLOT;
assembly {
s.slot := position
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC165 Interface Detection Standard.
/// @dev See https://eips.ethereum.org/EIPS/eip-165.
/// @dev Note: The ERC-165 identifier for this interface is 0x01ffc9a7.
interface IERC165 {
/// @notice Returns whether this contract implements a given interface.
/// @dev Note: This function call must use less than 30 000 gas.
/// @param interfaceId the interface identifier to test.
/// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported.
function supportsInterface(bytes4 interfaceId) external view returns (bool supported);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "./../../token/ERC721/interfaces/IERC721.sol";
/// @title Uniquely identified seals management.
interface ITokenRecovery {
/// @notice Extract ETH tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Note: While contracts can generally prevent accidental ETH transfer by implementating a reverting
/// `receive()` function, this can still be bypassed in a `selfdestruct(address)` scenario.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ETH tokens
/// so that the extraction is limited to only amounts sent accidentally.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param amounts the list of token amounts to transfer.
function recoverETH(address payable[] calldata accounts, uint256[] calldata amounts) external;
/// @notice Extract ERC20 tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC20 tokens
/// so that the extraction is limited to only amounts sent accidentally.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param tokens the list of ERC20 token addresses.
/// @param amounts the list of token amounts to transfer.
function recoverERC20s(address[] calldata accounts, IERC20[] calldata tokens, uint256[] calldata amounts) external;
/// @notice Extract ERC721 tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC721 tokens
/// so that the extraction is limited to only tokens sent accidentally.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param contracts the list of ERC721 contract addresses.
/// @param tokenIds the list of token ids to transfer.
function recoverERC721s(address[] calldata accounts, IERC721[] calldata contracts, uint256[] calldata tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {InconsistentArrayLengths} from "./../../CommonErrors.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "./../../token/ERC721/interfaces/IERC721.sol";
import {IERC165} from "./../../introspection/interfaces/IERC165.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
library TokenRecoveryLibrary {
using SafeERC20 for IERC20;
using Address for address payable;
/// @notice Thrown when trying to recover a token of the wrong contract type.
/// @param tokenContract The token contract being recovered.
error IncorrectTokenContractType(address tokenContract);
/// @notice Extract ETH tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Note: While contracts can generally prevent accidental ETH transfer by implementating a reverting
/// `receive()` function, this can still be bypassed in a `selfdestruct(address)` scenario.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ETH tokens
/// so that the extraction is limited to only amounts sent accidentally.
/// @dev Reverts with {InconsistentArrayLengths} `accounts` and `amounts` do not have the same length.
/// @dev Reverts if one of the ETH transfers fails for any reason.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param amounts the list of token amounts to transfer.
function recoverETH(address payable[] calldata accounts, uint256[] calldata amounts) internal {
uint256 length = accounts.length;
if (length != amounts.length) revert InconsistentArrayLengths();
for (uint256 i; i < length; ++i) {
accounts[i].sendValue(amounts[i]);
}
}
/// @notice Extract ERC20 tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC20 tokens
/// so that the extraction is limited to only amounts sent accidentally.
/// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `tokens` and `amounts` do not have the same length.
/// @dev Reverts if one of the ERC20 transfers fails for any reason.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param tokens the list of ERC20 token addresses.
/// @param amounts the list of token amounts to transfer.
function recoverERC20s(address[] calldata accounts, IERC20[] calldata tokens, uint256[] calldata amounts) internal {
uint256 length = accounts.length;
if (length != tokens.length || length != amounts.length) revert InconsistentArrayLengths();
for (uint256 i; i < length; ++i) {
tokens[i].safeTransfer(accounts[i], amounts[i]);
}
}
/// @notice Extract ERC721 tokens which were accidentally sent to the contract to a list of accounts.
/// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC721 tokens
/// so that the extraction is limited to only tokens sent accidentally.
/// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `contracts` and `amounts` do not have the same length.
/// @dev Reverts if one of the ERC721 transfers fails for any reason.
/// @param accounts the list of accounts to transfer the tokens to.
/// @param contracts the list of ERC721 contract addresses.
/// @param tokenIds the list of token ids to transfer.
function recoverERC721s(address[] calldata accounts, IERC721[] calldata contracts, uint256[] calldata tokenIds) internal {
uint256 length = accounts.length;
if (length != contracts.length || length != tokenIds.length) revert InconsistentArrayLengths();
for (uint256 i; i < length; ++i) {
IERC721 tokenContract = contracts[i];
if (!IERC165(address(tokenContract)).supportsInterface(type(IERC721).interfaceId)) {
revert IncorrectTokenContractType(address(tokenContract));
}
contracts[i].safeTransferFrom(address(this), accounts[i], tokenIds[i]);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Emitted when trying to set a phase value that has already been reached. /// @param currentPhase The current phase. /// @param newPhase The new phase trying to be set. error InitializationPhaseAlreadyReached(uint256 currentPhase, uint256 newPhase);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when setting the illegal interfaceId 0xffffffff. error IllegalInterfaceId();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol";
import {TokenMetadataStorage} from "./../libraries/TokenMetadataStorage.sol";
/// @title TokenMetadataBase (proxiable version).
/// @notice Provides metadata management for token contracts (ERC721/ERC1155) which uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in a proxied implementation.
abstract contract TokenMetadataBase {
using TokenMetadataStorage for TokenMetadataStorage.Layout;
/// @notice Gets the token name. E.g. "My Token".
/// @return tokenName The token name.
function name() public view virtual returns (string memory tokenName) {
return TokenMetadataStorage.layout().name();
}
/// @notice Gets the token symbol. E.g. "TOK".
/// @return tokenSymbol The token symbol.
function symbol() public view virtual returns (string memory tokenSymbol) {
return TokenMetadataStorage.layout().symbol();
}
/// @notice Gets the token metadata resolver address.
/// @return tokenMetadataResolver The token metadata resolver address.
function metadataResolver() external view virtual returns (ITokenMetadataResolver tokenMetadataResolver) {
return TokenMetadataStorage.layout().metadataResolver();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title ERC2981 NFT Royalty Standard.
/// @dev See https://eips.ethereum.org/EIPS/eip-2981
/// @dev Note: The ERC-165 identifier for this interface is 0x2a55205a.
interface IERC2981 {
/// @notice Called with the sale price to determine how much royalty is owed and to whom.
/// @param tokenId The NFT asset queried for royalty information
/// @param salePrice The sale price of the NFT asset specified by `tokenId`
/// @return receiver Address of who should be sent the royalty payment
/// @return royaltyAmount The royalty payment amount for `salePrice`
function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice Thrown when setting a royalty percentage that is above 100% (> FEE_DENOMINATOR). /// @param percentage The royalty percentage that was attempted to be set. error ERC2981IncorrectRoyaltyPercentage(uint256 percentage); /// @notice Thrown when setting a royalty receiver that is the zero address. error ERC2981IncorrectRoyaltyReceiver();
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"optimizer": {
"enabled": true,
"mode": "3"
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": false,
"codegen": "yul",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"contract ITokenMetadataResolver","name":"metadataResolver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"ERC2981IncorrectRoyaltyPercentage","type":"error"},{"inputs":[],"name":"ERC2981IncorrectRoyaltyReceiver","type":"error"},{"inputs":[],"name":"ERC721BalanceOfAddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721ExistingToken","type":"error"},{"inputs":[],"name":"ERC721MintToAddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonApprovedForApproval","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonApprovedForTransfer","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonExistingToken","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonOwnedToken","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721SafeTransferRejected","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ERC721SelfApproval","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ERC721SelfApprovalForAll","type":"error"},{"inputs":[],"name":"ERC721TransferToAddressZero","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"IllegalInterfaceId","type":"error"},{"inputs":[],"name":"InconsistentArrayLengths","type":"error"},{"inputs":[{"internalType":"address","name":"tokenContract","type":"address"}],"name":"IncorrectTokenContractType","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotContractOwner","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"NotRoleHolder","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"PendingScratchRequest","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IScratching","name":"scratchingContract","type":"address"}],"name":"ScratchingContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"approved","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"hasRole_","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":"approvedForAll","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataResolver","outputs":[{"internalType":"contract ITokenMetadataResolver","name":"tokenMetadataResolver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"tokenName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"tokenOwner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverERC20s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC721[]","name":"contracts","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"recoverERC721s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","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":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scratchingContract","outputs":[{"internalType":"contract IScratching","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"setRoyaltyPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setRoyaltyReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IScratching","name":"scratching","type":"address"}],"name":"setScratchingContract","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":"tokenSymbol","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
9c4d535b00000000000000000000000000000000000000000000000000000000000000000100040b6abbfe684f22fd90a517251b77a10270bf1e49758d199e0e6c15f28e000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000006aa75ad1fe433cf6eb83436e3fdfd02999638f2d0000000000000000000000000000000000000000000000000000000000000013416e6963686573732050656e6775426f61726400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a50454e4755424f41524400000000000000000000000000000000000000000000
Deployed Bytecode
0x00010000000000020009000000000002000000000301034f00000000000103550000008004000039000000400040043f000000600110027000000377011001970000000100200190000000ad0000c13d000000040010008c000000cc0000413d000000000203043b000000e002200270000003960020009c000001150000a13d000003970020009c000001950000a13d000003980020009c000001cc0000a13d000003990020009c0000031e0000a13d0000039a0020009c000007b30000613d0000039b0020009c000004c10000613d0000039c0020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000402300370000000000202043b0000037a0020009c000000cc0000213d0000002304200039000000000014004b000000cc0000813d0000000404200039000000000443034f000000000404043b000600000004001d0000037a0040009c000000cc0000213d000500240020003d000000060200002900000005022002100000000502200029000000000012004b000000cc0000213d0000002402300370000000000402043b0000037a0040009c000000cc0000213d0000002302400039000000000012004b000000cc0000813d0000000402400039000000000223034f000000000202043b0000037a0020009c000000cc0000213d000400240040003d00000005032002100000000403300029000000000013004b000000cc0000213d00000000010004110000037f011001970000038e03000041000000000303041a0000037f03300197000000000031004b000008490000c13d000000060020006b00000ac20000c13d000000060000006b0000078b0000613d0000000003000019000000050130021000000005021000290000000002200367000000000202043b000800000002001d0000037f0020009c000000cc0000213d000700000003001d00000004011000290000000001100367000000000101043b000900000001001d000003c7010000410000000000100443000000000100041000000004001004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c70000800a020000390dd70dd20000040f0000000100200190000009610000613d000000000101043b0000000903000029000000000031004b00000b420000413d00000008010000290000037f041001970000000001000414000003770010009c0000037701008041000000c001100210000000000003004b0000007a0000613d0000038f011001c7000080090200003900000000050000190000007b0000013d00000000020400190dd70dcd0000040f0000006003100270000003770530019800000080040000390000006003000039000000a60000613d0000001f0350003900000378033001970000003f03300039000003c904300197000000400300043d0000000004430019000000000034004b000000000600003900000001060040390000037a0040009c0000010f0000213d00000001006001900000010f0000c13d000000400040043f000000000453043600000379075001980000000006740019000000990000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000069004b000000950000c13d0000001f05500190000000a60000613d000000000171034f0000000305500210000000000706043300000000075701cf000000000757022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000171019f0000000000160435000000010020019000000b4d0000613d00000007030000290000000103300039000000060030006c000000510000413d0000078b0000013d0000000002000416000000000002004b000000cc0000c13d0000001f0210003900000378022001970000008002200039000000400020043f0000001f0510018f00000379061001980000008002600039000000bd0000613d000000000703034f000000007807043c0000000004840436000000000024004b000000b90000c13d000000000005004b000000ca0000613d000000000363034f0000000304500210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000600010008c000000ce0000813d000000000100001900000dd900010430000000800400043d0000037a0040009c000000cc0000213d00000080021000390000009f03400039000000000023004b000000cc0000813d000000800340003900000000030304330000037b0030009c0000010f0000813d0000001f053000390000037c055001970000003f055000390000037d05500197000000400700043d0000000005570019000000000075004b000000000600003900000001060040390000037a0050009c0000010f0000213d00000001006001900000010f0000c13d000000400050043f000900000007001d0000000005370436000800000005001d000000a0044000390000000005430019000000000025004b000000cc0000213d000000000003004b0000000808000029000000f90000613d000000000500001900000000065800190000000007450019000000000707043300000000007604350000002005500039000000000035004b000000f20000413d000000090330002900000020033000390000000000030435000000a00300043d0000037a0030009c000000cc0000213d0000001f04300039000000000014004b00000000010000190000037e010080410000037e04400197000000000004004b00000000050000190000037e050040410000037e0040009c000000000501c019000000000005004b000000cc0000c13d000000800130003900000000010104330000037a0010009c000007fb0000a13d0000039401000041000000000010043f0000004101000039000000040010043f000003950100004100000dd900010430000003af0020009c000001240000213d000003bb0020009c000002ab0000213d000003c10020009c000003290000213d000003c40020009c000004e20000613d000003c50020009c000000cc0000c13d0000000001000416000000000001004b000000cc0000c13d0000038301000041000003030000013d000003b00020009c000002c10000213d000003b60020009c000003500000213d000003b90020009c000004f00000613d000003ba0020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000900000001001d000003d401000041000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b00000000020004110000037f02200197000800000002001d000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff00100190000002f10000613d0000000901000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0008037f0010019c000007640000613d0000000901000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000003f602000041000000000021041b0000000801000029000000000010043f000003ec01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d020000390000000403000039000003ef040000410000000805000029000000000600001900000009070000290dd70dcd0000040f0000000100200190000000cc0000613d0000078b0000013d000003a40020009c000002f90000213d000003aa0020009c0000048c0000213d000003ad0020009c000007c40000613d000003ae0020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000900000001001d000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b00000000020004110000037f02200197000800000002001d000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff00100190000008860000c13d000003e701000041000000000010043f0000000901000029000000040010043f0000000001000411000000240010043f000003cd0100004100000dd9000104300000039f0020009c000003130000213d000003a20020009c0000058c0000613d000003a30020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000640010008c000000cc0000413d0000000402300370000000000202043b0000037a0020009c000000cc0000213d0000002304200039000000000014004b000000cc0000813d0000000404200039000000000443034f000000000404043b000700000004001d0000037a0040009c000000cc0000213d000300240020003d000000070200002900000005022002100000000302200029000000000012004b000000cc0000213d0000002402300370000000000402043b0000037a0040009c000000cc0000213d0000002302400039000000000012004b000000cc0000813d0000000402400039000000000223034f000000000202043b0000037a0020009c000000cc0000213d000200240040003d00000005042002100000000204400029000000000014004b000000cc0000213d0000004404300370000000000404043b0000037a0040009c000000cc0000213d0000002305400039000000000015004b000000cc0000813d0000000405400039000000000353034f000000000303043b0000037a0030009c000000cc0000213d000100240040003d00000005043002100000000104400029000000000014004b000000cc0000213d00000000010004110000037f011001970000038e04000041000000000404041a0000037f04400197000000000041004b000008490000c13d000000070020006b00000ac20000c13d000000070030006b00000ac20000c13d000000070000006b0000078b0000613d00000080030000390000008405000039000800000000001d0000000802000029000000070020006c00000bbd0000813d00000005042002100000000201400029000400000001001d0000000001100367000000000201043b0000037f0020009c000000cc0000213d000600000004001d000003d801000041000000000013043500000380010000410000000000150435000003770030009c0000037701000041000000000103401900000040011002100000000004000414000003770040009c0000037704008041000000c004400210000000000114019f00000395011001c7000500000002001d000900000003001d0dd70dd20000040f000000090a00002900000060031002700000037703300197000000200030008c00000020040000390000000004034019000000200640019000000000056a0019000002470000613d000000000701034f00000000080a0019000000007907043c0000000008980436000000000058004b000002430000c13d0000001f07400190000002540000613d000000000661034f0000000307700210000000000805043300000000087801cf000000000878022f000000000606043b0000010007700089000000000676022f00000000067601cf000000000686019f0000000000650435000000010020019000000bcf0000613d0000001f01400039000000600110018f0000000001a100190000037a0010009c0000010f0000213d000000400010043f000000200030008c00000006030000290000000502000029000000cc0000413d00000000010a0433000000010010008c000000cc0000213d000000000001004b00000bdb0000613d00000000010003670000000402100360000000000402043b0000037f0040009c000000cc0000213d0000000302300029000000000221034f000000000202043b000900000002001d0000037f0020009c000000cc0000213d0000000102300029000000000121034f000000000101043b000500000001001d000003d9010000410000000000100443000600000004001d00000004004004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c700008002020000390dd70dd20000040f0000000100200190000009610000613d000000000101043b000000000001004b0000000602000029000000cc0000613d000000400400043d000000440140003900000005030000290000000000310435000000240140003900000009030000290000000000310435000003da01000041000000000014043500000004034000390000000001000410000500000003001d0000000000130435000003770040009c000900000004001d0000037701000041000000000104401900000040011002100000000003000414000003770030009c0000037703008041000000c003300210000000000113019f000003db011001c70dd70dcd0000040f000000010020019000000bdd0000613d00000009030000290000037a0030009c0000010f0000213d000000400030043f00000008020000290000000102200039000800000002001d000000070020006c00000005050000290000021c0000413d0000078b0000013d000003bc0020009c000003660000213d000003bf0020009c000006540000613d000003c00020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d0dd70c0b0000040f000900000001001d000800000002001d0000000001030019000700000003001d0dd70c1d0000040f00000000010004110000000902000029000000080300002900000007040000290dd70c910000040f000000000100001900000dd80001042e000003b10020009c000003d20000213d000003b40020009c000006590000613d000003b50020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000037f0010009c000000cc0000213d000003d401000041000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b00000000020004110000037f02200197000800000002001d000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff00100190000009620000c13d000003e701000041000000000010043f000003d401000041000000040010043f0000000801000029000000240010043f000003cd0100004100000dd900010430000003a50020009c000004a60000213d000003a80020009c000007cb0000613d000003a90020009c000000cc0000c13d0000000001000416000000000001004b000000cc0000c13d00000388010000410dd70d5f0000040f0000002002000039000000400300043d000900000003001d00000000022304360dd70bf90000040f00000009020000290000000001210049000003770010009c00000377010080410000006001100210000003770020009c00000377020080410000004002200210000000000121019f00000dd80001042e000003a00020009c000006630000613d000003a10020009c000000cc0000c13d0000000001000416000000000001004b000000cc0000c13d000003d401000041000000800010043f000003cf0100004100000dd80001042e0000039d0020009c000006ed0000613d0000039e0020009c000000cc0000c13d0000000001000416000000000001004b000000cc0000c13d000003d001000041000000800010043f000003cf0100004100000dd80001042e000003c20020009c0000074c0000613d000003c30020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000037f0010009c000000cc0000213d0000002401300370000000000101043b000800000001001d000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0000037f03100198000008b90000c13d000003d701000041000000000010043f0000000801000029000000040010043f000003950100004100000dd900010430000003b70020009c0000076a0000613d000003b80020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b00000000020004110000037f022001970000038e03000041000000000303041a0000037f03300197000000000032004b000007f60000c13d000003f20010009c0000084e0000413d000003f3020000410000084a0000013d000003bd0020009c0000078d0000613d000003be0020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000002401300370000000000101043b000800000001001d0000037f0010009c000000cc0000213d00000000010004110000037f011001970000038e02000041000000000202041a0000037f02200197000000000021004b000008490000c13d000700000002001d0000000901000029000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff001001900000078b0000c13d0000000901000029000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a000004010220019700000001022001bf000000000021041b000000400100043d00000040021000390000000703000029000000000032043500000020021000390000000803000029000000000032043500000009020000290000000000210435000003770010009c000003770100804100000040011002100000000002000414000003770020009c0000037702008041000000c002200210000000000112019f000003d2011001c70000800d020000390000000103000039000003f804000041000007880000013d000003b20020009c000007a40000613d000003b30020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000640010008c000000cc0000413d0000000402300370000000000202043b0000037a0020009c000000cc0000213d0000002304200039000000000014004b000000cc0000813d0000000404200039000000000443034f000000000404043b000800000004001d0000037a0040009c000000cc0000213d000600240020003d000000080200002900000005022002100000000602200029000000000012004b000000cc0000213d0000002402300370000000000402043b0000037a0040009c000000cc0000213d0000002302400039000000000012004b000000cc0000813d0000000402400039000000000223034f000000000202043b0000037a0020009c000000cc0000213d000500240040003d00000005042002100000000504400029000000000014004b000000cc0000213d0000004404300370000000000404043b0000037a0040009c000000cc0000213d0000002305400039000000000015004b000000cc0000813d0000000405400039000000000353034f000000000303043b0000037a0030009c000000cc0000213d000400240040003d00000005043002100000000404400029000000000014004b000000cc0000213d00000000010004110000037f011001970000038e04000041000000000404041a0000037f04400197000000000041004b000008490000c13d000000080020006b00000ac20000c13d000000080030006b00000ac20000c13d000000080000006b0000078b0000613d0000000004000019000004280000013d000000000100043d000000010010008c00000000010000390000000101006039000000000001004b0000048a0000613d0000000104400039000000080040006c0000078b0000813d000000080040006c00000bbd0000813d000000050140021000000005031000290000000005000367000000000335034f000000000203043b0000037f0020009c000000cc0000213d0000000603100029000000000335034f000000000303043b0000037f0030009c000000cc0000213d000900000004001d0000000401100029000000000115034f000000000501043b000000400100043d000000440410003900000000005404350000002005100039000003e80400004100000000004504350000002404100039000000000034043500000044030000390000000000310435000003e90010009c0000010f0000213d0000008003100039000000400030043f000003770050009c000003770500804100000040035002100000000001010433000003770010009c00000377010080410000006001100210000000000131019f0000000003000414000003770030009c0000037703008041000000c003300210000000000131019f000700000002001d0dd70dcd0000040f00000060031002700000037703300197000000200030008c000000200500003900000000050340190000002004500190000004640000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b000004600000c13d0000001f05500190000004710000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000000010020019000000bc30000613d00000007010000290000037f02100197000000000003004b00000009040000290000041f0000c13d000003d9010000410000000000100443000700000002001d00000004002004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c700008002020000390dd70dd20000040f0000000100200190000009610000613d000000000101043b00000009040000290000000702000029000000000001004b000004250000c13d000003ea01000041000007f70000013d000003ab0020009c000007e80000613d000003ac0020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b0000037f0010009c000000cc0000213d00000000020004110000037f022001970000038e03000041000000000303041a0000037f03300197000000000032004b000007f60000c13d000000000001004b000008be0000c13d000003e601000041000000000010043f000003cb0100004100000dd900010430000003a60020009c000007ed0000613d000003a70020009c000000cc0000c13d0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000037f0010009c000000cc0000213d0000002401300370000000000101043b000000000001004b0000000002000039000000010200c039000800000002001d000000010010008c000000cc0000213d0000000002000411000000090020006b000008c50000c13d000003e401000041000007f70000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000601043b0000037f0060009c000000cc0000213d0000038e01000041000000000101041a0000037f021001970000000005000411000000000025004b000008530000c13d000000000065004b0000078b0000613d0000038c01100197000000000161019f0000038e02000041000000000012041b0000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d02000039000000030300003900000390040000410dd70dcd0000040f0000000100200190000000cc0000613d0000078b0000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000003e100100198000000cc0000c13d0000008002000039000004000010009c000008580000a13d00000000010000190000095a0000013d0000000002000416000000000002004b000000cc0000c13d000000640010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000037f0010009c000000cc0000213d0000002401300370000000000101043b000800000001001d0000037f0010009c000000cc0000213d0000004401300370000000000401043b0000000101000039000000000101041a0000037f02100198000700000004001d000008f90000c13d0000000001000411000000090200002900000008030000290dd70c910000040f000003d9010000410000000000100443000000080100002900000004001004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c700008002020000390dd70dd20000040f0000000100200190000009610000613d000000000101043b000000000001004b0000078b0000613d000000400200043d000003f70020009c0000010f0000213d0000002001200039000000400010043f0000000000020435000000400500043d000000640350003900000080040000390000000000430435000000440350003900000007040000290000000000430435000000240350003900000009040000290000000000430435000003e003000041000000000035043500000000030004110000037f0330019700000004045000390000000000340435000000000202043300000084035000390000000000230435000600000005001d000000a403500039000000000002004b0000053f0000613d000000000400001900000000053400190000000006140019000000000606043300000000006504350000002004400039000000000024004b000005380000413d0000001f01200039000004020110019700000000023200190000000000020435000000a401100039000003770010009c000003770100804100000060011002100000000602000029000003770020009c00000377020080410000004002200210000000000121019f0000000002000414000003770020009c0000037702008041000000c002200210000000000112019f00000008020000290dd70dcd0000040f00000060031002700000037703300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000605700029000005620000613d000000000801034f0000000609000029000000008a08043c0000000009a90436000000000059004b0000055e0000c13d000000000006004b0000056f0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000a830000613d0000001f01400039000000600210018f0000000601200029000000000021004b000000000200003900000001020040390000037a0010009c0000010f0000213d00000001002001900000010f0000c13d000000400010043f000000200030008c000000cc0000413d00000006010000290000000001010433000003e100100198000000cc0000c13d000003e00010009c0000078b0000613d000003e201000041000000000010043f0000000801000029000000040010043f0000000701000029000000240010043f000003cd0100004100000dd9000104300000000002000416000000000002004b000000cc0000c13d000000840010008c000000cc0000413d0000000402300370000000000202043b000900000002001d0000037f0020009c000000cc0000213d0000002402300370000000000202043b000800000002001d0000037f0020009c000000cc0000213d0000004402300370000000000202043b000700000002001d0000006402300370000000000202043b0000037a0020009c000000cc0000213d0000002304200039000000000014004b000000cc0000813d000500040020003d0000000503300360000000000303043b000600000003001d0000037a0030009c000000cc0000213d00000006022000290000002402200039000000000012004b000000cc0000213d0000000101000039000000000101041a0000037f0210019800000a070000c13d00000000010004110000000902000029000000080300002900000007040000290dd70c910000040f000003d9010000410000000000100443000000080100002900000004001004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c700008002020000390dd70dd20000040f0000000100200190000009610000613d000000000101043b000000000001004b0000078b0000613d00000006010000290000001f011000390000037c011001970000003f011000390000037d01100197000000400300043d0000000001130019000000000031004b000000000200003900000001020040390000037a0010009c0000010f0000213d00000001002001900000010f0000c13d000000400010043f0000000604000029000000000243043600000402054001980000001f0640018f0000000004520019000000050700002900000020077000390000000007700367000005e60000613d000000000807034f0000000009020019000000008a08043c0000000009a90436000000000049004b000005e20000c13d000000000006004b000005f30000613d000000000557034f0000000306600210000000000704043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f000000000054043500000006042000290000000000040435000000400600043d000000640460003900000080050000390000000000540435000000440460003900000007050000290000000000540435000000240460003900000009050000290000000000540435000003e004000041000000000046043500000000040004110000037f0440019700000004056000390000000000450435000000000303043300000084046000390000000000340435000600000006001d000000a404600039000000000003004b000006140000613d000000000500001900000000064500190000000007250019000000000707043300000000007604350000002005500039000000000035004b0000060d0000413d0000001f02300039000004020120019700000000024300190000000000020435000000a401100039000003770010009c000003770100804100000060011002100000000602000029000003770020009c00000377020080410000004002200210000000000121019f0000000002000414000003770020009c0000037702008041000000c002200210000000000112019f00000008020000290dd70dcd0000040f00000060031002700000037703300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000605700029000006370000613d000000000801034f0000000609000029000000008a08043c0000000009a90436000000000059004b000006330000c13d000000000006004b000006440000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000ad50000613d0000001f01400039000000600210018f0000000601200029000000000021004b000000000200003900000001020040390000037a0010009c0000010f0000213d00000001002001900000010f0000c13d000000400010043f000000200030008c0000057e0000813d000000cc0000013d0000000001000416000000000001004b000000cc0000c13d0000000101000039000007f10000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b0dd70d440000040f000000400200043d0000095b0000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000900000001001d000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0000037f00100198000007640000613d0000038b01000041000000000201041a000000400400043d000000240140003900000009030000290000000000310435000003d601000041000000000014043500000000010004100000037f0110019700000004034000390000000000130435000003770040009c000900000004001d0000037701000041000000000104401900000040011002100000000003000414000003770030009c0000037703008041000000c003300210000000000113019f000003cd011001c70000037f022001970dd70dd20000040f00000060031002700000001f0430018f000003790530019700000377033001970000000100200190000009300000613d00000009090000290000000002590019000000000005004b000006a40000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000027004b000006a00000c13d000000000004004b000006b10000613d000000000151034f0000000304400210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001204350000001f0130003900000378021001970000000001920019000000000021004b000000000200003900000001020040390000037a0010009c0000010f0000213d00000001002001900000010f0000c13d000000400010043f000000200030008c000000cc0000413d00000000020904330000037a0020009c000000cc0000213d000000000493001900000000029200190000001f03200039000000000043004b00000000050000190000037e050080410000037e033001970000037e06400197000000000763013f000000000063004b00000000030000190000037e030040410000037e0070009c000000000305c019000000000003004b000000cc0000c13d00000000320204340000037a0020009c0000010f0000213d0000001f052000390000037c055001970000003f055000390000037d0550019700000000051500190000037a0050009c0000010f0000213d000000400050043f00000000052104360000000006230019000000000046004b000000cc0000213d000000000002004b000006ea0000613d000000000400001900000000065400190000000007430019000000000707043300000000007604350000002004400039000000000024004b000006e30000413d00000000025200190000000000020435000003040000013d0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000401300370000000000101043b000900000001001d0000002401300370000000000101043b000800000001001d0000037f0010009c000000cc0000213d00000000010004110000037f011001970000038e02000041000000000202041a0000037f02200197000000000021004b000008490000c13d000700000002001d0000000901000029000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff001001900000078b0000613d0000000901000029000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a0000040102200197000000000021041b000000400100043d00000040021000390000000703000029000000000032043500000020021000390000000803000029000000000032043500000009020000290000000000210435000003770010009c000003770100804100000040011002100000000002000414000008b00000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b000900000001001d000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0000037f001001980000085c0000c13d000003d701000041000000000010043f0000000901000029000000040010043f000003950100004100000dd9000104300000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b0000037f0010009c000000cc0000213d00000000020004110000037f022001970000038e03000041000000000303041a0000037f03300197000000000032004b000007f60000c13d0000037f021001970000000103000039000000000403041a0000038c04400197000000000114019f000000000013041b000000800020043f0000000001000414000003770010009c0000037701008041000000c001100210000003f4011001c70000800d02000039000003f5040000410dd70dcd0000040f0000000100200190000000cc0000613d000000000100001900000dd80001042e0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d000003e501000041000000000101041a0000002402300370000000000302043b000000000003004b0000086f0000613d0000037f0010009c0000000002000019000008780000a13d000000a004100270000003d00030009c000008710000413d000003d00330012a00000000023400a900000000033200d9000000000043004b000008780000613d000009650000013d0000000002000416000000000002004b000000cc0000c13d000000240010008c000000cc0000413d0000000401300370000000000101043b0000037f0010009c000000cc0000213d000000000001004b0000087d0000c13d000003ed01000041000000000010043f000003cb0100004100000dd9000104300000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000000401300370000000000101043b0000037f0010009c000000cc0000213d0000002402300370000000000202043b000900000002001d0000037f0020009c000000cc0000213d000000000010043f000003ce01000041000007d90000013d0000000001000416000000000001004b000000cc0000c13d000000000100041a000000800010043f000003cf0100004100000dd80001042e0000000002000416000000000002004b000000cc0000c13d000000440010008c000000cc0000413d0000002401300370000000000101043b000900000001001d0000037f0010009c000000cc0000213d0000000401300370000000000101043b000000000010043f000003d101000041000000200010043f00000040010000390dd70dad0000040f0000000902000029000000000020043f000000200010043f00000040010000390dd70dad0000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f000003cf0100004100000dd80001042e0000000001000416000000000001004b000000cc0000c13d0000038e01000041000007f10000013d0000000001000416000000000001004b000000cc0000c13d0000038b01000041000000000101041a0000037f01100197000000800010043f000003cf0100004100000dd80001042e000003c601000041000000000010043f000000040020043f000003950100004100000dd9000104300000001f041000390000037c044001970000003f044000390000037d04400197000000400600043d0000000004460019000000000064004b000000000500003900000001050040390000037a0040009c0000010f0000213d00000001005001900000010f0000c13d000000400040043f000700000006001d0000000004160436000600000004001d000000a0033000390000000004310019000000000024004b000000cc0000213d000000000001004b00000006060000290000081b0000613d000000000200001900000000042600190000000005320019000000000505043300000000005404350000002002200039000000000012004b000008140000413d000000070110002900000020011000390000000000010435000000c00100043d000500000001001d0000037f0010009c000000cc0000213d0000038001000041000000000010043f0000038101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a000004010220019700000001022001bf000000000021041b00000009010000290000000001010433000400000001001d0000037a0010009c0000010f0000213d0000038301000041000000000101041a000000010210019000000001011002700000007f0110618f0000001f0010008c00000000030000390000000103002039000000000023004b00000a8f0000613d0000039401000041000000000010043f0000002201000039000000040010043f000003950100004100000dd900010430000003c602000041000000000020043f000000040010043f000003950100004100000dd900010430000000a001100210000003e502000041000000000302041a0000037f03300197000008c10000013d000003c601000041000000000010043f000000040050043f000003950100004100000dd900010430000003d80010009c000009480000c13d00000001010000390000095a0000013d000003fc0010019800000000010000190000086d0000613d000003fd01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0000037f01100197000000400200043d0000095b0000013d0000000002000019000008780000013d00000000023400a9000003f903300197000003f90220019700000000033200d9000000000034004b000009650000c13d000003d00220012a0000037f01100197000000800010043f000000a00020043f000003fa0100004100000dd80001042e000000000010043f000003ec01000041000000200010043f00000040010000390dd70dad0000040f000000000101041a000000800010043f000003cf0100004100000dd80001042e0000000901000029000000000010043f000003d101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a0000040102200197000000000021041b000000400100043d0000004002100039000000080300002900000000003204350000002002100039000000000032043500000009020000290000000000210435000003770010009c000003770100804100000040011002100000000002000414000003770020009c0000037702008041000000c002200210000000000112019f000003d2011001c70000800d020000390000000103000039000003d304000041000007880000013d0000000902000029000000000032004b0000096b0000c13d000003ff01000041000007f70000013d000003e502000041000000000302041a0000038c03300197000000000113019f000000000012041b000000000100001900000dd80001042e0000037f01200197000000000010043f000003ce01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000902000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a00000401022001970000000803000029000000000232019f000000000021041b000000400100043d0000000000310435000003770010009c000003770100804100000040011002100000000002000414000003770020009c0000037702008041000000c002200210000000000112019f00000386011001c70000800d020000390000000303000039000003e304000041000000000500041100000009060000290dd70dcd0000040f0000000100200190000000cc0000613d0000078b0000013d000003dd01000041000000800010043f000000840040043f0000000001000414000003770010009c0000037701008041000000c001100210000003de011001c70dd70dd20000040f00000060031002700000037703300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000009110000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b0000090d0000c13d000000000006004b0000091e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000009840000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c000000cc0000413d000000800100043d000000000001004b0000000704000029000005060000613d000003df02000041000000000020043f000000040040043f000000240010043f000003cd0100004100000dd900010430000000400200043d0000000006520019000000000005004b0000093a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000068004b000009360000c13d000000000004004b0000099c0000613d000000000151034f0000000304400210000000000506043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001604350000099c0000013d000000000010043f0000038101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000400200043d000000000101043b000000000101041a000000ff001001900000000001000039000000010100c039000000010110018f0000000000120435000003770020009c00000377020080410000004001200210000003f0011001c700000dd80001042e000000000001042f000000000200041a000000010120003a000009a20000c13d0000039401000041000000000010043f0000001101000039000000040010043f000003950100004100000dd90001043000000000040004110006037f0040019b000000060030006c000700000003001d000009a90000c13d000000000002004b000009d30000c13d000003fc00100198000009f80000613d0000000801000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000702000029000009f70000013d0000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000098b0000c13d000000000005004b0000099c0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000003770020009c00000377020080410000004002200210000000000112019f00000dd900010430000000000010041b000000090000006b00000a3f0000c13d000003f101000041000000000010043f000003cb0100004100000dd900010430000500000001001d000000000030043f000003ce01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000602000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a000000ff00100190000000090200002900000007030000290000000501000029000009700000c13d000003fb01000041000000000010043f0000000001000411000000040010043f000000240030043f0000000801000029000000440010043f000003db0100004100000dd900010430000603fc001001cb000000060010006c000009e60000613d0000000801000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000602000029000000000021041b0000000801000029000000000010043f000003fd01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a0000038c0220019700000009022001af000000000021041b0000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d020000390000000403000039000003fe040000410000000705000029000000090600002900000008070000290dd70dcd0000040f0000000100200190000000cc0000613d0000078b0000013d000003dd01000041000000800010043f0000000701000029000000840010043f0000000001000414000003770010009c0000037701008041000000c001100210000003de011001c70dd70dd20000040f00000060031002700000037703300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf00000a200000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b00000a1c0000c13d000000000006004b00000a2d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000ab60000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c000000cc0000413d000000800100043d000000000001004b000005b30000613d000003df02000041000000000020043f0000000702000029000000040020043f000000240010043f000003cd0100004100000dd900010430000800000002001d000000000020043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000101041a0000037f0010019800000ad30000c13d0000000801000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b0000000902000029000000000021041b000000000020043f000003ec01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a0000000102200039000000000021041b000000400100043d000700000001001d0000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d020000390000000403000039000003ef040000410000000005000019000000090600002900000008070000290dd70dcd0000040f0000000100200190000000cc0000613d000000080100002900000007020000290000095b0000013d0000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000a8a0000c13d0000098f0000013d000000200010008c00000aa20000413d0000038302000041000000000020043f00000004030000290000001f023000390000000502200270000003840220009a000000200030008c00000385020040410000001f011000390000000501100270000003840110009a000000000012004b00000aa20000813d000000000002041b0000000102200039000000000012004b00000a9e0000413d00000004010000290000001f0010008c00000ac60000a13d0000038301000041000000000010043f0000000001000414000003770010009c0000037701008041000000c00110021000000386011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d00000004020000290000038702200198000000000101043b00000ae10000c13d000000200300003900000aee0000013d0000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000abd0000c13d0000098f0000013d000003eb01000041000000000010043f000003cb0100004100000dd900010430000000040000006b000000000100001900000acb0000613d0000000801000029000000000101043300000004040000290000000302400210000004030220027f0000040302200167000000000121016f0000000102400210000000000121019f00000afc0000013d000003ee010000410000034b0000013d0000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000adc0000c13d0000098f0000013d000000010320008a0000000503300270000000000431001900000020030000390000000104400039000000090600002900000000056300190000000005050433000000000051041b00000020033000390000000101100039000000000041004b00000ae70000c13d000000040020006c00000af90000613d00000004020000290000000302200210000000f80220018f000004030220027f000004030220016700000009033000290000000003030433000000000223016f000000000021041b0000000401000029000000010110021000000001011001bf0000038302000041000000000012041b00000007010000290000000001010433000900000001001d0000037a0010009c0000010f0000213d0000038801000041000000000201041a000000010020019000000001012002700000007f0110618f0000001f0010008c00000000030000390000000103002039000000000223013f0000000100200190000008430000c13d000000200010008c00000b210000413d0000038802000041000000000020043f00000009030000290000001f023000390000000502200270000003890220009a000000200030008c0000038a020040410000001f011000390000000501100270000003890110009a000000000012004b00000b210000813d000000000002041b0000000102200039000000000012004b00000b1d0000413d00000009010000290000001f0010008c00000b350000a13d0000038801000041000000000010043f0000000001000414000003770010009c0000037701008041000000c00110021000000386011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d00000009020000290000038702200198000000000101043b00000b540000c13d000000200300003900000b610000013d000000090000006b000000000100001900000b3a0000613d0000000601000029000000000101043300000009040000290000000302400210000004030220027f0000040302200167000000000121016f0000000102400210000000000121019f00000b6f0000013d0000800a01000039000003c70200004100000000030004100dd70dbe0000040f000003cc02000041000000000020043f000000040010043f0000000901000029000000240010043f000003cd0100004100000dd9000104300000000001030433000000000001004b00000bb50000c13d000003ca01000041000000000010043f000003cb0100004100000dd900010430000000010320008a0000000503300270000000000431001900000020030000390000000104400039000000070600002900000000056300190000000005050433000000000051041b00000020033000390000000101100039000000000041004b00000b5a0000c13d000000090020006c00000b6c0000613d00000009020000290000000302200210000000f80220018f000004030220027f000004030220016700000007033000290000000003030433000000000223016f000000000021041b0000000901000029000000010110021000000001011001bf0000038802000041000000000012041b0000038b01000041000000000201041a0000038c0220019700000005022001af000000000021041b0000038d01000041000000000010043f0000038101000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f0000000100200190000000cc0000613d000000000101043b000000000201041a000004010220019700000001022001bf000000000021041b0000000006000411000000000006004b00000b9c0000613d0000038e01000041000000000201041a0000038c02200197000000000262019f000000000021041b0000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d020000390000000303000039000003900400004100000000050000190dd70dcd0000040f0000000100200190000000cc0000613d0000039101000041000000000010043f0000038101000041000000200010043f00000040010000390dd70dad0000040f000000000201041a000004010220019700000001022001bf000000000021041b0000039201000041000000000010043f0000038101000041000000200010043f00000040010000390dd70dad0000040f000000000201041a000004010220019700000001022001bf000000000021041b000000200100003900000100001004430000012000000443000003930100004100000dd80001042e000003770040009c00000377040080410000004002400210000003770010009c00000377010080410000006001100210000000000121019f00000dd9000104300000039401000041000000000010043f0000003201000039000000040010043f000003950100004100000dd9000104300000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000bca0000c13d0000098f0000013d0000001f0530018f0000037906300198000000400200043d00000000046200190000098f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000bd60000c13d0000098f0000013d000003dc01000041000007f70000013d00000060061002700000001f0460018f0000037905600198000000400200043d000000000352001900000be90000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000be50000c13d0000037706600197000000000004004b00000bf70000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000060016002100000099d0000013d00000000430104340000000001320436000000000003004b00000c050000613d000000000200001900000000051200190000000006240019000000000606043300000000006504350000002002200039000000000032004b00000bfe0000413d000000000213001900000000000204350000001f0230003900000402022001970000000001210019000000000001042d000004040010009c00000c1b0000213d000000630010008c00000c1b0000a13d00000000030003670000000401300370000000000101043b0000037f0010009c00000c1b0000213d0000002402300370000000000202043b0000037f0020009c00000c1b0000213d0000004403300370000000000303043b000000000001042d000000000100001900000dd90001043000020000000000020000000102000039000000000202041a0000037f0220019800000c640000613d000000400400043d000200000004001d000003dd0300004100000000003404350000000403400039000100000001001d0000000000130435000003770040009c0000037701000041000000000104401900000040011002100000000003000414000003770030009c0000037703008041000000c003300210000000000113019f00000395011001c70dd70dd20000040f000000020b00002900000060031002700000037703300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900000c440000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000c400000c13d000000000006004b00000c510000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000c650000613d0000001f01400039000000600210018f0000000001b20019000000000021004b000000000200003900000001020040390000037a0010009c00000c830000213d000000010020019000000c830000c13d000000400010043f000000200030008c00000c890000413d00000000010b0433000000000001004b000000010300002900000c8b0000c13d000000000001042d0000001f0530018f0000037906300198000000400200043d000000000462001900000c700000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000c6c0000c13d000000000005004b00000c7d0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000003770020009c00000377020080410000004002200210000000000112019f00000dd9000104300000039401000041000000000010043f0000004101000039000000040010043f000003950100004100000dd900010430000000000100001900000dd900010430000003df02000041000000000020043f000000040030043f000000240010043f000003cd0100004100000dd9000104300006000000000002000400000002001d000300000001001d0006037f0030019c00000d2a0000613d000500000004001d000000000040043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b000000000301041a0000037f0230019800000d2e0000613d00000004010000290000037f01100197000000000012004b00000d340000c13d00000003010000290002037f0010019b000000020020006c000400000002001d00000ce50000613d000100000003001d000000000020043f000003ce01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b0000000202000029000000000020043f000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b000000000101041a000000ff001001900000000402000029000000010100002900000ce50000c13d000003fc0010019800000d3b0000613d0000000501000029000000000010043f000003fd01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b000000000101041a000000030110014f0000037f00100198000000040200002900000d3b0000c13d0000000501000029000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b0000000602000029000000000021041b0000000405000029000000000025004b00000d1a0000613d000000000050043f000003ec01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000601000029000000000010043f000003ec01000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d280000613d000000000101043b000000000201041a0000000102200039000000000021041b00000004050000290000000001000414000003770010009c0000037701008041000000c0011002100000038f011001c70000800d020000390000000403000039000003ef04000041000000060600002900000005070000290dd70dcd0000040f000000010020019000000d280000613d000000000001042d000000000100001900000dd9000104300000040701000041000000000010043f000003cb0100004100000dd900010430000003d701000041000000000010043f0000000501000029000000040010043f000003950100004100000dd9000104300000040502000041000000000020043f000000040010043f0000000501000029000000240010043f000003cd0100004100000dd9000104300000040601000041000000000010043f0000000201000029000000040010043f000000240020043f0000000501000029000000440010043f000003db0100004100000dd9000104300001000000000002000100000001001d000000000010043f000003d501000041000000200010043f0000000001000414000003770010009c0000037701008041000000c00110021000000382011001c700008010020000390dd70dd20000040f000000010020019000000d570000613d000000000101043b000000000101041a0000037f0110019800000d590000613d000000000001042d000000000100001900000dd900010430000003d701000041000000000010043f0000000101000029000000040010043f000003950100004100000dd9000104300003000000000002000000000201041a000000010320019000000001062002700000007f0660618f0000001f0060008c00000000040000390000000104002039000000000034004b00000d9e0000c13d000000400500043d0000000004650436000000000003004b00000d890000613d000100000004001d000200000006001d000300000005001d000000000010043f0000000001000414000003770010009c0000037701008041000000c00110021000000386011001c700008010020000390dd70dd20000040f000000010020019000000daa0000613d0000000206000029000000000006004b00000d8f0000613d000000000201043b0000000001000019000000030500002900000001070000290000000003170019000000000402041a000000000043043500000001022000390000002001100039000000000061004b00000d810000413d00000d910000013d00000401012001970000000000140435000000000006004b0000002001000039000000000100603900000d910000013d000000000100001900000003050000290000003f0110003900000402021001970000000001520019000000000021004b000000000200003900000001020040390000037a0010009c00000da40000213d000000010020019000000da40000c13d000000400010043f0000000001050019000000000001042d0000039401000041000000000010043f0000002201000039000000040010043f000003950100004100000dd9000104300000039401000041000000000010043f0000004101000039000000040010043f000003950100004100000dd900010430000000000100001900000dd900010430000000000001042f000003770010009c000003770100804100000060011002100000000002000414000003770020009c0000037702008041000000c002200210000000000112019f0000038f011001c700008010020000390dd70dd20000040f000000010020019000000dbc0000613d000000000101043b000000000001042d000000000100001900000dd9000104300000000004010019000000000020044300000004003004430000000001000414000003770010009c0000037701008041000000c001100210000003c8011001c700000000020400190dd70dd20000040f000000010020019000000dcc0000613d000000000101043b000000000001042d000000000001042f00000dd0002104210000000102000039000000000001042d0000000002000019000000000001042d00000dd5002104230000000102000039000000000001042d0000000002000019000000000001042d00000dd70000043200000dd80001042e00000dd9000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000000000000000000000000000ffffffffffffffff0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffe0000000000000000000000000000000000000000000000003ffffffffffffffe08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff80ac58cd00000000000000000000000000000000000000000000000000000000ca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5d02000000000000000000000000000000000000400000000000000000000000007ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a4a9a21f304475c08f36c724e503aa9d96f0083aa88c38dcb59b6cff0a71c4cf44565de0cfbb8a3f70c938db1afc5562690ff7c55773c7234a649300f58e3b30bc0200000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffe07ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a53c6452c24a2a923307c64375868a64ce6d4688a8266c0899c366670b0410375fc39bad3db5d56dccf839bc8a79759b3192b97757d993f7663c9998f4fbefc8a17ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a6ffffffffffffffffffffffff00000000000000000000000000000000000000005b5e139f00000000000000000000000000000000000000000000000000000000c9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cc02000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e07f5828d0000000000000000000000000000000000000000000000000000000002a55205a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000400000010000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000000000000000000000075794a3b00000000000000000000000000000000000000000000000000000000b88d4fdd00000000000000000000000000000000000000000000000000000000d547741e00000000000000000000000000000000000000000000000000000000e985e9c400000000000000000000000000000000000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f7ba94bd00000000000000000000000000000000000000000000000000000000d547741f00000000000000000000000000000000000000000000000000000000e1a8bf2c00000000000000000000000000000000000000000000000000000000c87b56dc00000000000000000000000000000000000000000000000000000000c87b56dd00000000000000000000000000000000000000000000000000000000d539139300000000000000000000000000000000000000000000000000000000b88d4fde00000000000000000000000000000000000000000000000000000000c3666c360000000000000000000000000000000000000000000000000000000091d1485300000000000000000000000000000000000000000000000000000000a0c76f6100000000000000000000000000000000000000000000000000000000a0c76f6200000000000000000000000000000000000000000000000000000000a22cb4650000000000000000000000000000000000000000000000000000000091d148540000000000000000000000000000000000000000000000000000000095d89b41000000000000000000000000000000000000000000000000000000008da5cb5a000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000008dc251e30000000000000000000000000000000000000000000000000000000075794a3c000000000000000000000000000000000000000000000000000000008bb9c5bf0000000000000000000000000000000000000000000000000000000042842e0d000000000000000000000000000000000000000000000000000000006352211d0000000000000000000000000000000000000000000000000000000070a082300000000000000000000000000000000000000000000000000000000070a082310000000000000000000000000000000000000000000000000000000073c8a958000000000000000000000000000000000000000000000000000000006352211e000000000000000000000000000000000000000000000000000000006a6278420000000000000000000000000000000000000000000000000000000053f92e300000000000000000000000000000000000000000000000000000000053f92e310000000000000000000000000000000000000000000000000000000061ba27da0000000000000000000000000000000000000000000000000000000042842e0e0000000000000000000000000000000000000000000000000000000042966c68000000000000000000000000000000000000000000000000000000001548ed18000000000000000000000000000000000000000000000000000000002a552059000000000000000000000000000000000000000000000000000000002a55205a000000000000000000000000000000000000000000000000000000002f2ff15d000000000000000000000000000000000000000000000000000000001548ed190000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000081812fb00000000000000000000000000000000000000000000000000000000081812fc00000000000000000000000000000000000000000000000000000000095ea7b30000000000000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000006fdde032ef4875e000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f39020000020000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffe0d6bda275000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cf479181000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000ddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c3000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000000000000000000000000186a0c8827d3282af6f37b64c3e9e6f3ac9df286ab0bb0fccd6f8661bf19adb368b220200000000000000000000000000000000000060000000000000000000000000f6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6d696e7465720000000000000000000000000000000000000000000000000000ddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c0f724dad700000000000000000000000000000000000000000000000000000000dd5604750000000000000000000000000000000000000000000000000000000001ffc9a7000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8342842e0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000986b9f1f000000000000000000000000000000000000000000000000000000000ac7843c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000800000000000000000f11294ae00000000000000000000000000000000000000000000000000000000150b7a020000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc215a7a10000000000000000000000000000000000000000000000000000000017307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31e4215c6a000000000000000000000000000000000000000000000000000000002c0cf10337caabbd02dcf226f05f5fd19a0919a41a8df8958c39b8000782685716de0c80000000000000000000000000000000000000000000000000000000007aa7288200000000000000000000000000000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f5274afe7000000000000000000000000000000000000000000000000000000006582533600000000000000000000000000000000000000000000000000000000ddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c1aefbce4e00000000000000000000000000000000000000000000000000000000753eceac00000000000000000000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000000000000000000200000000000000000000000007851b9cd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a1ac04040800000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000080000000000000000033e85773eda69c91a470cca572dc936a94f4c242cbcbe59f4c9d8b77c16a7ddadead000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d00000000000000000000000000000000ffffffffffffffffffffffffffffffff0000000000000000000000000000000000000040000000800000000000000000c7563a18000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000ddf3ee18ae6d688373c219468f8be446e7ae82215f4779d821c7ea5e8c13c0c28c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925b7fdc01000000000000000000000000000000000000000000000000000000000fffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14dbb53600000000000000000000000000000000000000000000000000000000a4a3018b0000000000000000000000000000000000000000000000000000000086c8706700000000000000000000000000000000000000000000000000000000000000000000000000a26469706673582212203ee34e29b4bb3c1c20c112fda5140a1b2a943ac2e0e1f9984d0b0a6de12184e064736f6c6378247a6b736f6c633a312e352e31353b736f6c633a302e382e32383b6c6c766d3a312e302e320055
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000006aa75ad1fe433cf6eb83436e3fdfd02999638f2d0000000000000000000000000000000000000000000000000000000000000013416e6963686573732050656e6775426f61726400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a50454e4755424f41524400000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tokenName (string): Anichess PenguBoard
Arg [1] : tokenSymbol (string): PENGUBOARD
Arg [2] : metadataResolver (address): 0x6AA75ad1fe433CF6Eb83436e3fDFD02999638f2D
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 0000000000000000000000006aa75ad1fe433cf6eb83436e3fdfd02999638f2d
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000013
Arg [4] : 416e6963686573732050656e6775426f61726400000000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [6] : 50454e4755424f41524400000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.