Skip to content

Commit

Permalink
Support minting on legacy version of contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
oveddan committed Nov 9, 2023
1 parent b5ecdfc commit a403207
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-dodos-joke.md
Original file line number Diff line number Diff line change
@@ -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`
2 changes: 1 addition & 1 deletion .changeset/violet-starfishes-visit.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
* deprecated function `isValidSignature` - call `isValidSignatureV1` instead
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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(
Expand Down Expand Up @@ -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,
Expand All @@ -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);

Expand Down
19 changes: 9 additions & 10 deletions packages/1155-contracts/src/interfaces/IZoraCreator1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/*
Expand All @@ -36,7 +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 {
interface IZoraCreator1155 is
IZoraCreator1155TypesV1,
IZoraCreator1155Errors,
IVersionedContract,
IOwnable,
IERC1155MetadataURIUpgradeable,
IZoraCreator1155DelegatedCreation
{
function PERMISSION_BIT_ADMIN() external returns (uint256);

function PERMISSION_BIT_MINTER() external returns (uint256);
Expand All @@ -61,7 +68,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
Expand All @@ -84,13 +90,6 @@ interface IZoraCreator1155 is IZoraCreator1155TypesV1, IZoraCreator1155Errors, I
/// @param maxSupply maxSupply for the token, set to 0 for open edition
function setupNewToken(string memory tokenURI, uint256 maxSupply) external returns (uint256 tokenId);

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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ interface IZoraCreator1155Errors is ICreatorRoyaltyErrors, ILimitedMintPerAddres

error MintNotYetStarted();
error PremintDeleted();

error InvalidSignatureVersion();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 ///
Expand Down
20 changes: 16 additions & 4 deletions packages/1155-contracts/test/fixtures/Zora1155FactoryFixtures.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
});
}
}
Loading

0 comments on commit a403207

Please sign in to comment.