ETH Price: $3,342.28 (-0.43%)
 
Transaction Hash
Method
Block
From
To
Mint With Author...212874872024-11-28 16:47:3534 days ago1732812455IN
0x6aD85107...2d89EAcC8
0 ETH0.0019227912.84801161
Mint With Author...210819932024-10-31 0:19:4762 days ago1730333987IN
0x6aD85107...2d89EAcC8
0 ETH0.0016373710.93996688
Mint With Author...204704352024-08-06 15:30:23148 days ago1722958223IN
0x6aD85107...2d89EAcC8
0 ETH0.0013507910.18810117
Mint With Author...200744202024-06-12 8:01:35203 days ago1718179295IN
0x6aD85107...2d89EAcC8
0 ETH0.0014475712.52790778
Mint With Author...200741532024-06-12 7:07:59203 days ago1718176079IN
0x6aD85107...2d89EAcC8
0 ETH0.0012984111.23701297
Mint With Author...193953412024-03-09 5:05:35298 days ago1709960735IN
0x6aD85107...2d89EAcC8
0 ETH0.0068009945.44385999
Mint With Author...191801802024-02-08 1:28:59328 days ago1707355739IN
0x6aD85107...2d89EAcC8
0 ETH0.003593531.10421994
Mint With Author...183296882023-10-11 20:51:23447 days ago1697057483IN
0x6aD85107...2d89EAcC8
0 ETH0.001246578.32793487
Mint With Author...182794732023-10-04 20:14:35454 days ago1696450475IN
0x6aD85107...2d89EAcC8
0 ETH0.0016552614.32744421
Mint With Author...181858342023-09-21 17:48:11468 days ago1695318491IN
0x6aD85107...2d89EAcC8
0 ETH0.0011817710.22865372
Mint With Author...181804712023-09-20 23:45:59468 days ago1695253559IN
0x6aD85107...2d89EAcC8
0 ETH0.0015554311.73299146
Mint With Author...181804292023-09-20 23:37:35468 days ago1695253055IN
0x6aD85107...2d89EAcC8
0 ETH0.0013975612.09936283
Mint With Author...179601952023-08-21 2:41:47499 days ago1692585707IN
0x6aD85107...2d89EAcC8
0 ETH0.0018524416.03581198
Mint With Author...179561412023-08-20 13:05:35500 days ago1692536735IN
0x6aD85107...2d89EAcC8
0 ETH0.0021035718.2078676
Mint With Author...178127962023-07-31 11:49:23520 days ago1690804163IN
0x6aD85107...2d89EAcC8
0 ETH0.0025148116.80383098
Mint With Author...177682202023-07-25 6:06:59526 days ago1690265219IN
0x6aD85107...2d89EAcC8
0 ETH0.0023771820.57826174
Mint With Author...177495672023-07-22 15:28:59529 days ago1690039739IN
0x6aD85107...2d89EAcC8
0 ETH0.0026591123.01647548
Mint With Author...176638632023-07-10 14:29:59541 days ago1688999399IN
0x6aD85107...2d89EAcC8
0 ETH0.0042486436.7733836
Mint With Author...176638522023-07-10 14:27:47541 days ago1688999267IN
0x6aD85107...2d89EAcC8
0 ETH0.0059003935.38764866
Mint With Author...175536822023-06-25 2:57:59556 days ago1687661879IN
0x6aD85107...2d89EAcC8
0 ETH0.0024781516.55835749
Mint With Author...175470762023-06-24 4:40:35557 days ago1687581635IN
0x6aD85107...2d89EAcC8
0 ETH0.0020984418.16267575
Mint With Author...175428632023-06-23 14:28:35558 days ago1687530515IN
0x6aD85107...2d89EAcC8
0 ETH0.0034424823.00067962
Mint With Author...175146152023-06-19 15:14:35562 days ago1687187675IN
0x6aD85107...2d89EAcC8
0 ETH0.0029496625.5276061
Mint With Author...175076982023-06-18 15:57:47563 days ago1687103867IN
0x6aD85107...2d89EAcC8
0 ETH0.0020159717.4470623
Mint With Author...174986132023-06-17 9:24:11564 days ago1686993851IN
0x6aD85107...2d89EAcC8
0 ETH0.0016838814.57672262
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC721Minter

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 6 : ERC721Minter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../interfaces/ERC721Spec.sol";
import "../interfaces/AletheaERC721Spec.sol";
import "../utils/AccessControl.sol";
import "../lib/ECDSA.sol";

/**
 * @title ERC721 Minter
 *
 * @notice ERC721Minter contract introduces a scalable mechanism to mint NFTs to an arbitrary
 *      amount of addresses by leveraging the power of EIP712 signature.
 */
