From e7fcba15225280d7e0c7184f24e7d5b104576372 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Fri, 3 Nov 2023 12:01:14 -0600 Subject: [PATCH] Support minting on legacy version of contracts --- .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;