Skip to content

Commit

Permalink
Premint - can execute premint on legacy version of contracts (#299)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
oveddan authored Nov 15, 2023
1 parent c4cf5b6 commit 1c0caea
Show file tree
Hide file tree
Showing 13 changed files with 205 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
20 changes: 9 additions & 11 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,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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
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 1c0caea

Please sign in to comment.