contract ERC721Minter is AccessControl {
	
	/**
	 * @dev Mintable ERC721 contract address to mint tokens of
	 */
	address public immutable targetContract;

	/**
	 * @dev Number of ERC721 token been mint by ERC721Minter
	 */
	uint256 public tokenMintCount;

	/**
	 * @dev Max token can be minted by ERC721Minter
	 */
	uint256 public maxTokenMintLimit;

	/**
	 * @notice Enables the airdrop, redeeming the tokens via EIP712 signature
	 *
	 * @dev Feature FEATURE_REDEEM_ACTIVE must be enabled in order for
	 *      `mintWithAuthorization` and `mintBatchWithAuthorization` functions to succeed
	 */
	uint32 public constant FEATURE_REDEEM_ACTIVE = 0x0000_0001;

	/**
	 * @notice Authorization manager is responsible for supplying the EIP712 signature
	 *      which then can be used to mint tokens, meaning effectively,
	 *      that Authorization manager may act as a minter on the target NFT contract
	 *
	 * @dev Role ROLE_AUTHORIZATION_MANAGER allows minting tokens with authorization
	 */
	uint32 public constant ROLE_AUTHORIZATION_MANAGER = 0x0001_0000;

	/**
	 * @notice mint limit manager is responsible for update ERC721 token mint limit
	 *
	 * @dev Role ROLE_MINT_LIMIT_MANAGER allows update token mint limit
	 */
	uint32 public constant ROLE_MINT_LIMIT_MANAGER = 0x0002_0000;

	/**
	 * @notice EIP-712 contract's domain typeHash,
	 *      see https://eips.ethereum.org/EIPS/eip-712#rationale-for-typehash
	 *
	 * @dev Note: we do not include version into the domain typehash/separator,
	 *      it is implied version is concatenated to the name field, like "ERC721Minter"
	 */
	// keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)")
	bytes32 public constant DOMAIN_TYPEHASH = 0x8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866;

	/**
	 * @notice EIP-712 contract's domain separator,
	 *      see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
	 */
	bytes32 public immutable DOMAIN_SEPARATOR;

	// keccak256("MintWithAuthorization(address from,address to,uint256 id,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
	bytes32 public constant MINT_WITH_AUTHORIZATION_TYPEHASH = 0xaf4e98e5c9896ed6453d82e308a87caa8a02787c2c671d5a8cd308f9a99ed41f;

	// keccak256("MintBatchWithAuthorization(address from,address to,uint256 id,uint256 amount,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
	bytes32 public constant MINTBATCH_WITH_AUTHORIZATION_TYPEHASH = 0x67c2bc25c87d2f7202a6c00ccb845fe254f34def701c1f45f93e7e9219b1ebb2;

	// keccak256("CancelAuthorization(address authorizer,bytes32 nonce)")
	bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH = 0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429;

	/**
	 * @dev A record of used nonces for meta transactions
	 *
	 * @dev Maps authorizer address => nonce => true/false (used unused)
	 */
	mapping(address => mapping(bytes32 => bool)) private usedNonces;

	/**
	 * @dev Fired whenever the nonce gets used (ex.: `mintWithAuthorization`, `mintBatchWithAuthorization`)
	 *
	 * @param authorizer an address which has used the nonce
	 * @param nonce the nonce used
	 */
	event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);

	/**
	 * @dev Fired whenever the nonce gets cancelled (ex.: `cancelAuthorization`)
	 *
	 * @dev Both `AuthorizationUsed` and `AuthorizationCanceled` imply the nonce
	 *      cannot be longer used, the only difference is that `AuthorizationCanceled`
	 *      implies no smart contract state change made (except the nonce marked as cancelled)
	 *
	 * @param authorizer an address which has cancelled the nonce
	 * @param nonce the nonce cancelled
	 */
	event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce);

	/**
	 * @dev Fired whenever token mint Limit is updated (ex.: `updateTokenMintLimit`)
	 *
	 * @param authorizer an address which has updated token mint limit
	 * @param oldLimit old token mint limit
	 * @param newLimit new token mint limit
	 */
	event TokenMintLimitUpdated(address indexed authorizer, uint256 oldLimit, uint256 newLimit);

	/**
	 * @dev Creates/deploys ERC721Minter and binds it to ERC721 smart contract on construction
	 *
	 * @param _target deployed Mintable ERC721 smart contract; contract will mint NFTs of that type
	 */
	constructor(address _target) {
		// verify the input is set
		require(_target != address(0), "target contract is not set");

		// verify the input is valid smart contract of the expected interfaces
		require(
			ERC165(_target).supportsInterface(type(ERC721).interfaceId)
			&& ERC165(_target).supportsInterface(type(MintableERC721).interfaceId),
			"unexpected target type"
		);

		// assign the address
		targetContract = _target;

		// max ERC721Minter contract can mint 1000 token's
		maxTokenMintLimit = 1000;

		// build the EIP-712 contract domain separator, see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
		DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("ERC721Minter")), block.chainid, address(this)));
	}

	/**
	 * @notice Checks if specified nonce was already used
	 *
	 * @dev Nonces are expected to be client-side randomly generated 32-byte values
	 *      unique to the authorizer's address
	 *
	 * @dev Alias for usedNonces(authorizer, nonce)
	 *
	 * @param _authorizer an address to check nonce for
	 * @param _nonce a nonce to check
	 * @return true if the nonce was used, false otherwise
	 */
	function authorizationState(address _authorizer, bytes32 _nonce) public view returns (bool) {
		// simply return the value from the mapping
		return usedNonces[_authorizer][_nonce];
	}

	/**
	 * @notice Receive a token with a signed authorization from the authorization manager
	 *
	 * @dev This has an additional check to ensure that the receiver's address
	 *      matches the caller of this function to prevent front-running attacks.
	 *
	 * @param _from token sender and transaction authorizer
	 * @param _to token receiver
	 * @param _id token ID to mint
	 * @param _validAfter signature valid after time (unix timestamp)
	 * @param _validBefore signature valid before time (unix timestamp)
	 * @param _nonce unique random nonce
	 * @param v the recovery byte of the signature
	 * @param r half of the ECDSA signature pair
	 * @param s half of the ECDSA signature pair
	 */
	function mintWithAuthorization(
		address _from,
		address _to,
		uint256 _id,
		uint256 _validAfter,
		uint256 _validBefore,
		bytes32 _nonce,
		uint8 v,
		bytes32 r,
		bytes32 s
	) public {
		// verify redeems are enabled
		require(isFeatureEnabled(FEATURE_REDEEM_ACTIVE), "redeems are disabled");

		require(tokenMintCount < maxTokenMintLimit, "minting Limit has been reached!!");

		// derive signer of the EIP712 MintWithAuthorization message
		address signer = __deriveSigner(abi.encode(MINT_WITH_AUTHORIZATION_TYPEHASH, _from, _to, _id, _validAfter, _validBefore, _nonce), v, r, s);

		// perform message integrity and security validations
		require(signer == _from, "invalid signature");
		require(isOperatorInRole(signer, ROLE_AUTHORIZATION_MANAGER), "invalid access");
		require(block.timestamp > _validAfter, "signature not yet valid");
		require(block.timestamp < _validBefore, "signature expired");
		require(_to == msg.sender, "access denied");

		// update token mint count
		tokenMintCount++;

		// use the nonce supplied (verify, mark as used, emit event)
		__useNonce(_from, _nonce, false);

		// mint token to the recipient
		MintableERC721(targetContract).mint(_to, _id);
	}

	/**
	 * @notice Receive tokens with a signed authorization from the authorization manager
	 *
	 * @dev This has an additional check to ensure that the receiver's address
	 *      matches the caller of this function to prevent front-running attacks.
	 *
	 * @param _from token sender and transaction authorizer
	 * @param _to token receiver
	 * @param _id token ID to mint
	 * @param _amount amount of tokens to create, two or more
	 * @param _validAfter signature valid after time (unix timestamp)
	 * @param _validBefore signature valid before time (unix timestamp)
	 * @param _nonce unique random nonce
	 * @param v the recovery byte of the signature
	 * @param r half of the ECDSA signature pair
	 * @param s half of the ECDSA signature pair
	 */
	function mintBatchWithAuthorization(
		address _from,
		address _to,
		uint256 _id,
		uint256 _amount,
		uint256 _validAfter,
		uint256 _validBefore,
		bytes32 _nonce,
		uint8 v,
		bytes32 r,
		bytes32 s
	) public {
		// verify redeems are enabled
		require(isFeatureEnabled(FEATURE_REDEEM_ACTIVE), "redeems are disabled");

		require(tokenMintCount + _amount <= maxTokenMintLimit, "minting Limit has been reached!!");

		// derive signer of the EIP712 MintBatchWithAuthorization message
		address signer = __deriveSigner(abi.encode(MINTBATCH_WITH_AUTHORIZATION_TYPEHASH, _from, _to, _id, _amount, _validAfter, _validBefore, _nonce), v, r, s);

		// perform message integrity and security validations
		require(signer == _from, "invalid signature");
		require(isOperatorInRole(signer, ROLE_AUTHORIZATION_MANAGER), "invalid access");
		require(block.timestamp > _validAfter, "signature not yet valid");
		require(block.timestamp < _validBefore, "signature expired");
		require(_to == msg.sender, "access denied");

		// update token mint count
		tokenMintCount = tokenMintCount + _amount;

		// use the nonce supplied (verify, mark as used, emit event)
		__useNonce(_from, _nonce, false);

		// mint token to the recipient
		MintableERC721(targetContract).mintBatch(_to, _id, _amount);
	}

	/**
	 * @notice Attempt to cancel an authorization
	 *
	 * @param _authorizer transaction authorizer
	 * @param _nonce unique random nonce to cancel (mark as used)
	 * @param v the recovery byte of the signature
	 * @param r half of the ECDSA signature pair
	 * @param s half of the ECDSA signature pair
	 */
	function cancelAuthorization(
		address _authorizer,
		bytes32 _nonce,
		uint8 v,
		bytes32 r,
		bytes32 s
	) public {
		// derive signer of the EIP712 ReceiveWithAuthorization message
		address signer = __deriveSigner(abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, _authorizer, _nonce), v, r, s);

		// perform message integrity and security validations
		require(signer == _authorizer, "invalid signature");

		// cancel the nonce supplied (verify, mark as used, emit event)
		__useNonce(_authorizer, _nonce, true);
	}

	/**
	 * @dev Auxiliary function to verify structured EIP712 message signature and derive its signer
	 *
	 * @param abiEncodedTypehash abi.encode of the message typehash together with all its parameters
	 * @param v the recovery byte of the signature
	 * @param r half of the ECDSA signature pair
	 * @param s half of the ECDSA signature pair
	 */
	function __deriveSigner(bytes memory abiEncodedTypehash, uint8 v, bytes32 r, bytes32 s) private view returns(address) {
		// build the EIP-712 hashStruct of the message
		bytes32 hashStruct = keccak256(abiEncodedTypehash);

		// calculate the EIP-712 digest "\x19\x01" ‖ domainSeparator ‖ hashStruct(message)
		bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashStruct));

		// recover the address which signed the message with v, r, s
		address signer = ECDSA.recover(digest, v, r, s);

		// return the signer address derived from the signature
		return signer;
	}

	/**
	 * @dev Auxiliary function to use/cancel the nonce supplied for a given authorizer:
	 *      1. Verifies the nonce was not used before
	 *      2. Marks the nonce as used
	 *      3. Emits an event that the nonce was used/cancelled
	 *
	 * @dev Set `_cancellation` to false (default) to use nonce,
	 *      set `_cancellation` to true to cancel nonce
	 *
	 * @dev It is expected that the nonce supplied is a randomly
	 *      generated uint256 generated by the client
	 *
	 * @param _authorizer an address to use/cancel nonce for
	 * @param _nonce random nonce to use
	 * @param _cancellation true to emit `AuthorizationCancelled`, false to emit `AuthorizationUsed` event
	 */
	function __useNonce(address _authorizer, bytes32 _nonce, bool _cancellation) private {
		// verify nonce was not used before
		require(!usedNonces[_authorizer][_nonce], "invalid nonce");

		// update the nonce state to "used" for that particular signer to avoid replay attack
		usedNonces[_authorizer][_nonce] = true;

		// depending on the usage type (use/cancel)
		if(_cancellation) {
			// emit an event regarding the nonce cancelled
			emit AuthorizationCanceled(_authorizer, _nonce);
		}
		else {
			// emit an event regarding the nonce used
			emit AuthorizationUsed(_authorizer, _nonce);
		}
	}

	/**
	 * @notice Updates max ERC721 token mint Limit of 
	 *			ERC721Minter contract.
	 *
	 * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission
	 *
	 * @param _tokenMintLimit new ERC721 token mint limit
	 */
	function updateTokenMintLimit(uint256 _tokenMintLimit) public {
		// caller must have a permission to update token mint limit
		require(isSenderInRole(ROLE_MINT_LIMIT_MANAGER), "access denied");

		// fire an event
		emit TokenMintLimitUpdated(msg.sender, maxTokenMintLimit, _tokenMintLimit);

		// update token mint limit
		maxTokenMintLimit = _tokenMintLimit;
	}
}

