Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xa451d21cb4e6ed4c471b357770b2dc76df80ad084a9df6de85426e0bda6cc9d7 | 32321926 | 219 days 1 hr ago | 0x4e59b44847b379578588920ca78fbf26c0b4956c | Contract Creation | 0 MATIC |
[ Download CSV Export ]
Contract Name:
GatedEditionCreator
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library ClonesUpgradeable { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = _setInitializedVersion(1); if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { bool isTopLevelCall = _setInitializedVersion(version); if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(version); } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { _setInitializedVersion(type(uint8).max); } function _setInitializedVersion(uint8 version) private returns (bool) { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level // of initializers, because in other contexts the contract may have been reentered. if (_initializing) { require( version == 1 && !AddressUpgradeable.isContract(address(this)), "Initializable: contract is already initialized" ); return false; } else { require(_initialized < version, "Initializable: contract is already initialized"); _initialized = version; return true; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // 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 { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; interface IEditionSingleMintable { function mintEdition(address to) external returns (uint256); function mintEditions(address[] memory to) external returns (uint256); function numberCanMint() external view returns (uint256); function owner() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IGatedEditionMinter } from "./interfaces/IGatedEditionMinter.sol"; import { IShowtimeVerifier, Attestation, SignedAttestation } from "src/interfaces/IShowtimeVerifier.sol"; import { ISingleEditionMintableCreator, IEditionSingleMintable } from "./interfaces/ISingleEditionMintableCreator.sol"; import { MetaEditionMinter } from "./MetaEditionMinter.sol"; import { MetaEditionMinterFactory } from "./MetaEditionMinterFactory.sol"; import { TimeCop } from "./TimeCop.sol"; interface _IEditionSingleMintable { function transferOwnership(address newOwner) external; function setApprovedMinter(address minter, bool allowed) external; } contract GatedEditionCreator { error NullAddress(); error VerificationFailed(); error UnexpectedContext(address context); string constant SYMBOL = "SHOWTIME"; ISingleEditionMintableCreator public immutable editionCreator; IGatedEditionMinter public immutable minter; IShowtimeVerifier public immutable showtimeVerifier; TimeCop public immutable timeCop; constructor( address _editionCreator, address _minter, address _timeCop ) { if (_editionCreator == address(0) || _minter == address(0) || _timeCop == address(0)) { revert NullAddress(); } editionCreator = ISingleEditionMintableCreator(_editionCreator); minter = IGatedEditionMinter(_minter); timeCop = TimeCop(_timeCop); showtimeVerifier = IGatedEditionMinter(_minter).showtimeVerifier(); } /// Creates a new edition contract as a factory with a deterministic address /// Important: None of these fields (except the Url fields with the same hash) can be changed after calling /// @param name Name of the edition contract /// @param description Metadata: Description of the edition entry /// @param animationUrl Metadata: Animation url (optional) of the edition entry /// @param imageUrl Metadata: Image url (semi-required) of the edition entry /// @param editionSize Total size of the edition (number of possible editions) /// @param royaltyBPS BPS amount of royalty /// @param claimWindowDurationSeconds How long after deployment the edition can be claimed, in seconds /// @param signedAttestation the attestation to verify along with a corresponding signature /// @dev we expect the signed attestation's context to correspond to this contract's address /// @dev we expect the signed attestation's beneficiary to be the edition's creator /// @return the address of the created edition function createEdition( // ISingleEditionMintableCreator parameters string memory name, string memory description, string memory animationUrl, string memory imageUrl, uint256 editionSize, uint256 royaltyBPS, // additional parameters uint256 claimWindowDurationSeconds, SignedAttestation calldata signedAttestation ) external returns (address) { validateAttestation(signedAttestation); // deploy the new edition IEditionSingleMintable edition = editionCreator.getEditionAtId( editionCreator.createEdition( name, SYMBOL, description, animationUrl, 0, // animation hash imageUrl, 0, // image hash editionSize, royaltyBPS ) ); configureEdition(edition, signedAttestation, claimWindowDurationSeconds); return address(edition); } function getEditionAtId(uint256 editionId) external view returns (IEditionSingleMintable) { return editionCreator.getEditionAtId(editionId); } function validateAttestation(SignedAttestation calldata signedAttestation) internal returns (bool) { // verify that the context for this attestation is valid address context = signedAttestation.attestation.context; if (context != address(this)) { revert UnexpectedContext(context); } // verify attestation if (!showtimeVerifier.verifyAndBurn(signedAttestation)) { revert VerificationFailed(); } return true; } function configureEdition( IEditionSingleMintable edition, // address creator, SignedAttestation calldata signedAttestation, uint256 _claimWindowDurationSeconds ) internal { address creator = signedAttestation.attestation.beneficiary; // configure the time limit timeCop.setTimeLimit(address(edition), _claimWindowDurationSeconds); // configure the edition (while we still own it) _IEditionSingleMintable(address(edition)).setApprovedMinter(address(minter), true); // auto claim one for the creator edition.mintEdition(creator); // and finally transfer ownership of the configured contract to the actual creator _IEditionSingleMintable(address(edition)).transferOwnership(creator); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { IEditionSingleMintable } from "@zoralabs/nft-editions-contracts/contracts/IEditionSingleMintable.sol"; import { BaseRelayRecipient } from "../utils/BaseRelayRecipient.sol"; import { IEditionMinter } from "./interfaces/IEditionMinter.sol"; import { TimeCop } from "./TimeCop.sol"; contract MetaEditionMinter is BaseRelayRecipient, IEditionMinter, Initializable { event Destroyed(MetaEditionMinter minter, IEditionSingleMintable collection); error NullAddress(); error AlreadyMinted(IEditionSingleMintable collection, address operator); error TimeLimitReached(IEditionSingleMintable collection); error TimeLimitNotReached(IEditionSingleMintable collection); /// @dev these would be immutable if they were not set in the initializer IEditionSingleMintable public collection; TimeCop public timeCop; mapping(address => bool) public minted; /// @dev deploy the initial implementation via constructor and lock the contract, preventing calls to initialize() constructor() { _disableInitializers(); } function initialize( address _trustedForwarder, IEditionSingleMintable _collection, TimeCop _timeCop ) external initializer { if (address(_collection) == address(0)) { revert NullAddress(); } if (address(_timeCop) == address(0)) { revert NullAddress(); } // we accept the null address for the trusted forwarder (meta-tx disabled) trustedForwarder = _trustedForwarder; collection = _collection; timeCop = _timeCop; } function mintEdition(address _to) external override { if (timeCop.timeLimitReached(address(collection))) { revert TimeLimitReached(collection); } address operator = _msgSender(); recordMint(operator); if (operator != _to) { recordMint(_to); } collection.mintEdition(_to); } function recordMint(address minter) internal { if (minted[minter]) { revert AlreadyMinted(collection, minter); } minted[minter] = true; } /// @notice deletes the record of who minted for that collection if we are past the claim window /// @notice no-op if there was no time limit set or it has not expired yet function purge() external { // collection is not set in the implementation contract if (address(collection) == address(0)) { revert NullAddress(); } bool expired = timeCop.timeLimitReached(address(collection)); if (!expired) { revert TimeLimitNotReached(collection); } emit Destroyed(this, collection); selfdestruct(payable(collection.owner())); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { ClonesUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/ClonesUpgradeable.sol"; import { IEditionSingleMintable } from "@zoralabs/nft-editions-contracts/contracts/IEditionSingleMintable.sol"; import { MetaEditionMinter } from "./MetaEditionMinter.sol"; import { TimeCop } from "./TimeCop.sol"; contract MetaEditionMinterFactory { error NullAddress(); address public immutable trustedForwarder; MetaEditionMinter public immutable minterImpl; TimeCop public immutable timeCop; constructor (address _trustedForwarder, address _timeCop) { if (_timeCop == address(0)) { revert NullAddress(); } /// @dev we accept the null address for the trusted forwarder (meta-tx disabled) trustedForwarder = _trustedForwarder; timeCop = TimeCop(_timeCop); /// @dev this deploys and locks down the base implementation, which we will later deploy proxies to minterImpl = new MetaEditionMinter(); } /// returns an initialized minimal proxy to the base MetaEditionMinter implementation function createMinter(IEditionSingleMintable _edition) public returns (MetaEditionMinter newMinter) { // deploy the minter for this edition newMinter = MetaEditionMinter( ClonesUpgradeable.cloneDeterministic( address(minterImpl), bytes32(uint256(uint160(address(_edition)))) ) ); newMinter.initialize(trustedForwarder, _edition, timeCop); } function getMinterForEdition(address edition) public view returns (address) { return ClonesUpgradeable.predictDeterministicAddress( address(minterImpl), bytes32(uint256(uint160(edition))) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; contract TimeCop { event TimeLimitSet(address collection, uint256 deadline); error InvalidTimeLimit(uint256 offsetSeconds); error NotCollectionOwner(); error TimeLimitAlreadySet(); uint256 public immutable MAX_DURATION_SECONDS; /// @notice the time limits expressed as a timestamp in seconds mapping(address => uint256) public timeLimits; /// @param _maxDurationSeconds maximum time limit /// @dev _maxDurationSeconds can be set to 0 to have no maximum time limit constructor(uint256 _maxDurationSeconds) { MAX_DURATION_SECONDS = _maxDurationSeconds; } /// @notice Sets the deadline for the given collection /// @notice Only the owner of the collection can set the deadline /// @param collection The address to set the deadline for /// @param offsetSeconds a duration in seconds that will be used to set the time limit function setTimeLimit(address collection, uint256 offsetSeconds) external { if (offsetSeconds == 0) { revert InvalidTimeLimit(offsetSeconds); } if (MAX_DURATION_SECONDS > 0 && offsetSeconds > MAX_DURATION_SECONDS) { revert InvalidTimeLimit(offsetSeconds); } if (timeLimitSet(collection)) { revert TimeLimitAlreadySet(); } if (msg.sender != Ownable(collection).owner()) { revert NotCollectionOwner(); } uint256 deadline = block.timestamp + offsetSeconds; timeLimits[collection] = deadline; emit TimeLimitSet(collection, deadline); } function timeLimitSet(address collection) public view returns (bool) { return timeLimits[collection] > 0; } /// @return false if there is no time limit set for that collection function timeLimitReached(address collection) public view returns (bool) { return timeLimitSet(collection) && block.timestamp > timeLimits[collection]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; interface IEditionMinter { function mintEdition(address _to) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IShowtimeVerifier, SignedAttestation } from "src/interfaces/IShowtimeVerifier.sol"; interface IGatedEditionMinter { function mintEdition(SignedAttestation calldata signedAttestation) external; function mintEditions(SignedAttestation[] calldata signedAttestation) external; function showtimeVerifier() external view returns (IShowtimeVerifier); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { IEditionSingleMintable } from "@zoralabs/nft-editions-contracts/contracts/IEditionSingleMintable.sol"; interface ISingleEditionMintableCreator { /// @return The ID of the created edition function createEdition( string memory _name, string memory _symbol, string memory _description, string memory _animationUrl, bytes32 _animationHash, string memory _imageUrl, bytes32 _imageHash, uint256 _editionSize, uint256 _royaltyBPS ) external returns (uint256); /// Get edition given the created ID /// @param editionId id of edition to get contract for /// @return SingleEditionMintable Edition NFT contract function getEditionAtId(uint256 editionId) external view returns (IEditionSingleMintable); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; struct Attestation { address beneficiary; address context; uint256 nonce; uint256 validUntil; } struct SignedAttestation { Attestation attestation; bytes signature; } interface IShowtimeVerifier { error BadNonce(uint256 expected, uint256 actual); error DeadlineTooLong(); error Expired(); error NullAddress(); error SignerExpired(address signer); error Unauthorized(); error UnknownSigner(); event SignerAdded(address signer, uint256 validUntil); event SignerRevoked(address signer); event ManagerUpdated(address newManager); function verify(SignedAttestation calldata signedAttestation) external view returns (bool); function verifyAndBurn(SignedAttestation calldata signedAttestation) external returns (bool); function verify( Attestation calldata attestation, bytes32 typeHash, bytes memory encodedData, bytes calldata signature ) external view returns (bool); function verifyAndBurn( Attestation calldata attestation, bytes32 typeHash, bytes memory encodedData, bytes calldata signature ) external returns (bool); function setManager(address _manager) external; function registerSigner(address signer, uint256 validityDays) external returns (uint256 validUntil); function revokeSigner(address signer) external; function registerAndRevoke( address signerToRegister, address signerToRevoke, uint256 validityDays ) external returns (uint256 validUntil); }
// SPDX-License-Identifier:MIT pragma solidity ^0.8.7; /** * A base contract to be inherited by any contract that want to receive relayed transactions * A subclass must use "_msgSender()" instead of "msg.sender" */ abstract contract BaseRelayRecipient { /* * Forwarder singleton we accept calls from */ address public trustedForwarder; /* * require a function to be called through GSN only */ modifier trustedForwarderOnly() { require(msg.sender == address(trustedForwarder), "Function can only be called through the trusted Forwarder"); _; } function isTrustedForwarder(address forwarder) public view returns (bool) { return forwarder == trustedForwarder; } /** * return the sender of this call. * if the call came through our trusted forwarder, return the original sender. * otherwise, return `msg.sender`. * should be used in the contract anywhere instead of msg.sender */ function _msgSender() internal view virtual returns (address ret) { if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) { // At this point we know that the sender is a trusted forwarder, // so we trust that the last bytes of msg.data are the verified sender address. // extract sender address from the end of msg.data assembly { ret := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return msg.sender; } } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "none", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000000 }, "remappings": [], "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_editionCreator","type":"address"},{"internalType":"address","name":"_minter","type":"address"},{"internalType":"address","name":"_timeCop","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NullAddress","type":"error"},{"inputs":[{"internalType":"address","name":"context","type":"address"}],"name":"UnexpectedContext","type":"error"},{"inputs":[],"name":"VerificationFailed","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"animationUrl","type":"string"},{"internalType":"string","name":"imageUrl","type":"string"},{"internalType":"uint256","name":"editionSize","type":"uint256"},{"internalType":"uint256","name":"royaltyBPS","type":"uint256"},{"internalType":"uint256","name":"claimWindowDurationSeconds","type":"uint256"},{"components":[{"components":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"context","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"}],"internalType":"struct Attestation","name":"attestation","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SignedAttestation","name":"signedAttestation","type":"tuple"}],"name":"createEdition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"editionCreator","outputs":[{"internalType":"contract ISingleEditionMintableCreator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"editionId","type":"uint256"}],"name":"getEditionAtId","outputs":[{"internalType":"contract IEditionSingleMintable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"contract IGatedEditionMinter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"showtimeVerifier","outputs":[{"internalType":"contract IShowtimeVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeCop","outputs":[{"internalType":"contract TimeCop","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101008060405234620000be5760608162000f978038038091620000248285620000c3565b833981010312620000be57805162000068916200004182620000fd565b60406020820151916200005483620000fd565b0151916200006283620000fd565b62000137565b604051610d8f9081620002088239608051818181610203015281816102c70152610731015260a05181818160de0152610bd3015260c0518181816101620152610a04015260e05181818161054d0152610b130152f35b600080fd5b601f909101601f19168101906001600160401b03821190821017620000e757604052565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811603620000be57565b90816020910312620000be57516200012781620000fd565b90565b506040513d6000823e3d90fd5b6001600160a01b03908116929083158015620001fc575b8015620001f1575b620001df578060209360049560805216918260a0521660e052604051928380926314d8397560e21b82525afa908115620001cf575b6000916200019a575b5060c052565b620001c0915060203d8111620001c7575b620001b78183620000c3565b8101906200010f565b3862000194565b503d620001ab565b620001d96200012a565b6200018b565b60405163e99d5ac560e01b8152600490fd5b508082161562000156565b50808316156200014e56fe608080604052600436101561001357600080fd5b6000803560e01c918263075461721461009657505080635360e5d41461008d578063ac52edfd14610084578063d33ed8b81461007b578063e4e22e1e146100725763f565d63d14610065575b38600080fd5b61006d610501565b61005f565b5061006d61040e565b5061006d61027b565b5061006d610186565b5061006d610116565b3461010257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101025760209073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b600091031261011157565b600080fd5b50346101115760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346101115760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101115760206040517fac52edfd000000000000000000000000000000000000000000000000000000008152600435600482015273ffffffffffffffffffffffffffffffffffffffff8282602481847f0000000000000000000000000000000000000000000000000000000000000000165afa91821561026e575b60009261023f575b5060405191168152f35b610260919250833d8111610267575b610258818361033c565b8101906106eb565b9038610235565b503d61024e565b6102766106c0565b61022d565b50346101115760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161032f57604052565b6103376102eb565b604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761032f57604052565b81601f820112156101115780359067ffffffffffffffff82116103f3575b604051926103d160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116018561033c565b8284526020838301011161011157816000926020809301838601378301015290565b6103fb6102eb565b61039b565b908160a09103126101115790565b5034610111576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101115767ffffffffffffffff6004803582811161011157610460903690830161037d565b60243583811161011157610477903690840161037d565b6044358481116101115761048e903690850161037d565b90606435858111610111576104a6903690860161037d565b9260e435958611610111576104c46104d6956104fd97369101610400565b9360c4359360a4359360843593610703565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b0390f35b50346101115760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b604051906040820182811067ffffffffffffffff8211176105bc575b604052600882527f53484f5754494d450000000000000000000000000000000000000000000000006020830152565b6105c46102eb565b61058d565b90816020910312610111575190565b91908251928382526000905b84821061062f5750601f84602094957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09311610622575b0116010190565b600085828601015261061b565b906020908180828501015190828601015201906105e4565b9361068c6106af9461067e610100989561067061069a969d9c9b9d610120808c528b01906105d8565b9089820360208b01526105d8565b9087820360408901526105d8565b9085820360608701526105d8565b906000608085015283820360a08501526105d8565b94600060c083015260e08201520152565b506040513d6000823e3d90fd5b73ffffffffffffffffffffffffffffffffffffffff81160361011157565b908160209103126101115751610700816106cd565b90565b916107ea9397969491959261071788610995565b5073ffffffffffffffffffffffffffffffffffffffff98897f0000000000000000000000000000000000000000000000000000000000000000169261079961075d610571565b9660405196879485947f10c3009e00000000000000000000000000000000000000000000000000000000865260209d8e9b8c9960048901610647565b03816000855af191821561086e575b60009261083f575b5060405180809581947fac52edfd000000000000000000000000000000000000000000000000000000008352600483019190602083019252565b03915afa928315610832575b60009361080f575b5050819261080b92610aef565b1690565b61080b9350908161082b92903d1061026757610258818361033c565b91386107fe565b61083a6106c0565b6107f6565b610860919250833d8511610867575b610858818361033c565b8101906105c9565b90386107b0565b503d61084e565b6108766106c0565b6107a8565b35610700816106cd565b90816020910312610111575180151581036101115790565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b906020825280356108ec816106cd565b73ffffffffffffffffffffffffffffffffffffffff80911660208401526020820135610917816106cd565b166040830152604081013560608301526060810135608083015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156101115781019081359067ffffffffffffffff8211610111578136031261011157602060c08460a08061070097015201920161089d565b6109a16020820161087b565b9073ffffffffffffffffffffffffffffffffffffffff913083821603610aa65750610a006000926020926040519485809481937f82059300000000000000000000000000000000000000000000000000000000008352600483016108dc565b03927f0000000000000000000000000000000000000000000000000000000000000000165af1908115610a99575b600091610a6b575b5015610a4157600190565b60046040517f439cc0cd000000000000000000000000000000000000000000000000000000008152fd5b610a8c915060203d8111610a92575b610a84818361033c565b810190610885565b38610a36565b503d610a7a565b610aa16106c0565b610a2e565b6040517fcc49271c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152602490fd5b9190610afa9061087b565b73ffffffffffffffffffffffffffffffffffffffff80807f000000000000000000000000000000000000000000000000000000000000000016941692843b15610111576040517f26d79f7c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602481019190915260009485908290604490829084905af18015610d75575b610d62575b50823b15610d5e576040517f29ec16dd0000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000009190911673ffffffffffffffffffffffffffffffffffffffff16600482015260016024820152838160448183875af18015610d51575b610d3e575b506040517fa66ff0af00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260208160248187875af18015610d31575b610d13575b50813b15610d0f576040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015291908290602490829084905af18015610d02575b610ced5750565b80610cfa610d009261031b565b80610106565b565b610d0a6106c0565b610ce6565b8280fd5b610d2a9060203d811161086757610858818361033c565b5038610c86565b610d396106c0565b610c81565b80610cfa610d4b9261031b565b38610c2d565b610d596106c0565b610c28565b8380fd5b80610cfa610d6f9261031b565b38610ba3565b610d7d6106c0565b610b9e56fea164736f6c634300080d000a0000000000000000000000004500590afc7f12575d613457af01f06b1eee57a300000000000000000000000000d2249ef000002b2fdec16900058800e900000c00000000000000000000000050c001e4eb10801968f6640e1537d63a557e5d72
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004500590afc7f12575d613457af01f06b1eee57a300000000000000000000000000d2249ef000002b2fdec16900058800e900000c00000000000000000000000050c001e4eb10801968f6640e1537d63a557e5d72
-----Decoded View---------------
Arg [0] : _editionCreator (address): 0x4500590afc7f12575d613457af01f06b1eee57a3
Arg [1] : _minter (address): 0x00d2249ef000002b2fdec16900058800e900000c
Arg [2] : _timeCop (address): 0x50c001e4eb10801968f6640e1537d63a557e5d72
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004500590afc7f12575d613457af01f06b1eee57a3
Arg [1] : 00000000000000000000000000d2249ef000002b2fdec16900058800e900000c
Arg [2] : 00000000000000000000000050c001e4eb10801968f6640e1537d63a557e5d72
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.