From 1c0caea7684ced12e81eb02598ca0e993d25e27d Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Wed, 15 Nov 2023 13:20:57 -0800 Subject: [PATCH] Premint - can execute premint on legacy version of contracts (#299) If an 1155 contract was created with the old function delegateSetupNewToken() - the upgraded premint executor could not execute that function cause it expected the newer signature with different arguments. This PR will have the premint executor check if the contract supports the new function, and if it doesn't, then it calls the old function --- .changeset/dirty-dodos-joke.md | 5 + .changeset/violet-starfishes-visit.md | 2 +- .../ZoraCreator1155PremintExecutorImpl.sol | 3 +- .../ZoraCreator1155PremintExecutorImplLib.sol | 39 +++++++- .../src/interfaces/IZoraCreator1155.sol | 20 ++-- .../IZoraCreator1155DelegatedCreation.sol | 13 +++ .../src/interfaces/IZoraCreator1155Errors.sol | 2 + .../IZoraCreator1155PremintExecutor.sol | 8 +- .../src/nft/ZoraCreator1155Impl.sol | 7 +- .../test/fixtures/Zora1155FactoryFixtures.sol | 20 +++- .../test/fixtures/Zora1155PremintFixtures.sol | 24 ++++- .../Zora1155PremintExecutorProxy.t.sol | 95 ++++++++++++++++--- .../ZoraCreator1155PremintExecutor.t.sol | 29 +----- 13 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 .changeset/dirty-dodos-joke.md create mode 100644 packages/1155-contracts/src/interfaces/IZoraCreator1155DelegatedCreation.sol diff --git a/.changeset/dirty-dodos-joke.md b/.changeset/dirty-dodos-joke.md new file mode 100644 index 000000000..956fa899b --- /dev/null +++ b/.changeset/dirty-dodos-joke.md @@ -0,0 +1,5 @@ +--- +"@zoralabs/zora-1155-contracts": patch +--- + +Premint executor can still execute premint mints on 1155 contracts that were created with the old signature for `delegateSetupNewToken` \ No newline at end of file diff --git a/.changeset/violet-starfishes-visit.md b/.changeset/violet-starfishes-visit.md index ea27371da..bdd1b3c6c 100644 --- a/.changeset/violet-starfishes-visit.md +++ b/.changeset/violet-starfishes-visit.md @@ -111,4 +111,4 @@ struct TokenCreationConfig { * deprecated function `premint` - call `premintV1` instead * new function `isValidSignatureV1` - takes an 1155 address, contract admin, premint v1 config and signature, and validates the signature. Can be used for 1155 contracts that were not created via the premint executor contract. * new function `isValidSignatureV2` - takes an 1155 address, contract admin, premint v2 config and signature, and validates the signature. Can be used for 1155 contracts that were not created via the premint executor contract. -* deprecated function `isValidSignature` - call `isValidSignatureV1` instead \ No newline at end of file +* deprecated function `isValidSignature` - call `isValidSignatureV1` instead diff --git a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol index 0e5ea5c30..d739f2cd4 100644 --- a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol +++ b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImpl.sol @@ -14,7 +14,7 @@ import {IMinter1155} from "../interfaces/IMinter1155.sol"; import {ERC1155DelegationStorageV1} from "../delegation/ERC1155DelegationStorageV1.sol"; import {ZoraCreator1155PremintExecutorImplLib} from "./ZoraCreator1155PremintExecutorImplLib.sol"; import {PremintEncoding, ZoraCreator1155Attribution, ContractCreationConfig, PremintConfig, PremintConfigV2, TokenCreationConfig, TokenCreationConfigV2} from "./ZoraCreator1155Attribution.sol"; -import {IZoraCreator1155PremintExecutor, ILegacyZoraCreator1155PremintExecutor} from "../interfaces/IZoraCreator1155PremintExecutor.sol"; +import {IZoraCreator1155PremintExecutor} from "../interfaces/IZoraCreator1155PremintExecutor.sol"; struct MintArguments { // which account should receive the tokens minted. If set to address(0), then defaults to the msg.sender @@ -30,7 +30,6 @@ struct MintArguments { /// Mints the first x tokens to the executor of the transaction. /// @author @oveddan contract ZoraCreator1155PremintExecutorImpl is - ILegacyZoraCreator1155PremintExecutor, IZoraCreator1155PremintExecutor, Ownable2StepUpgradeable, UUPSUpgradeable, diff --git a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol index ce5fcef75..019b3117d 100644 --- a/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol +++ b/packages/1155-contracts/src/delegation/ZoraCreator1155PremintExecutorImplLib.sol @@ -1,12 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; -import {ContractCreationConfig} from "./ZoraCreator1155Attribution.sol"; +import {ContractCreationConfig, PremintConfig} from "./ZoraCreator1155Attribution.sol"; import {IZoraCreator1155} from "../interfaces/IZoraCreator1155.sol"; import {IZoraCreator1155Factory} from "../interfaces/IZoraCreator1155Factory.sol"; import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol"; import {IMinter1155} from "../interfaces/IMinter1155.sol"; import {IZoraCreator1155PremintExecutor} from "../interfaces/IZoraCreator1155PremintExecutor.sol"; +import {IZoraCreator1155DelegatedCreation} from "../interfaces/IZoraCreator1155DelegatedCreation.sol"; + +interface ILegacyZoraCreator1155DelegatedMinter { + function delegateSetupNewToken(PremintConfig calldata premintConfig, bytes calldata signature, address sender) external returns (uint256 newTokenId); +} library ZoraCreator1155PremintExecutorImplLib { function getOrCreateContract( @@ -60,6 +65,21 @@ library ZoraCreator1155PremintExecutorImplLib { return abi.decode(mintArguments, (address, string)); } + function legacySetupNewToken(address contractAddress, bytes memory encodedPremintConfig, bytes calldata signature) private returns (uint256) { + // for use when the erc1155 contract does not support the new delegateSetupNewToken interface, where it expects + // a PremintConfig as an argument. + + // decode the PremintConfig from the encoded bytes. + PremintConfig memory premintConfig = abi.decode(encodedPremintConfig, (PremintConfig)); + + // call the legacy version of the delegateSetupNewToken function. + return ILegacyZoraCreator1155DelegatedMinter(contractAddress).delegateSetupNewToken(premintConfig, signature, msg.sender); + } + + function supportsNewPremintInterface(address contractAddress) internal view returns (bool) { + return IZoraCreator1155(contractAddress).supportsInterface(type(IZoraCreator1155DelegatedCreation).interfaceId); + } + function premint( IZoraCreator1155Factory zora1155Factory, ContractCreationConfig calldata contractConfig, @@ -74,10 +94,19 @@ library ZoraCreator1155PremintExecutorImplLib { // contract address is deterministic. (IZoraCreator1155 tokenContract, bool isNewContract) = getOrCreateContract(zora1155Factory, contractConfig); - // pass the signature and the premint config to the token contract to create the token. - // The token contract will verify the signature and that the signer has permission to create a new token. - // and then create and setup the token using the given token config. - uint256 newTokenId = tokenContract.delegateSetupNewToken(encodedPremintConfig, premintVersion, signature, msg.sender); + uint256 newTokenId; + + if (supportsNewPremintInterface(address(tokenContract))) { + // if the contract supports the new interface, we can use it to create the token. + + // pass the signature and the premint config to the token contract to create the token. + // The token contract will verify the signature and that the signer has permission to create a new token. + // and then create and setup the token using the given token config. + newTokenId = tokenContract.delegateSetupNewToken(encodedPremintConfig, premintVersion, signature, msg.sender); + } else { + // otherwise, we need to use the legacy interface. + newTokenId = legacySetupNewToken(address(tokenContract), encodedPremintConfig, signature); + } _performMint(tokenContract, fixedPriceMinter, newTokenId, quantityToMint, mintArguments); diff --git a/packages/1155-contracts/src/interfaces/IZoraCreator1155.sol b/packages/1155-contracts/src/interfaces/IZoraCreator1155.sol index 4e3faa85d..03e483723 100644 --- a/packages/1155-contracts/src/interfaces/IZoraCreator1155.sol +++ b/packages/1155-contracts/src/interfaces/IZoraCreator1155.sol @@ -10,7 +10,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 {PremintConfigV2} from "../delegation/ZoraCreator1155Attribution.sol"; +import {IZoraCreator1155DelegatedCreation} from "./IZoraCreator1155DelegatedCreation.sol"; /* @@ -36,8 +36,14 @@ import {PremintConfigV2} from "../delegation/ZoraCreator1155Attribution.sol"; /// @notice Main interface for the ZoraCreator1155 contract /// @author @iainnash / @tbtstl -interface IZoraCreator1155 is IZoraCreator1155TypesV1, IZoraCreator1155Errors, IVersionedContract, IOwnable, IERC1155MetadataURIUpgradeable { - /// @notice This user role allows for any action to be performed +interface IZoraCreator1155 is + IZoraCreator1155TypesV1, + IZoraCreator1155Errors, + IVersionedContract, + IOwnable, + IERC1155MetadataURIUpgradeable, + IZoraCreator1155DelegatedCreation +{ function PERMISSION_BIT_ADMIN() external returns (uint256); /// @notice This user role allows for only mint actions to be performed @@ -70,7 +76,6 @@ interface IZoraCreator1155 is IZoraCreator1155TypesV1, IZoraCreator1155Errors, I event ContractRendererUpdated(IRenderer1155 renderer); event ContractMetadataUpdated(address indexed updater, string uri, string name); event Purchased(address indexed sender, address indexed minter, uint256 indexed tokenId, uint256 quantity, uint256 value); - event CreatorAttribution(bytes32 structHash, string domainName, string version, address creator, bytes signature); /// @notice Only allow minting one token id at time /// @dev Mint contract function that calls the underlying sales function for commands @@ -103,13 +108,6 @@ interface IZoraCreator1155 is IZoraCreator1155TypesV1, IZoraCreator1155Errors, I function getCreatorRewardRecipient(uint256 tokenId) external view returns (address); - function delegateSetupNewToken( - bytes memory premintConfigEncoded, - bytes32 premintVersion, - bytes calldata signature, - address sender - ) external returns (uint256 newTokenId); - function updateTokenURI(uint256 tokenId, string memory _newURI) external; function updateContractMetadata(string memory _newURI, string memory _newName) external; diff --git a/packages/1155-contracts/src/interfaces/IZoraCreator1155DelegatedCreation.sol b/packages/1155-contracts/src/interfaces/IZoraCreator1155DelegatedCreation.sol new file mode 100644 index 000000000..85c49eaba --- /dev/null +++ b/packages/1155-contracts/src/interfaces/IZoraCreator1155DelegatedCreation.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +interface IZoraCreator1155DelegatedCreation { + event CreatorAttribution(bytes32 structHash, string domainName, string version, address creator, bytes signature); + + function delegateSetupNewToken( + bytes memory premintConfigEncoded, + bytes32 premintVersion, + bytes calldata signature, + address sender + ) external returns (uint256 newTokenId); +} diff --git a/packages/1155-contracts/src/interfaces/IZoraCreator1155Errors.sol b/packages/1155-contracts/src/interfaces/IZoraCreator1155Errors.sol index b32a7d445..36e1ced50 100644 --- a/packages/1155-contracts/src/interfaces/IZoraCreator1155Errors.sol +++ b/packages/1155-contracts/src/interfaces/IZoraCreator1155Errors.sol @@ -34,4 +34,6 @@ interface IZoraCreator1155Errors is ICreatorRoyaltyErrors, ILimitedMintPerAddres error MintNotYetStarted(); error PremintDeleted(); + + error InvalidSignatureVersion(); } diff --git a/packages/1155-contracts/src/interfaces/IZoraCreator1155PremintExecutor.sol b/packages/1155-contracts/src/interfaces/IZoraCreator1155PremintExecutor.sol index b66df3af3..fbc449ed0 100644 --- a/packages/1155-contracts/src/interfaces/IZoraCreator1155PremintExecutor.sol +++ b/packages/1155-contracts/src/interfaces/IZoraCreator1155PremintExecutor.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.17; import {PremintEncoding, ZoraCreator1155Attribution, ContractCreationConfig, PremintConfig, PremintConfigV2, TokenCreationConfig, TokenCreationConfigV2} from "../delegation/ZoraCreator1155Attribution.sol"; +import {IOwnable2StepUpgradeable} from "../utils/ownable/IOwnable2StepUpgradeable.sol"; import {IZoraCreator1155Factory} from "./IZoraCreator1155Factory.sol"; // interface for legacy v1 of premint executor methods @@ -62,7 +63,12 @@ interface IZoraCreator1155PremintExecutorV2 { ) external view returns (bool isValid, address recoveredSigner); } -interface IZoraCreator1155PremintExecutor is IZoraCreator1155PremintExecutorV1, IZoraCreator1155PremintExecutorV2 { +interface IZoraCreator1155PremintExecutor is + ILegacyZoraCreator1155PremintExecutor, + IZoraCreator1155PremintExecutorV1, + IZoraCreator1155PremintExecutorV2, + IOwnable2StepUpgradeable +{ struct MintArguments { address mintRecipient; string mintComment; diff --git a/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol b/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol index d09db27ae..7ee7c4d3c 100644 --- a/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol +++ b/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol @@ -32,6 +32,7 @@ import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol"; import {ZoraCreator1155StorageV1} from "./ZoraCreator1155StorageV1.sol"; import {IZoraCreator1155Errors} from "../interfaces/IZoraCreator1155Errors.sol"; import {ERC1155DelegationStorageV1} from "../delegation/ERC1155DelegationStorageV1.sol"; +import {IZoraCreator1155DelegatedCreation} from "../interfaces/IZoraCreator1155DelegatedCreation.sol"; import {ZoraCreator1155Attribution, DecodedCreatorAttribution, PremintTokenSetup, PremintConfig, PremintConfigV2, DelegatedTokenCreation, DelegatedTokenSetup} from "../delegation/ZoraCreator1155Attribution.sol"; /// Imagine. Mint. Enjoy. @@ -564,7 +565,11 @@ contract ZoraCreator1155Impl is function supportsInterface( bytes4 interfaceId ) public view virtual override(CreatorRoyaltiesControl, ERC1155Upgradeable, IERC165Upgradeable) returns (bool) { - return super.supportsInterface(interfaceId) || interfaceId == type(IZoraCreator1155).interfaceId || ERC1155Upgradeable.supportsInterface(interfaceId); + return + super.supportsInterface(interfaceId) || + interfaceId == type(IZoraCreator1155).interfaceId || + ERC1155Upgradeable.supportsInterface(interfaceId) || + interfaceId == type(IZoraCreator1155DelegatedCreation).interfaceId; } /// Generic 1155 function overrides /// diff --git a/packages/1155-contracts/test/fixtures/Zora1155FactoryFixtures.sol b/packages/1155-contracts/test/fixtures/Zora1155FactoryFixtures.sol index d6ccfae24..6bfa5a533 100644 --- a/packages/1155-contracts/test/fixtures/Zora1155FactoryFixtures.sol +++ b/packages/1155-contracts/test/fixtures/Zora1155FactoryFixtures.sol @@ -10,11 +10,13 @@ import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; import {ProtocolRewards} from "@zoralabs/protocol-rewards/src/ProtocolRewards.sol"; import {ProxyShim} from "../../src/utils/ProxyShim.sol"; +import {IUpgradeGate} from "../../src/interfaces/IUpgradeGate.sol"; +import {UpgradeGate} from "../../src/upgrades/UpgradeGate.sol"; library Zora1155FactoryFixtures { - function setupZora1155Impl(address zora, Zora1155Factory factoryProxy) internal returns (ZoraCreator1155Impl) { + function setupZora1155Impl(address zora, IUpgradeGate upgradeGate) internal returns (ZoraCreator1155Impl) { ProtocolRewards rewards = new ProtocolRewards(); - return new ZoraCreator1155Impl(zora, address(factoryProxy), address(rewards)); + return new ZoraCreator1155Impl(zora, address(upgradeGate), address(rewards)); } function upgradeFactoryProxyToUse1155( @@ -36,13 +38,23 @@ library Zora1155FactoryFixtures { factoryProxy = new Zora1155Factory(factoryShimAddress, ""); } + function setupNew1155AndFactory( + address zora, + IUpgradeGate upgradeGate, + IMinter1155 fixedPriceMinter + ) internal returns (ZoraCreator1155Impl zoraCreator1155Impl, ZoraCreator1155FactoryImpl factoryImpl) { + zoraCreator1155Impl = setupZora1155Impl(zora, upgradeGate); + factoryImpl = new ZoraCreator1155FactoryImpl(zoraCreator1155Impl, IMinter1155(address(1)), fixedPriceMinter, IMinter1155(address(3))); + } + function setup1155AndFactoryProxy( address zora, address deployer - ) internal returns (ZoraCreator1155Impl zoraCreator1155Impl, IMinter1155 fixedPriceMinter, Zora1155Factory factoryProxy) { + ) internal returns (ZoraCreator1155Impl zoraCreator1155Impl, IMinter1155 fixedPriceMinter, Zora1155Factory factoryProxy, IUpgradeGate upgradeGate) { factoryProxy = setupFactoryProxy(deployer); fixedPriceMinter = new ZoraCreatorFixedPriceSaleStrategy(); - zoraCreator1155Impl = setupZora1155Impl(zora, factoryProxy); + upgradeGate = new UpgradeGate(); + zoraCreator1155Impl = setupZora1155Impl(zora, upgradeGate); upgradeFactoryProxyToUse1155(factoryProxy, zoraCreator1155Impl, fixedPriceMinter, deployer); } } diff --git a/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol b/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol index 99acb2d6c..e3d99241f 100644 --- a/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol +++ b/packages/1155-contracts/test/fixtures/Zora1155PremintFixtures.sol @@ -9,7 +9,7 @@ import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {ZoraCreator1155FactoryImpl} from "../../src/factory/ZoraCreator1155FactoryImpl.sol"; import {ProtocolRewards} from "@zoralabs/protocol-rewards/src/ProtocolRewards.sol"; import {ProxyShim} from "../../src/utils/ProxyShim.sol"; -import {ContractCreationConfig, TokenCreationConfigV2} from "../../src/delegation/ZoraCreator1155Attribution.sol"; +import {PremintConfig, ContractCreationConfig, TokenCreationConfigV2, TokenCreationConfig} from "../../src/delegation/ZoraCreator1155Attribution.sol"; library Zora1155PremintFixtures { function makeDefaultContractCreationConfig(address contractAdmin) internal pure returns (ContractCreationConfig memory) { @@ -51,4 +51,26 @@ library Zora1155PremintFixtures { createReferral: createReferral }); } + + function makeDefaultV1PremintConfig(IMinter1155 fixedPriceMinter, address royaltyRecipient) internal pure returns (PremintConfig memory) { + // make a v1 premint config + return + PremintConfig({ + tokenConfig: TokenCreationConfig({ + tokenURI: "blah.token", + maxSupply: 10, + maxTokensPerAddress: 5, + pricePerToken: 0, + mintStart: 0, + mintDuration: 0, + fixedPriceMinter: address(fixedPriceMinter), + royaltyRecipient: royaltyRecipient, + royaltyBPS: 10, + royaltyMintSchedule: 0 + }), + uid: 100, + version: 0, + deleted: false + }); + } } diff --git a/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol b/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol index 2aac3c870..b20fb10a2 100644 --- a/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol +++ b/packages/1155-contracts/test/premint/Zora1155PremintExecutorProxy.t.sol @@ -11,11 +11,12 @@ import {ZoraCreator1155PremintExecutorImpl} from "../../src/delegation/ZoraCreat import {Zora1155Factory} from "../../src/proxies/Zora1155Factory.sol"; import {IMinter1155} from "../../src/interfaces/IMinter1155.sol"; import {ProxyShim} from "../../src/utils/ProxyShim.sol"; -import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfigV2, PremintConfigV2} from "../../src/delegation/ZoraCreator1155Attribution.sol"; +import {ZoraCreator1155Attribution, ContractCreationConfig, TokenCreationConfigV2, PremintConfigV2, PremintConfig} from "../../src/delegation/ZoraCreator1155Attribution.sol"; import {IOwnable2StepUpgradeable} from "../../src/utils/ownable/IOwnable2StepUpgradeable.sol"; import {IHasContractName} from "../../src/interfaces/IContractMetadata.sol"; import {ZoraCreator1155PremintExecutorImplLib} from "../../src/delegation/ZoraCreator1155PremintExecutorImplLib.sol"; -import {IZoraCreator1155PremintExecutor} from "../../src/interfaces/IZoraCreator1155PremintExecutor.sol"; +import {IUpgradeGate} from "../../src/interfaces/IUpgradeGate.sol"; +import {IZoraCreator1155PremintExecutor, ILegacyZoraCreator1155PremintExecutor} from "../../src/interfaces/IZoraCreator1155PremintExecutor.sol"; contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { address internal owner; @@ -37,7 +38,7 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { (creator, creatorPrivateKey) = makeAddrAndKey("creator"); vm.startPrank(zora); - (, , factoryProxy) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(zora, zora); + (, , factoryProxy, ) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(zora, zora); factoryAtProxy = ZoraCreator1155FactoryImpl(address(factoryProxy)); vm.stopPrank(); @@ -70,20 +71,14 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { address deterministicAddress = preminterAtProxy.getContractAddress(contractConfig); // sign the premint - bytes32 structHash = ZoraCreator1155Attribution.hashPremint(premintConfig); - bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4( - structHash, - deterministicAddress, + bytes memory signature = _signPremint( + ZoraCreator1155Attribution.hashPremint(premintConfig), ZoraCreator1155Attribution.HASHED_VERSION_2, - block.chainid + deterministicAddress ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(creatorPrivateKey, digest); - uint256 quantityToMint = 1; - bytes memory signature = abi.encodePacked(r, s, v); - // execute the premint vm.deal(collector, mintFeeAmount); vm.prank(collector); @@ -121,4 +116,80 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName { vm.prank(owner); preminterAtProxy.upgradeTo(address(newImplementation)); } + + function test_canExecutePremint_onOlderVersionOf1155() external { + vm.createSelectFork("zora", 5_000_000); + + // 1. execute premint using older version of proxy, this will create 1155 contract using the legacy interface + address preminterProxy = 0x7777773606e7e46C8Ba8B98C08f5cD218e31d340; + address upgradeGate = 0xbC50029836A59A4E5e1Bb8988272F46ebA0F9900; + // get premint and factory proxies from forked deployments + ZoraCreator1155PremintExecutorImpl forkedPreminterProxy = ZoraCreator1155PremintExecutorImpl(preminterProxy); + ZoraCreator1155FactoryImpl forkedFactoryAtProxy = ZoraCreator1155FactoryImpl(address(forkedPreminterProxy.zora1155Factory())); + IMinter1155 fixedPriceMinter = forkedFactoryAtProxy.fixedPriceMinter(); + + // build and sign v1 premint config + ContractCreationConfig memory contractConfig = Zora1155PremintFixtures.makeDefaultContractCreationConfig(creator); + address deterministicAddress = forkedPreminterProxy.getContractAddress(contractConfig); + PremintConfig memory premintConfig = Zora1155PremintFixtures.makeDefaultV1PremintConfig(fixedPriceMinter, creator); + + bytes memory signature = _signPremint( + ZoraCreator1155Attribution.hashPremint(premintConfig), + ZoraCreator1155Attribution.HASHED_VERSION_1, + deterministicAddress + ); + + // create 1155 contract via premint, using legacy interface + uint256 quantityToMint = 1; + vm.deal(collector, mintFeeAmount); + vm.prank(collector); + + uint256 tokenId = ILegacyZoraCreator1155PremintExecutor(forkedPreminterProxy).premint{value: mintFeeAmount}( + contractConfig, + premintConfig, + signature, + quantityToMint, + "yo" + ); + + // sanity check, make sure the token was minted + assertEq(tokenId, 1); + + // 2. upgrade premint executor and factory to current version + // create new factory proxy implementation + (, ZoraCreator1155FactoryImpl newFactoryVersion) = Zora1155FactoryFixtures.setupNew1155AndFactory(zora, IUpgradeGate(upgradeGate), fixedPriceMinter); + + // upgrade factory proxy + address upgradeOwner = forkedPreminterProxy.owner(); + vm.prank(upgradeOwner); + forkedFactoryAtProxy.upgradeTo(address(newFactoryVersion)); + // upgrade preminter + ZoraCreator1155PremintExecutorImpl newImplementation = new ZoraCreator1155PremintExecutorImpl(forkedFactoryAtProxy); + vm.prank(upgradeOwner); + forkedPreminterProxy.upgradeTo(address(newImplementation)); + + // 3. create premint on old version of contract using new version of preminter + uint32 existingUid = premintConfig.uid; + premintConfig = Zora1155PremintFixtures.makeDefaultV1PremintConfig(fixedPriceMinter, creator); + premintConfig.uid = existingUid + 1; + signature = _signPremint(ZoraCreator1155Attribution.hashPremint(premintConfig), ZoraCreator1155Attribution.HASHED_VERSION_1, deterministicAddress); + + // execute the premint + vm.deal(collector, mintFeeAmount); + vm.prank(collector); + // now premint using the new method - it should still work + tokenId = forkedPreminterProxy.premintV1{value: mintFeeAmount}(contractConfig, premintConfig, signature, quantityToMint, defaultMintArguments).tokenId; + + // sanity check, make sure token was minted and has a new token id + assertEq(tokenId, 2); + } + + function _signPremint(bytes32 structHash, bytes32 premintVersion, address contractAddress) private view returns (bytes memory signature) { + // sign the premint + bytes32 digest = ZoraCreator1155Attribution.premintHashedTypeDataV4(structHash, contractAddress, premintVersion, block.chainid); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(creatorPrivateKey, digest); + + return abi.encodePacked(r, s, v); + } } diff --git a/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol b/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol index 5e0c4486a..bd2630ff3 100644 --- a/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol +++ b/packages/1155-contracts/test/premint/ZoraCreator1155PremintExecutor.t.sol @@ -59,7 +59,7 @@ contract ZoraCreator1155PreminterTest is Test { collector = makeAddr("collector"); vm.startPrank(zora); - (, , factoryProxy) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(zora, zora); + (, , factoryProxy, ) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(zora, zora); vm.stopPrank(); factory = ZoraCreator1155FactoryImpl(address(factoryProxy)); @@ -97,34 +97,15 @@ contract ZoraCreator1155PreminterTest is Test { }); } - function makeDefaultV1PremintConfig() private view returns (PremintConfig memory) { - // make a v1 premint config - return - PremintConfig({ - tokenConfig: TokenCreationConfig({ - tokenURI: "blah.token", - maxSupply: 10, - maxTokensPerAddress: 5, - pricePerToken: 0, - mintStart: 0, - mintDuration: 0, - fixedPriceMinter: address(getFixedPriceMinter()), - royaltyRecipient: creator, - royaltyBPS: 10, - royaltyMintSchedule: 0 - }), - uid: 100, - version: 0, - deleted: false - }); - } - function test_v1Signatures_workOnV2Contract() external { // 1. Make contract creation params // configuration of contract to create ContractCreationConfig memory contractConfig = makeDefaultContractCreationConfig(); - PremintConfig memory premintConfig = makeDefaultV1PremintConfig(); + PremintConfig memory premintConfig = Zora1155PremintFixtures.makeDefaultV1PremintConfig({ + fixedPriceMinter: getFixedPriceMinter(), + royaltyRecipient: creator + }); // how many tokens are minted to the executor uint256 quantityToMint = 1;