File 2 of 6 : ERC721Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./ERC165Spec.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev Solidity issue #3412: The ERC721 interfaces include explicit mutability guarantees for each function.
 *      Mutability guarantees are, in order weak to strong: payable, implicit nonpayable, view, and pure.
 *      Implementation MUST meet the mutability guarantee in this interface and MAY meet a stronger guarantee.
 *      For example, a payable function in this interface may be implemented as nonpayable
 *      (no state mutability specified) in implementing contract.
 *      It is expected a later Solidity release will allow stricter contract to inherit from this interface,
 *      but current workaround is that we edit this interface to add stricter mutability before inheriting:
 *      we have removed all "payable" modifiers.
 *
 * @dev The ERC-165 identifier for this interface is 0x80ac58cd.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721 is ERC165 {
	/// @dev This emits when ownership of any NFT changes by any mechanism.
	///  This event emits when NFTs are created (`from` == 0) and destroyed
	///  (`to` == 0). Exception: during contract creation, any number of NFTs
	///  may be created and assigned without emitting Transfer. At the time of
	///  any transfer, the approved address for that NFT (if any) is reset to none.
	event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

	/// @dev This emits when the approved address for an NFT is changed or
	///  reaffirmed. The zero address indicates there is no approved address.
	///  When a Transfer event emits, this also indicates that the approved
	///  address for that NFT (if any) is reset to none.
	event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

	/// @dev This emits when an operator is enabled or disabled for an owner.
	///  The operator can manage all NFTs of the owner.
	event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

	/// @notice Count all NFTs assigned to an owner
	/// @dev NFTs assigned to the zero address are considered invalid, and this
	///  function throws for queries about the zero address.
	/// @param _owner An address for whom to query the balance
	/// @return The number of NFTs owned by `_owner`, possibly zero
	function balanceOf(address _owner) external view returns (uint256);

	/// @notice Find the owner of an NFT
	/// @dev NFTs assigned to zero address are considered invalid, and queries
	///  about them do throw.
	/// @param _tokenId The identifier for an NFT
	/// @return The address of the owner of the NFT
	function ownerOf(uint256 _tokenId) external view returns (address);

	/// @notice Transfers the ownership of an NFT from one address to another address
	/// @dev Throws unless `msg.sender` is the current owner, an authorized
	///  operator, or the approved address for this NFT. Throws if `_from` is
	///  not the current owner. Throws if `_to` is the zero address. Throws if
	///  `_tokenId` is not a valid NFT. When transfer is complete, this function
	///  checks if `_to` is a smart contract (code size > 0). If so, it calls
	///  `onERC721Received` on `_to` and throws if the return value is not
	///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	/// @param _data Additional data with no specified format, sent in call to `_to`
	function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external /*payable*/;

	/// @notice Transfers the ownership of an NFT from one address to another address
	/// @dev This works identically to the other function with an extra data parameter,
	///  except this function just sets data to "".
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	function safeTransferFrom(address _from, address _to, uint256 _tokenId) external /*payable*/;

	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
	///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
	///  THEY MAY BE PERMANENTLY LOST
	/// @dev Throws unless `msg.sender` is the current owner, an authorized
	///  operator, or the approved address for this NFT. Throws if `_from` is
	///  not the current owner. Throws if `_to` is the zero address. Throws if
	///  `_tokenId` is not a valid NFT.
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	function transferFrom(address _from, address _to, uint256 _tokenId) external /*payable*/;

	/// @notice Change or reaffirm the approved address for an NFT
	/// @dev The zero address indicates there is no approved address.
	///  Throws unless `msg.sender` is the current NFT owner, or an authorized
	///  operator of the current owner.
	/// @param _approved The new approved NFT controller
	/// @param _tokenId The NFT to approve
	function approve(address _approved, uint256 _tokenId) external /*payable*/;

	/// @notice Enable or disable approval for a third party ("operator") to manage
	///  all of `msg.sender`'s assets
	/// @dev Emits the ApprovalForAll event. The contract MUST allow
	///  multiple operators per owner.
	/// @param _operator Address to add to the set of authorized operators
	/// @param _approved True if the operator is approved, false to revoke approval
	function setApprovalForAll(address _operator, bool _approved) external;

	/// @notice Get the approved address for a single NFT
	/// @dev Throws if `_tokenId` is not a valid NFT.
	/// @param _tokenId The NFT to find the approved address for
	/// @return The approved address for this NFT, or the zero address if there is none
	function getApproved(uint256 _tokenId) external view returns (address);

	/// @notice Query if an address is an authorized operator for another address
	/// @param _owner The address that owns the NFTs
	/// @param _operator The address that acts on behalf of the owner
	/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
	function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface ERC721TokenReceiver {
	/// @notice Handle the receipt of an NFT
	/// @dev The ERC721 smart contract calls this function on the recipient
	///  after a `transfer`. This function MAY throw to revert and reject the
	///  transfer. Return of other than the magic value MUST result in the
	///  transaction being reverted.
	///  Note: the contract address is always the message sender.
	/// @param _operator The address which called `safeTransferFrom` function
	/// @param _from The address which previously owned the token
	/// @param _tokenId The NFT identifier which is being transferred
	/// @param _data Additional data with no specified format
	/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
	///  unless throwing
	function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev The ERC-165 identifier for this interface is 0x5b5e139f.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721Metadata is ERC721 {
	/// @notice A descriptive name for a collection of NFTs in this contract
	function name() external view returns (string memory _name);

	/// @notice An abbreviated name for NFTs in this contract
	function symbol() external view returns (string memory _symbol);

	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
	/// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
	///  3986. The URI may point to a JSON file that conforms to the "ERC721
	///  Metadata JSON Schema".
	function tokenURI(uint256 _tokenId) external view returns (string memory);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev The ERC-165 identifier for this interface is 0x780e9d63.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721Enumerable is ERC721 {
	/// @notice Count NFTs tracked by this contract
	/// @return A count of valid NFTs tracked by this contract, where each one of
	///  them has an assigned and queryable owner not equal to the zero address
	function totalSupply() external view returns (uint256);

	/// @notice Enumerate valid NFTs
	/// @dev Throws if `_index` >= `totalSupply()`.
	/// @param _index A counter less than `totalSupply()`
	/// @return The token identifier for the `_index`th NFT,
	///  (sort order not specified)
	function tokenByIndex(uint256 _index) external view returns (uint256);

	/// @notice Enumerate NFTs assigned to an owner
	/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
	///  `_owner` is the zero address, representing invalid NFTs.
	/// @param _owner An address where we are interested in NFTs owned by them
	/// @param _index A counter less than `balanceOf(_owner)`
	/// @return The token identifier for the `_index`th NFT assigned to `_owner`,
	///   (sort order not specified)
	function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

File 3 of 6 : AletheaERC721Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @title Alethea Mintable ERC721
 *
 * @notice Defines mint capabilities for Alethea ERC721 tokens.
 *      This interface should be treated as a definition of what mintable means for ERC721
 *
 * @author Basil Gorin
 */
interface MintableERC721 {
	/**
	 * @notice Checks if specified token exists
	 *
	 * @dev Returns whether the specified token ID has an ownership
	 *      information associated with it
	 *
	 * @param _tokenId ID of the token to query existence for
	 * @return whether the token exists (true - exists, false - doesn't exist)
	 */
	function exists(uint256 _tokenId) external view returns(bool);

	/**
	 * @dev Creates new token with token ID specified
	 *      and assigns an ownership `_to` for this token
	 *
	 * @dev Unsafe: doesn't execute `onERC721Received` on the receiver.
	 *      Prefer the use of `saveMint` instead of `mint`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint token to
	 * @param _tokenId ID of the token to mint
	 */
	function mint(address _to, uint256 _tokenId) external;

	/**
	 * @dev Creates new tokens starting with token ID specified
	 *      and assigns an ownership `_to` for these tokens
	 *
	 * @dev Token IDs to be minted: [_tokenId, _tokenId + n)
	 *
	 * @dev n must be greater or equal 2: `n > 1`
	 *
	 * @dev Unsafe: doesn't execute `onERC721Received` on the receiver.
	 *      Prefer the use of `saveMintBatch` instead of `mintBatch`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint tokens to
	 * @param _tokenId ID of the first token to mint
	 * @param n how many tokens to mint, sequentially increasing the _tokenId
	 */
	function mintBatch(address _to, uint256 _tokenId, uint256 n) external;

	/**
	 * @dev Creates new token with token ID specified
	 *      and assigns an ownership `_to` for this token
	 *
	 * @dev Checks if `_to` is a smart contract (code size > 0). If so, it calls
	 *      `onERC721Received` on `_to` and throws if the return value is not
	 *      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint token to
	 * @param _tokenId ID of the token to mint
	 */
	function safeMint(address _to, uint256 _tokenId) external;

	/**
	 * @dev Creates new token with token ID specified
	 *      and assigns an ownership `_to` for this token
	 *
	 * @dev Checks if `_to` is a smart contract (code size > 0). If so, it calls
	 *      `onERC721Received` on `_to` and throws if the return value is not
	 *      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint token to
	 * @param _tokenId ID of the token to mint
	 * @param _data additional data with no specified format, sent in call to `_to`
	 */
	function safeMint(address _to, uint256 _tokenId, bytes memory _data) external;

	/**
	 * @dev Creates new tokens starting with token ID specified
	 *      and assigns an ownership `_to` for these tokens
	 *
	 * @dev Token IDs to be minted: [_tokenId, _tokenId + n)
	 *
	 * @dev n must be greater or equal 2: `n > 1`
	 *
	 * @dev Checks if `_to` is a smart contract (code size > 0). If so, it calls
	 *      `onERC721Received` on `_to` and throws if the return value is not
	 *      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint token to
	 * @param _tokenId ID of the token to mint
	 * @param n how many tokens to mint, sequentially increasing the _tokenId
	 */
	function safeMintBatch(address _to, uint256 _tokenId, uint256 n) external;

	/**
	 * @dev Creates new tokens starting with token ID specified
	 *      and assigns an ownership `_to` for these tokens
	 *
	 * @dev Token IDs to be minted: [_tokenId, _tokenId + n)
	 *
	 * @dev n must be greater or equal 2: `n > 1`
	 *
	 * @dev Checks if `_to` is a smart contract (code size > 0). If so, it calls
	 *      `onERC721Received` on `_to` and throws if the return value is not
	 *      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	 *
	 * @dev Should have a restricted access handled by the implementation
	 *
	 * @param _to an address to mint token to
	 * @param _tokenId ID of the token to mint
	 * @param n how many tokens to mint, sequentially increasing the _tokenId
	 * @param _data additional data with no specified format, sent in call to `_to`
	 */
	function safeMintBatch(address _to, uint256 _tokenId, uint256 n, bytes memory _data) external;
}

/**
 * @title Alethea Burnable ERC721
 *
 * @notice Defines burn capabilities for Alethea ERC721 tokens.
 *      This interface should be treated as a definition of what burnable means for ERC721
 *
 * @author Basil Gorin
 */
interface BurnableERC721 {
	/**
	 * @notice Destroys the token with token ID specified
	 *
	 * @dev Should be accessible publicly by token owners.
	 *      May have a restricted access handled by the implementation
	 *
	 * @param _tokenId ID of the token to burn
	 */
	function burn(uint256 _tokenId) external;
}

/**
 * @title With Base URI
 *
 * @notice A marker interface for the contracts having the baseURI() function
 *      or public string variable named baseURI
 *      NFT implementations like TinyERC721, or ShortERC721 are example of such smart contracts
 *
 * @author Basil Gorin
 */
interface WithBaseURI {
	/**
	 * @dev Usually used in NFT implementations to construct ERC721Metadata.tokenURI as
	 *      `base URI + token ID` if token URI is not set (not present in `_tokenURIs` mapping)
	 *
	 * @dev For example, if base URI is https://api.com/token/, then token #1
	 *      will have an URI https://api.com/token/1
	 */
	function baseURI() external view returns(string memory);
}

File 4 of 6 : AccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @title Access Control List
 *
 * @notice Access control smart contract provides an API to check
 *      if specific operation is permitted globally and/or
 *      if particular user has a permission to execute it.
 *
 * @notice It deals with two main entities: features and roles.
 *
 * @notice Features are designed to be used to enable/disable specific
 *      functions (public functions) of the smart contract for everyone.
 * @notice User roles are designed to restrict access to specific
 *      functions (restricted functions) of the smart contract to some users.
 *
 * @notice Terms "role", "permissions" and "set of permissions" have equal meaning
 *      in the documentation text and may be used interchangeably.
 * @notice Terms "permission", "single permission" implies only one permission bit set.
 *
 * @notice Access manager is a special role which allows to grant/revoke other roles.
 *      Access managers can only grant/revoke permissions which they have themselves.
 *      As an example, access manager with no other roles set can only grant/revoke its own
 *      access manager permission and nothing else.
 *
 * @notice Access manager permission should be treated carefully, as a super admin permission:
 *      Access manager with even no other permission can interfere with another account by
 *      granting own access manager permission to it and effectively creating more powerful
 *      permission set than its own.
 *
 * @dev Both current and OpenZeppelin AccessControl implementations feature a similar API
 *      to check/know "who is allowed to do this thing".
 * @dev Zeppelin implementation is more flexible:
 *      - it allows setting unlimited number of roles, while current is limited to 256 different roles
 *      - it allows setting an admin for each role, while current allows having only one global admin
 * @dev Current implementation is more lightweight:
 *      - it uses only 1 bit per role, while Zeppelin uses 256 bits
 *      - it allows setting up to 256 roles at once, in a single transaction, while Zeppelin allows
 *        setting only one role in a single transaction
 *
 * @dev This smart contract is designed to be inherited by other
 *      smart contracts which require access control management capabilities.
 *
 * @dev Access manager permission has a bit 255 set.
 *      This bit must not be used by inheriting contracts for any other permissions/features.
 *
 * @author Basil Gorin
 */
contract AccessControl {
	/**
	 * @notice Access manager is responsible for assigning the roles to users,
	 *      enabling/disabling global features of the smart contract
	 * @notice Access manager can add, remove and update user roles,
	 *      remove and update global features
	 *
	 * @dev Role ROLE_ACCESS_MANAGER allows modifying user roles and global features
	 * @dev Role ROLE_ACCESS_MANAGER has single bit at position 255 enabled
	 */
	uint256 public constant ROLE_ACCESS_MANAGER = 0x8000000000000000000000000000000000000000000000000000000000000000;

	/**
	 * @dev Bitmask representing all the possible permissions (super admin role)
	 * @dev Has all the bits are enabled (2^256 - 1 value)
	 */
	uint256 private constant FULL_PRIVILEGES_MASK = type(uint256).max; // before 0.8.0: uint256(-1) overflows to 0xFFFF...

	/**
	 * @notice Privileged addresses with defined roles/permissions
	 * @notice In the context of ERC20/ERC721 tokens these can be permissions to
	 *      allow minting or burning tokens, transferring on behalf and so on
	 *
	 * @dev Maps user address to the permissions bitmask (role), where each bit
	 *      represents a permission
	 * @dev Bitmask 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
	 *      represents all possible permissions
	 * @dev 'This' address mapping represents global features of the smart contract
	 */
	mapping(address => uint256) public userRoles;

	/**
	 * @dev Fired in updateRole() and updateFeatures()
	 *
	 * @param _by operator which called the function
	 * @param _to address which was granted/revoked permissions
	 * @param _requested permissions requested
	 * @param _actual permissions effectively set
	 */
	event RoleUpdated(address indexed _by, address indexed _to, uint256 _requested, uint256 _actual);

	/**
	 * @notice Creates an access control instance,
	 *      setting contract creator to have full privileges
	 */
	constructor() {
		// contract creator has full privileges
		userRoles[msg.sender] = FULL_PRIVILEGES_MASK;
	}

	/**
	 * @notice Retrieves globally set of features enabled
	 *
	 * @dev Effectively reads userRoles role for the contract itself
	 *
	 * @return 256-bit bitmask of the features enabled
	 */
	function features() public view returns(uint256) {
		// features are stored in 'this' address  mapping of `userRoles` structure
		return userRoles[address(this)];
	}

	/**
	 * @notice Updates set of the globally enabled features (`features`),
	 *      taking into account sender's permissions
	 *
	 * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission
	 * @dev Function is left for backward compatibility with older versions
	 *
	 * @param _mask bitmask representing a set of features to enable/disable
	 */
	function updateFeatures(uint256 _mask) public {
		// delegate call to `updateRole`
		updateRole(address(this), _mask);
	}

	/**
	 * @notice Updates set of permissions (role) for a given user,
	 *      taking into account sender's permissions.
	 *
	 * @dev Setting role to zero is equivalent to removing an all permissions
	 * @dev Setting role to `FULL_PRIVILEGES_MASK` is equivalent to
	 *      copying senders' permissions (role) to the user
	 * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission
	 *
	 * @param operator address of a user to alter permissions for or zero
	 *      to alter global features of the smart contract
	 * @param role bitmask representing a set of permissions to
	 *      enable/disable for a user specified
	 */
	function updateRole(address operator, uint256 role) public {
		// caller must have a permission to update user roles
		require(isSenderInRole(ROLE_ACCESS_MANAGER), "access denied");

		// evaluate the role and reassign it
		userRoles[operator] = evaluateBy(msg.sender, userRoles[operator], role);

		// fire an event
		emit RoleUpdated(msg.sender, operator, role, userRoles[operator]);
	}

	/**
	 * @notice Determines the permission bitmask an operator can set on the
	 *      target permission set
	 * @notice Used to calculate the permission bitmask to be set when requested
	 *     in `updateRole` and `updateFeatures` functions
	 *
	 * @dev Calculated based on:
	 *      1) operator's own permission set read from userRoles[operator]
	 *      2) target permission set - what is already set on the target
	 *      3) desired permission set - what do we want set target to
	 *
	 * @dev Corner cases:
	 *      1) Operator is super admin and its permission set is `FULL_PRIVILEGES_MASK`:
	 *        `desired` bitset is returned regardless of the `target` permission set value
	 *        (what operator sets is what they get)
	 *      2) Operator with no permissions (zero bitset):
	 *        `target` bitset is returned regardless of the `desired` value
	 *        (operator has no authority and cannot modify anything)
	 *
	 * @dev Example:
	 *      Consider an operator with the permissions bitmask     00001111
	 *      is about to modify the target permission set          01010101
	 *      Operator wants to set that permission set to          00110011
	 *      Based on their role, an operator has the permissions
	 *      to update only lowest 4 bits on the target, meaning that
	 *      high 4 bits of the target set in this example is left
	 *      unchanged and low 4 bits get changed as desired:      01010011
	 *
	 * @param operator address of the contract operator which is about to set the permissions
	 * @param target input set of permissions to operator is going to modify
	 * @param desired desired set of permissions operator would like to set
	 * @return resulting set of permissions given operator will set
	 */
	function evaluateBy(address operator, uint256 target, uint256 desired) public view returns(uint256) {
		// read operator's permissions
		uint256 p = userRoles[operator];

		// taking into account operator's permissions,
		// 1) enable the permissions desired on the `target`
		target |= p & desired;
		// 2) disable the permissions desired on the `target`
		target &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ desired));

		// return calculated result
		return target;
	}

	/**
	 * @notice Checks if requested set of features is enabled globally on the contract
	 *
	 * @param required set of features to check against
	 * @return true if all the features requested are enabled, false otherwise
	 */
	function isFeatureEnabled(uint256 required) public view returns(bool) {
		// delegate call to `__hasRole`, passing `features` property
		return __hasRole(features(), required);
	}

	/**
	 * @notice Checks if transaction sender `msg.sender` has all the permissions required
	 *
	 * @param required set of permissions (role) to check against
	 * @return true if all the permissions requested are enabled, false otherwise
	 */
	function isSenderInRole(uint256 required) public view returns(bool) {
		// delegate call to `isOperatorInRole`, passing transaction sender
		return isOperatorInRole(msg.sender, required);
	}

	/**
	 * @notice Checks if operator has all the permissions (role) required
	 *
	 * @param operator address of the user to check role for
	 * @param required set of permissions (role) to check
	 * @return true if all the permissions requested are enabled, false otherwise
	 */
	function isOperatorInRole(address operator, uint256 required) public view returns(bool) {
		// delegate call to `__hasRole`, passing operator's permissions (role)
		return __hasRole(userRoles[operator], required);
	}

	/**
	 * @dev Checks if role `actual` contains all the permissions required `required`
	 *
	 * @param actual existent role
	 * @param required required role
	 * @return true if actual has required role (all permissions), false otherwise
	 */
	function __hasRole(uint256 actual, uint256 required) internal pure returns(bool) {
		// check the bitmask for the role required and return the result
		return actual & required == required;
	}
}

File 5 of 6 : ECDSA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 *
 * @dev Copy of the Zeppelin's library:
 *      https://github.com/OpenZeppelin/openzeppelin-contracts/blob/b0cf6fbb7a70f31527f36579ad644e1cf12fdf4e/contracts/utils/cryptography/ECDSA.sol
 */
library ECDSA {
	/**
	 * @dev Returns the address that signed a hashed message (`hash`) with
	 * `signature`. This address can then be used for verification purposes.
	 *
	 * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
	 * this function rejects them by requiring the `s` value to be in the lower
	 * half order, and the `v` value to be either 27 or 28.
	 *
	 * IMPORTANT: `hash` _must_ be the result of a hash operation for the
	 * verification to be secure: it is possible to craft signatures that
	 * recover to arbitrary addresses for non-hashed data. A safe way to ensure
	 * this is by receiving a hash of the original message (which may otherwise
	 * be too long), and then calling {toEthSignedMessageHash} on it.
	 *
	 * Documentation for signature generation:
	 * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
	 * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
	 */
	function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
		// Divide the signature in r, s and v variables
		bytes32 r;
		bytes32 s;
		uint8 v;

		// Check the signature length
		// - case 65: r,s,v signature (standard)
		// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
		if (signature.length == 65) {
			// ecrecover takes the signature parameters, and the only way to get them
			// currently is to use assembly.
			assembly {
				r := mload(add(signature, 0x20))
				s := mload(add(signature, 0x40))
				v := byte(0, mload(add(signature, 0x60)))
			}
		}
		else if (signature.length == 64) {
			// ecrecover takes the signature parameters, and the only way to get them
			// currently is to use assembly.
			assembly {
				let vs := mload(add(signature, 0x40))
				r := mload(add(signature, 0x20))
				s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
				v := add(shr(255, vs), 27)
			}
		}
		else {
			revert("invalid signature length");
		}

		return recover(hash, v, r, s);
	}

	/**
	 * @dev Overload of {ECDSA-recover} that receives the `v`,
	 * `r` and `s` signature fields separately.
	 */
	function recover(
		bytes32 hash,
		uint8 v,
		bytes32 r,
		bytes32 s
	) internal pure returns (address) {
		// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
		// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
		// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
		// signatures from current libraries generate a unique signature with an s-value in the lower half order.
		//
		// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
		// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
		// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
		// these malleable signatures as well.
		require(
			uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
			"invalid signature 's' value"
		);
		require(v == 27 || v == 28, "invalid signature 'v' value");

		// If the signature is valid (and not malleable), return the signer address
		address signer = ecrecover(hash, v, r, s);
		require(signer != address(0), "invalid signature");

		return signer;
	}

	/**
	 * @dev Returns an Ethereum Signed Message, created from a `hash`. This
	 * produces hash corresponding to the one signed with the
	 * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
	 * JSON-RPC method as part of EIP-191.
	 *
	 * See {recover}.
	 */
	function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
		// 32 is the length in bytes of hash,
		// enforced by the type signature above
		return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
	}

	/**
	 * @dev Returns an Ethereum Signed Typed Data, created from a
	 * `domainSeparator` and a `structHash`. This produces hash corresponding
	 * to the one signed with the
	 * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
	 * JSON-RPC method as part of EIP-712.
	 *
	 * See {recover}.
	 */
	function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
		return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
	}
}

