// SPDX-License-Identifier: MITpragmasolidity 0.8.17;interfaceIHasContractName{
/// @notice Contract name returns the pretty contract namefunctioncontractName() externalreturns (stringmemory);
}
interfaceIContractMetadataisIHasContractName{
/// @notice Contract URI returns the uri for more information about the given contractfunctioncontractURI() externalreturns (stringmemory);
}
Contract Source Code
File 3 of 11: ICreatorCommands.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;/// @notice Creator Commands used by minter modules passed back to the main modulesinterfaceICreatorCommands{
/// @notice This enum is used to define supported creator action types./// This can change in the futureenumCreatorActions {
// No operation - also the default for mintings that may not return a command
NO_OP,
// Send ether
SEND_ETH,
// Mint operation
MINT
}
/// @notice This command is forstructCommand {
// Method for operation
CreatorActions method;
// Arguments used for this operationbytes args;
}
/// @notice This command set is returned from the minter back to the userstructCommandSet {
Command[] commands;
uint256 at;
}
}
Contract Source Code
File 4 of 11: IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165Upgradeable{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import {ILimitedMintPerAddress} from"../../interfaces/ILimitedMintPerAddress.sol";
contractLimitedMintPerAddressisILimitedMintPerAddress{
/// @notice Storage for slot to check user mints/// @notice target contract -> tokenId -> minter user -> numberMinted/// @dev No gap or stroage interface since this is used within non-upgradeable contractsmapping(address=>mapping(uint256=>mapping(address=>uint256))) internal mintedPerAddress;
functiongetMintedPerWallet(address tokenContract, uint256 tokenId, address wallet) externalviewreturns (uint256) {
return mintedPerAddress[tokenContract][tokenId][wallet];
}
function_requireMintNotOverLimitAndUpdate(uint256 limit, uint256 numRequestedMint, address tokenContract, uint256 tokenId, address wallet) internal{
mintedPerAddress[tokenContract][tokenId][wallet] += numRequestedMint;
if (mintedPerAddress[tokenContract][tokenId][wallet] > limit) {
revert UserExceedsMintLimit(wallet, limit, mintedPerAddress[tokenContract][tokenId][wallet]);
}
}
functionsupportsInterface(bytes4 interfaceId) publicpurevirtualoverridereturns (bool) {
return interfaceId ==type(ILimitedMintPerAddress).interfaceId;
}
}
Contract Source Code
File 9 of 11: SaleCommandHelper.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import {ICreatorCommands} from"../../interfaces/ICreatorCommands.sol";
/// @title SaleCommandHelper/// @notice Helper library for creating commands for the sale contract/// @author @iainnash / @tbtstllibrarySaleCommandHelper{
/// @notice Sets the size of commands and initializes command array. Empty entries are skipped by the resolver./// @dev Beware: this removes all previous command entries from memory/// @param commandSet command set struct storage./// @param size size to set for the new structfunctionsetSize(ICreatorCommands.CommandSet memory commandSet, uint256 size) internalpure{
commandSet.commands =new ICreatorCommands.Command[](size);
}
/// @notice Creates a command to mint a token/// @param commandSet The command set to add the command to/// @param to The address to mint to/// @param tokenId The token ID to mint/// @param quantity The quantity of tokens to mintfunctionmint(ICreatorCommands.CommandSet memory commandSet, address to, uint256 tokenId, uint256 quantity) internalpure{
unchecked {
commandSet.commands[commandSet.at++] = ICreatorCommands.Command({
method: ICreatorCommands.CreatorActions.MINT,
args: abi.encode(to, tokenId, quantity)
});
}
}
/// @notice Creates a command to transfer ETH/// @param commandSet The command set to add the command to/// @param to The address to transfer to/// @param amount The amount of ETH to transferfunctiontransfer(ICreatorCommands.CommandSet memory commandSet, address to, uint256 amount) internalpure{
unchecked {
commandSet.commands[commandSet.at++] = ICreatorCommands.Command({method: ICreatorCommands.CreatorActions.SEND_ETH, args: abi.encode(to, amount)});
}
}
}
Contract Source Code
File 10 of 11: SaleStrategy.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import {IERC165Upgradeable} from"@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
import {IMinter1155} from"../interfaces/IMinter1155.sol";
import {IContractMetadata} from"../interfaces/IContractMetadata.sol";
import {IVersionedContract} from"../interfaces/IVersionedContract.sol";
/// @notice Sales Strategy Helper contract template on top of IMinter1155/// @author @iainnash / @tbtstlabstractcontractSaleStrategyisIMinter1155, IVersionedContract, IContractMetadata{
/// @notice This function resets the sales configuration for a given tokenId and contract./// @dev This function is intentioned to be called directly from the affected sales contractfunctionresetSale(uint256 tokenId) externalvirtual;
functionsupportsInterface(bytes4 interfaceId) publicpurevirtualreturns (bool) {
return interfaceId ==type(IMinter1155).interfaceId|| interfaceId ==type(IERC165Upgradeable).interfaceId;
}
}
Contract Source Code
File 11 of 11: ZoraCreatorFixedPriceSaleStrategy.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import {Enjoy} from"_imagine/mint/Enjoy.sol";
import {IMinter1155} from"../../interfaces/IMinter1155.sol";
import {ICreatorCommands} from"../../interfaces/ICreatorCommands.sol";
import {SaleStrategy} from"../SaleStrategy.sol";
import {SaleCommandHelper} from"../utils/SaleCommandHelper.sol";
import {LimitedMintPerAddress} from"../utils/LimitedMintPerAddress.sol";
/*
░░░░░░░░░░░░░░
░░▒▒░░░░░░░░░░░░░░░░░░░░
░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░
░░▒▒▒▒░░░░░░░░░░░░░░ ░░░░░░░░
░▓▓▒▒▒▒░░░░░░░░░░░░ ░░░░░░░
░▓▓▓▒▒▒▒░░░░░░░░░░░░ ░░░░░░░░
░▓▓▓▒▒▒▒░░░░░░░░░░░░░░ ░░░░░░░░░░
░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░
░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░
░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░
░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░
░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░
░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░
░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░
OURS TRULY,
github.com/ourzora/zora-1155-contracts
*//// @title ZoraCreatorFixedPriceSaleStrategy/// @notice A sale strategy for ZoraCreator that allows for fixed price sales over a given time period/// @author @iainnash / @tbtstlcontractZoraCreatorFixedPriceSaleStrategyisEnjoy, SaleStrategy, LimitedMintPerAddress{
structSalesConfig {
/// @notice Unix timestamp for the sale startuint64 saleStart;
/// @notice Unix timestamp for the sale enduint64 saleEnd;
/// @notice Max tokens that can be minted for an address, 0 if unlimiteduint64 maxTokensPerAddress;
/// @notice Price per token in eth weiuint96 pricePerToken;
/// @notice Funds recipient (0 if no different funds recipient than the contract global)address fundsRecipient;
}
// target -> tokenId -> settingsmapping(address=>mapping(uint256=> SalesConfig)) internal salesConfigs;
usingSaleCommandHelperforICreatorCommands.CommandSet;
functioncontractURI() externalpureoverridereturns (stringmemory) {
return"https://github.com/ourzora/zora-1155-contracts/";
}
/// @notice The name of the sale strategyfunctioncontractName() externalpureoverridereturns (stringmemory) {
return"Fixed Price Sale Strategy";
}
/// @notice The version of the sale strategyfunctioncontractVersion() externalpureoverridereturns (stringmemory) {
return"1.1.0";
}
errorWrongValueSent();
errorSaleEnded();
errorSaleHasNotStarted();
eventSaleSet(addressindexed mediaContract, uint256indexed tokenId, SalesConfig salesConfig);
eventMintComment(addressindexed sender, addressindexed tokenContract, uint256indexed tokenId, uint256 quantity, string comment);
/// @notice Compiles and returns the commands needed to mint a token using this sales strategy/// @param tokenId The token ID to mint/// @param quantity The quantity of tokens to mint/// @param ethValueSent The amount of ETH sent with the transaction/// @param minterArguments The arguments passed to the minter, which should be the address to mint tofunctionrequestMint(address,
uint256 tokenId,
uint256 quantity,
uint256 ethValueSent,
bytescalldata minterArguments
) externalreturns (ICreatorCommands.CommandSet memory commands) {
address mintTo;
stringmemory comment ="";
if (minterArguments.length==32) {
mintTo =abi.decode(minterArguments, (address));
} else {
(mintTo, comment) =abi.decode(minterArguments, (address, string));
}
SalesConfig storage config = salesConfigs[msg.sender][tokenId];
// If sales config does not exist this first check will always fail.// Check sale endif (block.timestamp> config.saleEnd) {
revert SaleEnded();
}
// Check sale startif (block.timestamp< config.saleStart) {
revert SaleHasNotStarted();
}
// Check value sentif (config.pricePerToken * quantity != ethValueSent) {
revert WrongValueSent();
}
// Check minted per address limitif (config.maxTokensPerAddress >0) {
_requireMintNotOverLimitAndUpdate(config.maxTokensPerAddress, quantity, msg.sender, tokenId, mintTo);
}
bool shouldTransferFunds = config.fundsRecipient !=address(0);
commands.setSize(shouldTransferFunds ? 2 : 1);
// Mint command
commands.mint(mintTo, tokenId, quantity);
if (bytes(comment).length>0) {
emit MintComment(mintTo, msg.sender, tokenId, quantity, comment);
}
// Should transfer funds if funds recipient is set to a non-default addressif (shouldTransferFunds) {
commands.transfer(config.fundsRecipient, ethValueSent);
}
}
/// @notice Sets the sale config for a given tokenfunctionsetSale(uint256 tokenId, SalesConfig memory salesConfig) external{
salesConfigs[msg.sender][tokenId] = salesConfig;
// Emit eventemit SaleSet(msg.sender, tokenId, salesConfig);
}
/// @notice Deletes the sale config for a given tokenfunctionresetSale(uint256 tokenId) externaloverride{
delete salesConfigs[msg.sender][tokenId];
// Deleted sale emit eventemit SaleSet(msg.sender, tokenId, salesConfigs[msg.sender][tokenId]);
}
/// @notice Returns the sale config for a given tokenfunctionsale(address tokenContract, uint256 tokenId) externalviewreturns (SalesConfig memory) {
return salesConfigs[tokenContract][tokenId];
}
functionsupportsInterface(bytes4 interfaceId) publicpurevirtualoverride(LimitedMintPerAddress, SaleStrategy) returns (bool) {
returnsuper.supportsInterface(interfaceId) || LimitedMintPerAddress.supportsInterface(interfaceId) || SaleStrategy.supportsInterface(interfaceId);
}
}