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 3, 2023
1 parent b5c7481 commit 14066b4
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 64 deletions.
7 changes: 5 additions & 2 deletions .changeset/violet-starfishes-visit.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
"@zoralabs/zora-1155-contracts": minor
---

Premint v2 - for add new signature, where createReferral can be specified. ZoraCreator1155PremintExecutor recognizes new version of the signature, and still works with the v1 (legacy) version of the signature. 1155 contract has been updated to now take abi encoded premint config, premint config version, and send it to an external library to decode the config, the signer, and setup actions.
Premint v2 - for add new signature, where createReferral can be specified. ZoraCreator1155PremintExecutor recognizes new version of the signature, and still works with the v1 (legacy) version of the signature. ZoraCreator1155PremintExecutor can now validate signatures by passing it the contract address, instead of needing to pass the full contract creation config, enabling it to validate signatures for 1155 contracts that were not created via the premint executor contract. 1155 contract has been updated to now take abi encoded premint config, premint config version, and send it to an external library to decode the config, the signer, and setup actions.

changes to `ZoraCreator1155PremintExecutorImpl`:
* new function `premintV1` - takes a premint v1 signature and executed a premint, with added functionality of being able to specify mint referral and mint recipient
* new function `premintV2` - takes a premint v2 signature and executes a premint, with being able to specify mint referral and mint recipient
* 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 `premint` - call `premintV1` instead
* deprecated function `isValidSignature` - call `isValidSignatureV1` instead
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ library DelegatedTokenCreation {
);

(params, tokenSetupActions) = _recoverDelegatedTokenSetup(premintConfig, newTokenId);
} else {
} else if (premintVersion == ZoraCreator1155Attribution.HASHED_VERSION_2) {
PremintConfigV2 memory premintConfig = abi.decode(premintConfigEncoded, (PremintConfigV2));

creatorAttribution = _recoverCreatorAttribution(
Expand All @@ -411,6 +411,8 @@ library DelegatedTokenCreation {
);

(params, tokenSetupActions) = _recoverDelegatedTokenSetup(premintConfig, newTokenId);
} else {
revert IZoraCreator1155Errors.InvalidSignatureVersion();
}
}

Expand Down
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 14066b4

Please sign in to comment.