File 6 of 6 : ERC165Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @title ERC-165 Standard Interface Detection
 *
 * @dev Interface of the ERC165 standard, as defined in the
 *       https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * @dev Implementers can declare support of contract interfaces,
 *      which can then be queried by others.
 *
 * @author Christian Reitwießner, Nick Johnson, Fabian Vogelsteller, Jordi Baylina, Konrad Feldmeier, William Entriken
 */
interface ERC165 {
	/**
	 * @notice Query if a contract implements an interface
	 *
	 * @dev Interface identification is specified in ERC-165.
	 *      This function uses less than 30,000 gas.
	 *
	 * @param interfaceID The interface identifier, as specified in ERC-165
	 * @return `true` if the contract implements `interfaceID` and
	 *      `interfaceID` is not 0xffffffff, `false` otherwise
	 */
	function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_target","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_requested","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_actual","type":"uint256"}],"name":"RoleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"TokenMintLimitUpdated","type":"event"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEATURE_REDEEM_ACTIVE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTBATCH_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_ACCESS_MANAGER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_AUTHORIZATION_MANAGER","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_MINT_LIMIT_MANAGER","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"target","type":"uint256"},{"internalType":"uint256","name":"desired","type":"uint256"}],"name":"evaluateBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"features","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isFeatureEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isOperatorInRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isSenderInRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokenMintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"mintBatchWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"mintWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMintCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mask","type":"uint256"}],"name":"updateFeatures","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"role","type":"uint256"}],"name":"updateRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenMintLimit","type":"uint256"}],"name":"updateTokenMintLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b5060405162001598380380620015988339810160408190526200003491620002cf565b33600090815260208190526040902060001990556001600160a01b038116620000a45760405162461bcd60e51b815260206004820152601a60248201527f74617267657420636f6e7472616374206973206e6f742073657400000000000060448201526064015b60405180910390fd5b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038216906301ffc9a79060240160206040518083038186803b158015620000eb57600080fd5b505afa15801562000100573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000126919062000301565b8015620001b057506040516301ffc9a760e01b8152633197b5d160e21b60048201526001600160a01b038216906301ffc9a79060240160206040518083038186803b1580156200017557600080fd5b505afa1580156200018a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b0919062000301565b620001fe5760405162461bcd60e51b815260206004820152601660248201527f756e65787065637465642074617267657420747970650000000000000000000060448201526064016200009b565b6001600160601b0319606082901b166080526103e8600255604080518082018252600c81526b22a9219b9918a6b4b73a32b960a11b6020918201529051620002ad917f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866917fa72986cf2e84c8e2bcbe7c0e1ecaa1e88cd80d547ea7b949d5dcd2b92edeabe7914691309101938452602084019290925260408301526001600160a01b0316606082015260800190565b60408051601f19818403018152919052805160209091012060a0525062000325565b600060208284031215620002e257600080fd5b81516001600160a01b0381168114620002fa57600080fd5b9392505050565b6000602082840312156200031457600080fd5b81518015158114620002fa57600080fd5b60805160601c60a05161123562000363600039600081816101f40152610c7b0152600081816102f90152818161089c0152610bb201526112356000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063a1155f50116100de578063d1333c9811610097578063e94a010211610071578063e94a010214610393578063f822d5aa146103cc578063fcc2c078146103df578063ff2642cf146103f257600080fd5b8063d1333c9814610346578063d5bb7f6714610359578063d91694871461036c57600080fd5b8063a1155f50146102ba578063ae5b102e146102c3578063ae682e2e146102d6578063ba652d18146102e1578063bd90df70146102f4578063c688d6931461033357600080fd5b80635a049a70116101305780635a049a701461022b5780635c39eeb51461023e5780636fe41ee414610265578063725f36261461026d57806374d5e100146102905780638f6a046c146102b057600080fd5b806311a8278a1461017857806320606b701461019c57806325ada770146101d15780632b521416146101da5780633644e515146101ef57806352d8a87c14610216575b600080fd5b6101826201000081565b60405163ffffffff90911681526020015b60405180910390f35b6101c37f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b604051908152602001610193565b6101c360015481565b306000908152602081905260409020546101c3565b6101c37f000000000000000000000000000000000000000000000000000000000000000081565b61022961022436600461114b565b610419565b005b6102296102393660046110ca565b61048d565b6101c37f67c2bc25c87d2f7202a6c00ccb845fe254f34def701c1f45f93e7e9219b1ebb281565b610182600181565b61028061027b36600461114b565b610538565b6040519015158152602001610193565b6101c361029e366004610f7e565b60006020819052908152604090205481565b6101826202000081565b6101c360025481565b6102296102d13660046110a0565b610553565b6101c3600160ff1b81565b6102296102ef366004611017565b6105fd565b61031b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610193565b6102806103413660046110a0565b610905565b610229610354366004610f99565b61092a565b61022961036736600461114b565b610c1a565b6101c37f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742981565b6102806103a13660046110a0565b6001600160a01b03919091166000908152600360209081526040808320938352929052205460ff1690565b6101c36103da366004611118565b610c27565b6102806103ed36600461114b565b610c52565b6101c37faf4e98e5c9896ed6453d82e308a87caa8a02787c2c671d5a8cd308f9a99ed41f81565b61042562020000610c52565b61044a5760405162461bcd60e51b81526004016104419061118f565b60405180910390fd5b600254604080519182526020820183905233917f6d74a65a0a51fed60628f3559d4289c2aade63a663302b58bebe3a281fbaed67910160405180910390a2600255565b604080517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742960208201526001600160a01b03871691810191909152606081018590526000906104f1906080015b604051602081830303815290604052858585610c5e565b9050856001600160a01b0316816001600160a01b0316146105245760405162461bcd60e51b815260040161044190611164565b61053086866001610ce0565b505050505050565b30600090815260208190526040812054821682145b92915050565b610560600160ff1b610c52565b61057c5760405162461bcd60e51b81526004016104419061118f565b6001600160a01b0382166000908152602081905260409020546105a190339083610c27565b6001600160a01b03831660008181526020818152604091829020849055815185815290810193909352909133917f5a10526456f5116c0b7b80582c217d666243fd51b6a2d92c8011e601c2462e5f910160405180910390a35050565b6106076001610538565b61064a5760405162461bcd60e51b81526020600482015260146024820152731c995919595b5cc8185c9948191a5cd8589b195960621b6044820152606401610441565b6002548760015461065b91906111b6565b11156106a95760405162461bcd60e51b815260206004820181905260248201527f6d696e74696e67204c696d697420686173206265656e207265616368656421216044820152606401610441565b604080517f67c2bc25c87d2f7202a6c00ccb845fe254f34def701c1f45f93e7e9219b1ebb260208201526001600160a01b03808d1692820192909252908a1660608201526080810189905260a0810188905260c0810187905260e08101869052610100810185905260009061072190610120016104da565b90508a6001600160a01b0316816001600160a01b0316146107545760405162461bcd60e51b815260040161044190611164565b6107618162010000610905565b61079e5760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642061636365737360901b6044820152606401610441565b8642116107e75760405162461bcd60e51b81526020600482015260176024820152761cda59db985d1d5c99481b9bdd081e595d081d985b1a59604a1b6044820152606401610441565b85421061082a5760405162461bcd60e51b81526020600482015260116024820152701cda59db985d1d5c9948195e1c1a5c9959607a1b6044820152606401610441565b6001600160a01b038a1633146108525760405162461bcd60e51b81526004016104419061118f565b8760015461086091906111b6565b60015561086f8b866000610ce0565b604051631740d57560e11b81526001600160a01b038b81166004830152602482018b9052604482018a90527f00000000000000000000000000000000000000000000000000000000000000001690632e81aaea90606401600060405180830381600087803b1580156108e057600080fd5b505af11580156108f4573d6000803e3d6000fd5b505050505050505050505050505050565b6001600160a01b038216600090815260208190526040812054821682145b9392505050565b6109346001610538565b6109775760405162461bcd60e51b81526020600482015260146024820152731c995919595b5cc8185c9948191a5cd8589b195960621b6044820152606401610441565b600254600154106109ca5760405162461bcd60e51b815260206004820181905260248201527f6d696e74696e67204c696d697420686173206265656e207265616368656421216044820152606401610441565b604080517faf4e98e5c9896ed6453d82e308a87caa8a02787c2c671d5a8cd308f9a99ed41f60208201526001600160a01b03808c169282019290925290891660608201526080810188905260a0810187905260c0810186905260e08101859052600090610a3a90610100016104da565b9050896001600160a01b0316816001600160a01b031614610a6d5760405162461bcd60e51b815260040161044190611164565b610a7a8162010000610905565b610ab75760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642061636365737360901b6044820152606401610441565b864211610b005760405162461bcd60e51b81526020600482015260176024820152761cda59db985d1d5c99481b9bdd081e595d081d985b1a59604a1b6044820152606401610441565b854210610b435760405162461bcd60e51b81526020600482015260116024820152701cda59db985d1d5c9948195e1c1a5c9959607a1b6044820152606401610441565b6001600160a01b0389163314610b6b5760405162461bcd60e51b81526004016104419061118f565b60018054906000610b7b836111ce565b9190505550610b8c8a866000610ce0565b6040516340c10f1960e01b81526001600160a01b038a81166004830152602482018a90527f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b158015610bf657600080fd5b505af1158015610c0a573d6000803e3d6000fd5b5050505050505050505050505050565b610c243082610553565b50565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b600061054d3383610905565b835160208086019190912060405161190160f01b928101929092527f000000000000000000000000000000000000000000000000000000000000000060228301526042820181905260009182906062016040516020818303038152906040528051906020012090506000610cd482888888610dee565b98975050505050505050565b6001600160a01b038316600090815260036020908152604080832085845290915290205460ff1615610d445760405162461bcd60e51b815260206004820152600d60248201526c696e76616c6964206e6f6e636560981b6044820152606401610441565b6001600160a01b03831660009081526003602090815260408083208584529091529020805460ff191660011790558015610db35760405182906001600160a01b038516907f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d8190600090a3505050565b60405182906001600160a01b038516907f98de503528ee59b575ef0c0a2576a82497bfc029a5685b209e9ec333479b10a590600090a3505050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115610e605760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202773272076616c756500000000006044820152606401610441565b8360ff16601b1480610e7557508360ff16601c145b610ec15760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202776272076616c756500000000006044820152606401610441565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015610f15573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610f485760405162461bcd60e51b815260040161044190611164565b95945050505050565b80356001600160a01b0381168114610f6857600080fd5b919050565b803560ff81168114610f6857600080fd5b600060208284031215610f9057600080fd5b61092382610f51565b60008060008060008060008060006101208a8c031215610fb857600080fd5b610fc18a610f51565b9850610fcf60208b01610f51565b975060408a0135965060608a0135955060808a0135945060a08a01359350610ff960c08b01610f6d565b925060e08a013591506101008a013590509295985092959850929598565b6000806000806000806000806000806101408b8d03121561103757600080fd5b6110408b610f51565b995061104e60208c01610f51565b985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935061107f60e08c01610f6d565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600080604083850312156110b357600080fd5b6110bc83610f51565b946020939093013593505050565b600080600080600060a086880312156110e257600080fd5b6110eb86610f51565b94506020860135935061110060408701610f6d565b94979396509394606081013594506080013592915050565b60008060006060848603121561112d57600080fd5b61113684610f51565b95602085013595506040909401359392505050565b60006020828403121561115d57600080fd5b5035919050565b602080825260119082015270696e76616c6964207369676e617475726560781b604082015260600190565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b600082198211156111c9576111c96111e9565b500190565b60006000198214156111e2576111e26111e9565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220a467b60ef6ab1fc854a58cc2d7612a65317cce8d623b62442969df680fe11e3e64736f6c63430008070033000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101735760003560e01c8063a1155f50116100de578063d1333c9811610097578063e94a010211610071578063e94a010214610393578063f822d5aa146103cc578063fcc2c078146103df578063ff2642cf146103f257600080fd5b8063d1333c9814610346578063d5bb7f6714610359578063d91694871461036c57600080fd5b8063a1155f50146102ba578063ae5b102e146102c3578063ae682e2e146102d6578063ba652d18146102e1578063bd90df70146102f4578063c688d6931461033357600080fd5b80635a049a70116101305780635a049a701461022b5780635c39eeb51461023e5780636fe41ee414610265578063725f36261461026d57806374d5e100146102905780638f6a046c146102b057600080fd5b806311a8278a1461017857806320606b701461019c57806325ada770146101d15780632b521416146101da5780633644e515146101ef57806352d8a87c14610216575b600080fd5b6101826201000081565b60405163ffffffff90911681526020015b60405180910390f35b6101c37f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b604051908152602001610193565b6101c360015481565b306000908152602081905260409020546101c3565b6101c37fad86e9b1a125f22d1703e10e3aee42b417379544fd864ec5ac93be1e129a9f1d81565b61022961022436600461114b565b610419565b005b6102296102393660046110ca565b61048d565b6101c37f67c2bc25c87d2f7202a6c00ccb845fe254f34def701c1f45f93e7e9219b1ebb281565b610182600181565b61028061027b36600461114b565b610538565b6040519015158152602001610193565b6101c361029e366004610f7e565b60006020819052908152604090205481565b6101826202000081565b6101c360025481565b6102296102d13660046110a0565b610553565b6101c3600160ff1b81565b6102296102ef366004611017565b6105fd565b61031b7f000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af81565b6040516001600160a01b039091168152602001610193565b6102806103413660046110a0565b610905565b610229610354366004610f99565b61092a565b61022961036736600461114b565b610c1a565b6101c37f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742981565b6102806103a13660046110a0565b6001600160a01b03919091166000908152600360209081526040808320938352929052205460ff1690565b6101c36103da366004611118565b610c27565b6102806103ed36600461114b565b610c52565b6101c37faf4e98e5c9896ed6453d82e308a87caa8a02787c2c671d5a8cd308f9a99ed41f81565b61042562020000610c52565b61044a5760405162461bcd60e51b81526004016104419061118f565b60405180910390fd5b600254604080519182526020820183905233917f6d74a65a0a51fed60628f3559d4289c2aade63a663302b58bebe3a281fbaed67910160405180910390a2600255565b604080517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742960208201526001600160a01b03871691810191909152606081018590526000906104f1906080015b604051602081830303815290604052858585610c5e565b9050856001600160a01b0316816001600160a01b0316146105245760405162461bcd60e51b815260040161044190611164565b61053086866001610ce0565b505050505050565b30600090815260208190526040812054821682145b92915050565b610560600160ff1b610c52565b61057c5760405162461bcd60e51b81526004016104419061118f565b6001600160a01b0382166000908152602081905260409020546105a190339083610c27565b6001600160a01b03831660008181526020818152604091829020849055815185815290810193909352909133917f5a10526456f5116c0b7b80582c217d666243fd51b6a2d92c8011e601c2462e5f910160405180910390a35050565b6106076001610538565b61064a5760405162461bcd60e51b81526020600482015260146024820152731c995919595b5cc8185c9948191a5cd8589b195960621b6044820152606401610441565b6002548760015461065b91906111b6565b11156106a95760405162461bcd60e51b815260206004820181905260248201527f6d696e74696e67204c696d697420686173206265656e207265616368656421216044820152606401610441565b604080517f67c2bc25c87d2f7202a6c00ccb845fe254f34def701c1f45f93e7e9219b1ebb260208201526001600160a01b03808d1692820192909252908a1660608201526080810189905260a0810188905260c0810187905260e08101869052610100810185905260009061072190610120016104da565b90508a6001600160a01b0316816001600160a01b0316146107545760405162461bcd60e51b815260040161044190611164565b6107618162010000610905565b61079e5760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642061636365737360901b6044820152606401610441565b8642116107e75760405162461bcd60e51b81526020600482015260176024820152761cda59db985d1d5c99481b9bdd081e595d081d985b1a59604a1b6044820152606401610441565b85421061082a5760405162461bcd60e51b81526020600482015260116024820152701cda59db985d1d5c9948195e1c1a5c9959607a1b6044820152606401610441565b6001600160a01b038a1633146108525760405162461bcd60e51b81526004016104419061118f565b8760015461086091906111b6565b60015561086f8b866000610ce0565b604051631740d57560e11b81526001600160a01b038b81166004830152602482018b9052604482018a90527f000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af1690632e81aaea90606401600060405180830381600087803b1580156108e057600080fd5b505af11580156108f4573d6000803e3d6000fd5b505050505050505050505050505050565b6001600160a01b038216600090815260208190526040812054821682145b9392505050565b6109346001610538565b6109775760405162461bcd60e51b81526020600482015260146024820152731c995919595b5cc8185c9948191a5cd8589b195960621b6044820152606401610441565b600254600154106109ca5760405162461bcd60e51b815260206004820181905260248201527f6d696e74696e67204c696d697420686173206265656e207265616368656421216044820152606401610441565b604080517faf4e98e5c9896ed6453d82e308a87caa8a02787c2c671d5a8cd308f9a99ed41f60208201526001600160a01b03808c169282019290925290891660608201526080810188905260a0810187905260c0810186905260e08101859052600090610a3a90610100016104da565b9050896001600160a01b0316816001600160a01b031614610a6d5760405162461bcd60e51b815260040161044190611164565b610a7a8162010000610905565b610ab75760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642061636365737360901b6044820152606401610441565b864211610b005760405162461bcd60e51b81526020600482015260176024820152761cda59db985d1d5c99481b9bdd081e595d081d985b1a59604a1b6044820152606401610441565b854210610b435760405162461bcd60e51b81526020600482015260116024820152701cda59db985d1d5c9948195e1c1a5c9959607a1b6044820152606401610441565b6001600160a01b0389163314610b6b5760405162461bcd60e51b81526004016104419061118f565b60018054906000610b7b836111ce565b9190505550610b8c8a866000610ce0565b6040516340c10f1960e01b81526001600160a01b038a81166004830152602482018a90527f000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af16906340c10f1990604401600060405180830381600087803b158015610bf657600080fd5b505af1158015610c0a573d6000803e3d6000fd5b5050505050505050505050505050565b610c243082610553565b50565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b600061054d3383610905565b835160208086019190912060405161190160f01b928101929092527fad86e9b1a125f22d1703e10e3aee42b417379544fd864ec5ac93be1e129a9f1d60228301526042820181905260009182906062016040516020818303038152906040528051906020012090506000610cd482888888610dee565b98975050505050505050565b6001600160a01b038316600090815260036020908152604080832085845290915290205460ff1615610d445760405162461bcd60e51b815260206004820152600d60248201526c696e76616c6964206e6f6e636560981b6044820152606401610441565b6001600160a01b03831660009081526003602090815260408083208584529091529020805460ff191660011790558015610db35760405182906001600160a01b038516907f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d8190600090a3505050565b60405182906001600160a01b038516907f98de503528ee59b575ef0c0a2576a82497bfc029a5685b209e9ec333479b10a590600090a3505050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115610e605760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202773272076616c756500000000006044820152606401610441565b8360ff16601b1480610e7557508360ff16601c145b610ec15760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207369676e6174757265202776272076616c756500000000006044820152606401610441565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015610f15573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610f485760405162461bcd60e51b815260040161044190611164565b95945050505050565b80356001600160a01b0381168114610f6857600080fd5b919050565b803560ff81168114610f6857600080fd5b600060208284031215610f9057600080fd5b61092382610f51565b60008060008060008060008060006101208a8c031215610fb857600080fd5b610fc18a610f51565b9850610fcf60208b01610f51565b975060408a0135965060608a0135955060808a0135945060a08a01359350610ff960c08b01610f6d565b925060e08a013591506101008a013590509295985092959850929598565b6000806000806000806000806000806101408b8d03121561103757600080fd5b6110408b610f51565b995061104e60208c01610f51565b985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935061107f60e08c01610f6d565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600080604083850312156110b357600080fd5b6110bc83610f51565b946020939093013593505050565b600080600080600060a086880312156110e257600080fd5b6110eb86610f51565b94506020860135935061110060408701610f6d565b94979396509394606081013594506080013592915050565b60008060006060848603121561112d57600080fd5b61113684610f51565b95602085013595506040909401359392505050565b60006020828403121561115d57600080fd5b5035919050565b602080825260119082015270696e76616c6964207369676e617475726560781b604082015260600190565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b600082198211156111c9576111c96111e9565b500190565b60006000198214156111e2576111e26111e9565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220a467b60ef6ab1fc854a58cc2d7612a65317cce8d623b62442969df680fe11e3e64736f6c63430008070033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af

-----Decoded View---------------
Arg [0] : _target (address): 0xcE69a87C02bAA8C5F17Ed7eB8B1C2657aFC2E1aF

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ce69a87c02baa8c5f17ed7eb8b1c2657afc2e1af


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.