diff --git a/script/DeployPreminter.s.sol b/script/DeployPreminter.s.sol index cc9b97d47..66fc05928 100644 --- a/script/DeployPreminter.s.sol +++ b/script/DeployPreminter.s.sol @@ -18,7 +18,7 @@ import {ProxyShim} from "../src/utils/ProxyShim.sol"; import {ZoraCreatorFixedPriceSaleStrategy} from "../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; import {ZoraCreatorMerkleMinterStrategy} from "../src/minters/merkle/ZoraCreatorMerkleMinterStrategy.sol"; import {ZoraCreatorRedeemMinterFactory} from "../src/minters/redeem/ZoraCreatorRedeemMinterFactory.sol"; -import {ZoraCreator1155Preminter} from "../src/premint/ZoraCreator1155Preminter.sol"; +import {ZoraCreator1155PremintExecutor} from "../src/premint/ZoraCreator1155PremintExecutor.sol"; contract DeployPreminter is ZoraDeployerBase { function run() public returns (string memory) { @@ -30,7 +30,7 @@ contract DeployPreminter is ZoraDeployerBase { vm.startBroadcast(deployerPrivateKey); - ZoraCreator1155Preminter preminter = new ZoraCreator1155Preminter(); + ZoraCreator1155PremintExecutor preminter = new ZoraCreator1155PremintExecutor(); preminter.initialize(factory); vm.stopBroadcast(); diff --git a/src/interfaces/IZoraCreator1155.sol b/src/interfaces/IZoraCreator1155.sol index fbeb2c9c0..7a663ac5a 100644 --- a/src/interfaces/IZoraCreator1155.sol +++ b/src/interfaces/IZoraCreator1155.sol @@ -9,7 +9,7 @@ import {IMinter1155} from "../interfaces/IMinter1155.sol"; import {IOwnable} from "../interfaces/IOwnable.sol"; import {IVersionedContract} from "./IVersionedContract.sol"; import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol"; -import {PremintConfig} from "../premint/ZoraCreator1155Delegation.sol"; +import {PremintConfig} from "../premint/ZoraCreator1155Attribution.sol"; /* diff --git a/src/nft/ZoraCreator1155Impl.sol b/src/nft/ZoraCreator1155Impl.sol index cacb27298..22b588125 100644 --- a/src/nft/ZoraCreator1155Impl.sol +++ b/src/nft/ZoraCreator1155Impl.sol @@ -31,7 +31,7 @@ import {PublicMulticall} from "../utils/PublicMulticall.sol"; import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol"; import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol"; import {ZoraCreator1155StorageV1} from "./ZoraCreator1155StorageV1.sol"; -import {ZoraCreator1155Attribution, TokenSetup, PremintConfig} from "../premint/ZoraCreator1155Delegation.sol"; +import {ZoraCreator1155Attribution, PremintTokenSetup, PremintConfig} from "../premint/ZoraCreator1155Attribution.sol"; /// Imagine. Mint. Enjoy. /// @title ZoraCreator1155Impl @@ -731,18 +731,12 @@ contract ZoraCreator1155Impl is mapping(uint32 => bool) public uidUsed; - // todo: move to its own contract - error PremintAlreadyExecuted(); - error MintNotYetStarted(); - error PremintDeleted(); - event CreatorAttribution(bytes32 structHash, bytes32 domainName, bytes32 version, bytes signature); + error PremintAlreadyExecuted(); + function delegateSetupNewToken(PremintConfig calldata premintConfig, bytes calldata signature) public returns (uint256 newTokenId) { - if (premintConfig.tokenConfig.mintStart != 0 && premintConfig.tokenConfig.mintStart > block.timestamp) { - // if the mint start is in the future, then revert - revert MintNotYetStarted(); - } + bytes32 hashedPremintConfig = ZoraCreator1155Attribution.validateAndHashPremint(premintConfig); // check that uid hasn't been used if (uidUsed[premintConfig.uid]) { @@ -751,14 +745,6 @@ contract ZoraCreator1155Impl is uidUsed[premintConfig.uid] = true; } - if (premintConfig.deleted) { - // if the signature says to be deleted, then dont execute any further minting logic; - // return 0 - revert PremintDeleted(); - } - - bytes32 hashedPremintConfig = ZoraCreator1155Attribution.hashPremint(premintConfig); - // this is what attributes this token to have been created by the original creator emit CreatorAttribution(hashedPremintConfig, ZoraCreator1155Attribution.HASHED_NAME, ZoraCreator1155Attribution.HASHED_VERSION, signature); @@ -768,21 +754,18 @@ contract ZoraCreator1155Impl is // require that the signer can create new tokens (is a valid creator) _requireAdminOrRole(recoveredSigner, CONTRACT_BASE_ID, PERMISSION_BIT_MINTER); - // temporarily grant msg sender admin permission to create new tokens - _addPermission(CONTRACT_BASE_ID, msg.sender, PERMISSION_BIT_MINTER); - - // get the new token id - it will fail if the recovered signer does not have PERMISSION_BIT_MINTER permission - newTokenId = setupNewToken(premintConfig.tokenConfig.tokenURI, premintConfig.tokenConfig.maxSupply); - // msg.sender should now have admin role on that token (lets make sure to remove it at the end of this call!!!) + // create the new token; msg sender will have PERMISSION_BIT_ADMIN on the new token + newTokenId = _setupNewTokenAndPermission(premintConfig.tokenConfig.tokenURI, premintConfig.tokenConfig.maxSupply, msg.sender, PERMISSION_BIT_ADMIN); // invoke setup actions for new token, to save contract size, first get them from an external lib - bytes[] memory tokenSetupActions = TokenSetup.makeSetupNewTokenCalls(newTokenId, recoveredSigner, premintConfig.tokenConfig); + bytes[] memory tokenSetupActions = PremintTokenSetup.makeSetupNewTokenCalls(newTokenId, recoveredSigner, premintConfig.tokenConfig); - // then invoke them, calling account should be original msg.sender + // then invoke them, calling account should be original msg.sender, which has admin on the new token _multicallInternal(tokenSetupActions); // remove the token creator as admin of the newly created token: _removePermission(newTokenId, msg.sender, PERMISSION_BIT_ADMIN); + // grant the token creator as admin of the newly created token _addPermission(newTokenId, recoveredSigner, PERMISSION_BIT_ADMIN); } diff --git a/src/premint/ZoraCreator1155Delegation.sol b/src/premint/ZoraCreator1155Attribution.sol similarity index 93% rename from src/premint/ZoraCreator1155Delegation.sol rename to src/premint/ZoraCreator1155Attribution.sol index 8180b980c..637ddf0c8 100644 --- a/src/premint/ZoraCreator1155Delegation.sol +++ b/src/premint/ZoraCreator1155Attribution.sol @@ -173,9 +173,27 @@ library ZoraCreator1155Attribution { function _stringHash(string calldata value) private pure returns (bytes32) { return keccak256(bytes(value)); } + + // todo: move to its own contract + error MintNotYetStarted(); + error PremintDeleted(); + + function validateAndHashPremint(PremintConfig calldata premintConfig) external view returns (bytes32) { + if (premintConfig.tokenConfig.mintStart != 0 && premintConfig.tokenConfig.mintStart > block.timestamp) { + // if the mint start is in the future, then revert + revert MintNotYetStarted(); + } + if (premintConfig.deleted) { + // if the signature says to be deleted, then dont execute any further minting logic; + // return 0 + revert PremintDeleted(); + } + + return hashPremint(premintConfig); + } } -library TokenSetup { +library PremintTokenSetup { uint256 constant PERMISSION_BIT_MINTER = 2 ** 2; function makeSetupNewTokenCalls( diff --git a/src/premint/ZoraCreator1155Preminter.sol b/src/premint/ZoraCreator1155PremintExecutor.sol similarity index 98% rename from src/premint/ZoraCreator1155Preminter.sol rename to src/premint/ZoraCreator1155PremintExecutor.sol index d18a30474..687744421 100644 --- a/src/premint/ZoraCreator1155Preminter.sol +++ b/src/premint/ZoraCreator1155PremintExecutor.sol @@ -9,14 +9,14 @@ import {IZoraCreator1155Factory} from "../interfaces/IZoraCreator1155Factory.sol import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol"; import {ZoraCreatorFixedPriceSaleStrategy} from "../minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; import {IMinter1155} from "../interfaces/IMinter1155.sol"; -import {PremintConfig, ContractCreationConfig, TokenCreationConfig} from "./ZoraCreator1155Delegation.sol"; +import {PremintConfig, ContractCreationConfig, TokenCreationConfig} from "./ZoraCreator1155Attribution.sol"; /// @title Enables a creator to signal intent to create a Zora erc1155 contract or new token on that /// contract by signing a transaction but not paying gas, and have a third party/collector pay the gas /// by executing the transaction. Incentivizes the third party to execute the transaction by offering /// a reward in the form of minted tokens. /// @author @oveddan -contract ZoraCreator1155Preminter { +contract ZoraCreator1155PremintExecutor { IZoraCreator1155Factory factory; /// @notice copied from SharedBaseConstants diff --git a/test/premint/ZoraCreator1155Preminter.t.sol b/test/premint/ZoraCreator1155Preminter.t.sol index 36074a396..2adc096df 100644 --- a/test/premint/ZoraCreator1155Preminter.t.sol +++ b/test/premint/ZoraCreator1155Preminter.t.sol @@ -16,12 +16,12 @@ import {ILimitedMintPerAddress} from "../../src/interfaces/ILimitedMintPerAddres import {ZoraCreatorFixedPriceSaleStrategy} from "../../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; -import {ZoraCreator1155Preminter} from "../../src/premint/ZoraCreator1155Preminter.sol"; +import {ZoraCreator1155PremintExecutor} from "../../src/premint/ZoraCreator1155PremintExecutor.sol"; import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol"; -import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfig, PremintConfig} from "../../src/premint/ZoraCreator1155Delegation.sol"; +import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfig, PremintConfig} from "../../src/premint/ZoraCreator1155Attribution.sol"; contract ZoraCreator1155PreminterTest is Test { - ZoraCreator1155Preminter internal preminter; + ZoraCreator1155PremintExecutor internal preminter; ZoraCreator1155FactoryImpl internal factory; // setup contract config uint256 creatorPrivateKey = 0xA11CE; @@ -55,7 +55,7 @@ contract ZoraCreator1155PreminterTest is Test { royaltyMintSchedule: royaltyMintSchedule }); - preminter = new ZoraCreator1155Preminter(); + preminter = new ZoraCreator1155PremintExecutor(); preminter.initialize(factory); creatorPrivateKey = 0xA11CE;