diff --git a/packages/1155-contracts/package/preminter.test.ts b/packages/1155-contracts/package/preminter.test.ts index 04dd697a0..cc705ea36 100644 --- a/packages/1155-contracts/package/preminter.test.ts +++ b/packages/1155-contracts/package/preminter.test.ts @@ -8,6 +8,7 @@ import { concat, recoverAddress, hashDomain, + zeroAddress, } from "viem"; import { foundry, zora } from "viem/chains"; import { describe, it, beforeEach, expect } from "vitest"; @@ -24,7 +25,6 @@ import { ContractCreationConfig, PremintConfigV2, TokenCreationConfigV2, - encodeMintArguments, preminterTypedDataDefinitionV2, } from "./preminter"; @@ -285,7 +285,11 @@ describe("ZoraCreator1155Preminter", () => { premintConfig, signedMessage, quantityToMint, - encodeMintArguments({ mintComment: comment }), + { + mintComment: comment, + mintRecipient: collectorAccount, + mintReferral: zeroAddress, + }, ], value: valueToSend, }); @@ -356,7 +360,11 @@ describe("ZoraCreator1155Preminter", () => { premintConfig2, signedMessage2, quantityToMint2, - encodeMintArguments({ mintComment: comment }), + { + mintComment: comment, + mintRecipient: collectorAccount, + mintReferral: zeroAddress, + }, ], value: valueToSend2, }); @@ -450,7 +458,11 @@ describe("ZoraCreator1155Preminter", () => { premintConfig, signedMessage, quantityToMint, - encodeMintArguments({ mintComment: comment }), + { + mintComment: comment, + mintRecipient: collectorAccount, + mintReferral: zeroAddress, + }, ], value: valueToSend, }); diff --git a/packages/1155-contracts/package/preminter.ts b/packages/1155-contracts/package/preminter.ts index e9759a062..c54dc3045 100644 --- a/packages/1155-contracts/package/preminter.ts +++ b/packages/1155-contracts/package/preminter.ts @@ -1,7 +1,7 @@ import { Address } from "abitype"; import { ExtractAbiFunction, AbiParametersToPrimitiveTypes } from "abitype"; import { zoraCreator1155PremintExecutorImplABI as preminterAbi } from "./wagmiGenerated"; -import { TypedDataDefinition, encodeAbiParameters } from "viem"; +import { TypedDataDefinition } from "viem"; type PremintInputs = ExtractAbiFunction< typeof preminterAbi, @@ -142,21 +142,3 @@ export const preminterTypedDataDefinitionV1 = ({ return result; }; - -const zeroAddress: Address = "0x0000000000000000000000000000000000000000"; - -export const encodeMintArguments = ({ - mintComment = "", - mintReferral = zeroAddress, -}: { - mintComment?: string; - mintReferral?: Address; -}) => { - return encodeAbiParameters( - [ - { name: "mintReferral", type: "address" }, - { name: "mintComment", type: "string" }, - ], - [mintReferral, mintComment] - ); -}; diff --git a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol index 776d0a9d6..c4aa080d1 100644 --- a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol +++ b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol @@ -43,6 +43,15 @@ interface ILegacyZoraCreator1155PremintExecutor { ) external payable returns (uint256 newTokenId); } +struct MintArguments { + // which account should receive the tokens minted. If set to address(0), then defaults to the msg.sender + address mintRecipient; + // comment to add to the mint + string mintComment; + // account that referred the minter to mint the tokens, this account will receive a mint referral award. If set to address(0), no account will get the mint referral reward + address mintReferral; +} + /// @title Enables creation of and minting tokens on Zora1155 contracts transactions using eip-712 signatures. /// Signature must provided by the contract creator, or an account that's permitted to create new tokens on the contract. /// Mints the first x tokens to the executor of the transaction. @@ -71,8 +80,7 @@ contract ZoraCreator1155PremintExecutorImpl is bool indexed createdNewContract, uint32 uid, address minter, - uint256 quantityMinted, - bytes mintArgumets + uint256 quantityMinted ); /// Creates a new token on the given erc1155 contract on behalf of a creator, and mints x tokens to the executor of this transaction. @@ -90,7 +98,7 @@ contract ZoraCreator1155PremintExecutorImpl is PremintConfigV2 calldata premintConfig, bytes calldata signature, uint256 quantityToMint, - bytes calldata mintArguments + MintArguments calldata mintArguments ) external payable returns (uint256 newTokenId) { (bytes memory encodedPremint, bytes32 premintVersion) = PremintEncoding.encodePremintV2(premintConfig); address fixedPriceMinter = premintConfig.tokenConfig.fixedPriceMinter; @@ -126,7 +134,7 @@ contract ZoraCreator1155PremintExecutorImpl is PremintConfig calldata premintConfig, bytes calldata signature, uint256 quantityToMint, - bytes memory mintArguments + MintArguments memory mintArguments ) public payable returns (uint256 newTokenId) { (bytes memory encodedPremint, bytes32 premintVersion) = PremintEncoding.encodePremintV1(premintConfig); @@ -151,7 +159,7 @@ contract ZoraCreator1155PremintExecutorImpl is uint256 quantityToMint, address fixedPriceMinter, uint32 uid, - bytes memory mintArguments + MintArguments memory mintArguments ) private returns (uint256 newTokenId) { // get or create the contract with the given params // contract address is deterministic. @@ -165,7 +173,7 @@ contract ZoraCreator1155PremintExecutorImpl is _performMint(tokenContract, fixedPriceMinter, newTokenId, quantityToMint, mintArguments); // emit Preminted event - emit PremintedV2(address(tokenContract), newTokenId, isNewContract, uid, msg.sender, quantityToMint, mintArguments); + emit PremintedV2(address(tokenContract), newTokenId, isNewContract, uid, msg.sender, quantityToMint); } function _performMint( @@ -173,19 +181,12 @@ contract ZoraCreator1155PremintExecutorImpl is address fixedPriceMinter, uint256 tokenId, uint256 quantityToMint, - bytes memory mintArguments + MintArguments memory mintArguments ) internal { - (address mintReferral, string memory mintComment) = ZoraCreator1155PremintExecutorImplLib.decodeMintArguments(mintArguments); - + bytes memory mintSettings = abi.encode(mintArguments.mintRecipient, mintArguments.mintComment); if (quantityToMint != 0) // mint the number of specified tokens to the executor - tokenContract.mintWithRewards{value: msg.value}( - IMinter1155(fixedPriceMinter), - tokenId, - quantityToMint, - abi.encode(msg.sender, mintComment), - mintReferral - ); + tokenContract.mintWithRewards{value: msg.value}(IMinter1155(fixedPriceMinter), tokenId, quantityToMint, mintSettings, mintArguments.mintReferral); } function isValidSignature( @@ -284,7 +285,7 @@ contract ZoraCreator1155PremintExecutorImpl is string calldata mintComment ) external payable returns (uint256 newTokenId) { // encode legacy mint arguments to call current function: - bytes memory mintArguments = ZoraCreator1155PremintExecutorImplLib.encodeMintArguments(address(0), mintComment); + MintArguments memory mintArguments = MintArguments({mintRecipient: msg.sender, mintComment: mintComment, mintReferral: address(0)}); return premint(contractConfig, premintConfig, signature, quantityToMint, mintArguments); } diff --git a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol index 6ac32a540..873e20290 100644 --- a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol +++ b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol @@ -51,11 +51,11 @@ library ZoraCreator1155PremintExecutorImplLib { zora1155Factory.deterministicContractAddress(address(this), contractConfig.contractURI, contractConfig.contractName, contractConfig.contractAdmin); } - function encodeMintArguments(address mintReferral, string memory mintComment) internal pure returns (bytes memory) { - return abi.encode(mintReferral, mintComment); + function encodeMintArguments(address mintRecipient, string memory mintComment) internal pure returns (bytes memory) { + return abi.encode(mintRecipient, mintComment); } - function decodeMintArguments(bytes memory mintArguments) internal pure returns (address mintReferral, string memory mintComment) { + function decodeMintArguments(bytes memory mintArguments) internal pure returns (address mintRecipient, string memory mintComment) { return abi.decode(mintArguments, (address, string)); } } diff --git a/packages/1155-contracts/src/deployment/DeploymentTestingUtils.sol b/packages/1155-contracts/src/deployment/DeploymentTestingUtils.sol index a91e7a34c..3ed77c292 100644 --- a/packages/1155-contracts/src/deployment/DeploymentTestingUtils.sol +++ b/packages/1155-contracts/src/deployment/DeploymentTestingUtils.sol @@ -5,7 +5,7 @@ import "forge-std/Script.sol"; import {IMinter1155} from "..//interfaces/IMinter1155.sol"; import {Zora1155FactoryFixtures} from "../../test/fixtures/Zora1155FactoryFixtures.sol"; import {Zora1155PremintFixtures} from "../../test/fixtures/Zora1155PremintFixtures.sol"; -import {ZoraCreator1155PremintExecutorImpl} from "../delegation/ZoraCreator1155PremintExecutorImpl.sol"; +import {ZoraCreator1155PremintExecutorImpl, MintArguments} from "../delegation/ZoraCreator1155PremintExecutorImpl.sol"; import {ZoraCreator1155FactoryImpl} from "../factory/ZoraCreator1155FactoryImpl.sol"; import {ZoraCreator1155Attribution, ContractCreationConfig, PremintConfigV2} from "../delegation/ZoraCreator1155Attribution.sol"; import {ZoraCreator1155Impl} from "../nft/ZoraCreator1155Impl.sol"; @@ -31,26 +31,27 @@ contract DeploymentTestingUtils is Script { ContractCreationConfig memory contractConfig = Zora1155PremintFixtures.makeDefaultContractCreationConfig(creator); address deterministicAddress = preminterAtProxy.getContractAddress(contractConfig); - bytes32 signatureVersion = ZoraCreator1155Attribution.HASHED_VERSION_2; - bytes32 structHash = ZoraCreator1155Attribution.hashPremint(premintConfig); - // sign the premint - bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4(structHash, deterministicAddress, signatureVersion, block.chainid); + uint256 quantityToMint = 1; - (uint8 v, bytes32 r, bytes32 s) = vm.sign(creatorPrivateKey, digest); + address mintRecipient = creator; - uint256 quantityToMint = 1; + MintArguments memory mintArguments = MintArguments({mintRecipient: mintRecipient, mintComment: "", mintReferral: address(0)}); - bytes memory signature = abi.encodePacked(r, s, v); + bytes memory signature = signPremint(premintConfig, deterministicAddress, creatorPrivateKey); // execute the premint - uint256 tokenId = preminterAtProxy.premint{value: 0.000777 ether}( - contractConfig, - premintConfig, - signature, - quantityToMint, - ZoraCreator1155PremintExecutorImplLib.encodeMintArguments(address(0), "") - ); + uint256 tokenId = preminterAtProxy.premint{value: 0.000777 ether}(contractConfig, premintConfig, signature, quantityToMint, mintArguments); require(ZoraCreator1155Impl(deterministicAddress).delegatedTokenId(premintConfig.uid) == tokenId, "token id not created for uid"); } + + function signPremint(PremintConfigV2 memory premintConfig, address deterministicAddress, uint256 privateKey) private view returns (bytes memory signature) { + bytes32 signatureVersion = ZoraCreator1155Attribution.HASHED_VERSION_2; + bytes32 structHash = ZoraCreator1155Attribution.hashPremint(premintConfig); + // sign the premint + bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4(structHash, deterministicAddress, signatureVersion, block.chainid); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); + return abi.encodePacked(r, s, v); + } } diff --git a/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol b/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol index afdcca3f0..bfe310946 100644 --- a/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol +++ b/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol @@ -760,6 +760,12 @@ contract ZoraCreator1155Impl is (DelegatedTokenSetup memory params, DecodedCreatorAttribution memory attribution, bytes[] memory tokenSetupActions) = DelegatedTokenCreation .decodeAndRecoverDelegatedTokenSetup(premintConfig, premintVersion, signature, address(this), nextTokenId); + // if a token has already been created for a premint config with this uid: + if (delegatedTokenId[params.uid] != 0) { + // return its token id + return delegatedTokenId[params.uid]; + } + // this is what attributes this token to have been created by the original creator emit CreatorAttribution(attribution.structHash, attribution.domainName, attribution.version, attribution.creator, attribution.signature); @@ -772,12 +778,6 @@ contract ZoraCreator1155Impl is bytes[] memory tokenSetupActions, address sender ) internal returns (uint256 newTokenId) { - // if a token has already been created for a premint config with this uid: - if (delegatedTokenId[params.uid] != 0) { - // return its token id - return delegatedTokenId[params.uid]; - } - // require that the signer can create new tokens (is a valid creator) _requireAdminOrRole(creator, CONTRACT_BASE_ID, PERMISSION_BIT_MINTER); diff --git a/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol b/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol index 0448044e6..7953b2849 100644 --- a/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol +++ b/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol @@ -20,8 +20,8 @@ library Zora1155PremintFixtures { return TokenCreationConfigV2({ tokenURI: "blah.token", - maxSupply: 10, - maxTokensPerAddress: 5, + maxSupply: 20, + maxTokensPerAddress: 10, pricePerToken: 0, mintStart: 0, mintDuration: 0, diff --git a/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol b/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol index e68f367b0..aea0fe36b 100644 --- a/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol +++ b/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol @@ -7,7 +7,7 @@ import {Zora1155PremintFixtures} from "../fixtures/Zora1155PremintFixtures.sol"; import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; import {Zora1155PremintExecutor} from "../../src/proxies/Zora1155PremintExecutor.sol"; import {ZoraCreator1155Impl} from "../../src/nft/ZoraCreator1155Impl.sol"; -import {ZoraCreator1155PremintExecutorImpl} from "../../src/delegation/ZoraCreator1155PremintExecutorImpl.sol"; +import {ZoraCreator1155PremintExecutorImpl, MintArguments} from "../../src/delegation/ZoraCreator1155PremintExecutorImpl.sol"; import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; import {ProxyShim} from "../../src/utils/ProxyShim.sol"; @@ -27,6 +27,8 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { uint256 internal mintFeeAmount = 0.000777 ether; ZoraCreator1155PremintExecutorImpl preminterAtProxy; + MintArguments defaultMintArguments; + function setUp() external { zora = makeAddr("zora"); owner = makeAddr("owner"); @@ -47,6 +49,8 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { // access the executor implementation via the proxy, and initialize the admin preminterAtProxy = ZoraCreator1155PremintExecutorImpl(address(proxy)); preminterAtProxy.initialize(owner); + + defaultMintArguments = MintArguments({mintRecipient: collector, mintComment: "blah", mintReferral: address(0)}); } function test_canInvokeImplementationMethods() external { @@ -82,13 +86,7 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { // execute the premint vm.deal(collector, mintFeeAmount); vm.prank(collector); - uint256 tokenId = preminterAtProxy.premint{value: mintFeeAmount}( - contractConfig, - premintConfig, - signature, - quantityToMint, - ZoraCreator1155PremintExecutorImplLib.encodeMintArguments(address(0), "") - ); + uint256 tokenId = preminterAtProxy.premint{value: mintFeeAmount}(contractConfig, premintConfig, signature, quantityToMint, defaultMintArguments); assertEq(ZoraCreator1155Impl(deterministicAddress).balanceOf(collector, tokenId), 1); } diff --git a/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol b/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol index e595b55d4..11efc8bf8 100644 --- a/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol +++ b/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol @@ -14,7 +14,7 @@ import {ICreatorRoyaltiesControl} from "../../src/interfaces/ICreatorRoyaltiesCo import {ZoraCreatorFixedPriceSaleStrategy} from "../../src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol"; import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; -import {ZoraCreator1155PremintExecutorImpl} from "../../src/delegation/ZoraCreator1155PremintExecutorImpl.sol"; +import {ZoraCreator1155PremintExecutorImpl, MintArguments} from "../../src/delegation/ZoraCreator1155PremintExecutorImpl.sol"; import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfig, TokenCreationConfigV2, PremintConfigV2, PremintConfig} from "../../src/delegation/ZoraCreator1155Attribution.sol"; import {ForkDeploymentConfig, Deployment} from "../../src/deployment/DeploymentConfig.sol"; import {UUPSUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; @@ -40,7 +40,7 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { address internal premintExecutor; address internal collector; - bytes defaultMintArguments; + MintArguments defaultMintArguments; event PremintedV2( address indexed contractAddress, @@ -48,8 +48,7 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { bool indexed createdNewContract, uint32 uid, address minter, - uint256 quantityMinted, - bytes mintArgumets + uint256 quantityMinted ); function setUp() external { @@ -66,7 +65,7 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { preminter = new ZoraCreator1155PremintExecutorImpl(factory); - defaultMintArguments = ZoraCreator1155PremintExecutorImplLib.encodeMintArguments(address(0), ""); + defaultMintArguments = MintArguments({mintRecipient: premintExecutor, mintComment: "blah", mintReferral: address(0)}); } function makeDefaultContractCreationConfig() internal view returns (ContractCreationConfig memory) { @@ -391,12 +390,18 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { uint256 nextTokenId; + uint256 beforeTokenBalance = created1155Contract.balanceOf(defaultMintArguments.mintRecipient, firstTokenId); + vm.startPrank(collector); // premint with new token config and signature, but same uid - it should mint tokens for the first token nextTokenId = preminter.premint{value: mintCost}(contractConfig, premintConfig, signature, quantityToMint, defaultMintArguments); assertEq(nextTokenId, firstTokenId); - assertEq(created1155Contract.balanceOf(collector, firstTokenId), quantityToMint); + assertEq( + created1155Contract.balanceOf(defaultMintArguments.mintRecipient, firstTokenId) - beforeTokenBalance, + quantityToMint, + "balance after first mint" + ); // change the version, it should still point to the first token premintConfig.version++; @@ -409,7 +414,11 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { vm.stopPrank(); assertEq(nextTokenId, firstTokenId); - assertEq(created1155Contract.balanceOf(collector, firstTokenId), quantityToMint * 2); + assertEq( + created1155Contract.balanceOf(defaultMintArguments.mintRecipient, firstTokenId) - beforeTokenBalance, + quantityToMint * 2, + "balance after second mint" + ); } function testCreateTokenPerUid() public { @@ -481,14 +490,12 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { // this account will be used to execute the premint, and should result in a contract being created vm.deal(premintExecutor, mintCost); - bytes memory mintArguments = defaultMintArguments; - vm.startPrank(premintExecutor); bool createdNewContract = true; vm.expectEmit(true, true, true, true); - emit PremintedV2(contractAddress, expectedTokenId, createdNewContract, premintConfig.uid, premintExecutor, quantityToMint, mintArguments); - preminter.premint{value: mintCost}(contractConfig, premintConfig, signature, quantityToMint, mintArguments); + emit PremintedV2(contractAddress, expectedTokenId, createdNewContract, premintConfig.uid, premintExecutor, quantityToMint); + preminter.premint{value: mintCost}(contractConfig, premintConfig, signature, quantityToMint, defaultMintArguments); } function test_onlyOwner_hasAdminRights_onCreatedToken() public { @@ -803,7 +810,7 @@ contract ZoraCreator1155PreminterTest is ForkDeploymentConfig, Test { ) private returns (uint256 newTokenId) { bytes memory signature = _signPremint(preminter.getContractAddress(contractConfig), premintConfig, privateKey, chainId); - bytes memory mintArguments = ZoraCreator1155PremintExecutorImplLib.encodeMintArguments(address(0), comment); + MintArguments memory mintArguments = MintArguments({mintRecipient: executor, mintComment: comment, mintReferral: address(0)}); uint256 mintCost = mintFeeAmount * quantityToMint; vm.deal(executor, mintCost);