Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Premint - get supported premint signature version #303

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/serious-goats-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/zora-1155-contracts": patch
---

Premint - added method getSupportedPremintSignatureVersions(contractAddress) that returns an array of the premint signature versions an 1155 contract supports. If the contract hasn't been created yet, assumes that when it will be created it will support the latest versions of the signatures, so the function returns all versions.
5 changes: 5 additions & 0 deletions .changeset/thirty-dragons-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/zora-1155-contracts": patch
---

Added method `IZoraCreator1155PremintExecutor.supportedPremintSignatureVersions(contractAddress)` that tells what version of the premint signature the contract supports, and added corresponding method `ZoraCreator1155Impl.supportedPremintSignatureVersions()` to fetch supported version. If premint not supported, returns an empty array.
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,16 @@ library DelegatedTokenCreation {
}
}

function supportedPremintSignatureVersions() external pure returns (string[] memory versions) {
return _supportedPremintSignatureVersions();
}

function _supportedPremintSignatureVersions() internal pure returns (string[] memory versions) {
versions = new string[](2);
versions[0] = ZoraCreator1155Attribution.VERSION_1;
versions[1] = ZoraCreator1155Attribution.VERSION_2;
}

function _recoverCreatorAttribution(
string memory version,
bytes32 structHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {ZoraCreatorFixedPriceSaleStrategy} from "../minters/fixed-price/ZoraCrea
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 {PremintEncoding, ZoraCreator1155Attribution, DelegatedTokenCreation, ContractCreationConfig, PremintConfig, PremintConfigV2, TokenCreationConfig, TokenCreationConfigV2} from "./ZoraCreator1155Attribution.sol";
import {IZoraCreator1155PremintExecutor} from "../interfaces/IZoraCreator1155PremintExecutor.sol";
import {IZoraCreator1155DelegatedCreation} from "../interfaces/IZoraCreator1155DelegatedCreation.sol";

struct MintArguments {
// which account should receive the tokens minted.
Expand Down Expand Up @@ -213,6 +214,31 @@ contract ZoraCreator1155PremintExecutorImpl is
);
}

/// @notice Returns the versions of the premint signature that the contract supports
/// @param contractAddress The address of the contract to check
/// @return versions The versions of the premint signature that the contract supports. If contract hasn't been created yet,
/// assumes that when it will be created it will support the latest versions of the signatures, so the function returns all versions.
function supportedPremintSignatureVersions(address contractAddress) external view returns (string[] memory versions) {
// if contract hasn't been created yet, assume it will be created with the latest version
// and thus supports all versions of the signature
if (contractAddress.code.length == 0) {
return DelegatedTokenCreation._supportedPremintSignatureVersions();
}

IZoraCreator1155 creatorContract = IZoraCreator1155(contractAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should version be a string or an integer?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hrrrm great q. when you sign the message, the version according to eip-712 is a string. so maybe it makes sense for this to actually return an array saying supportedSignatureVersions with an array of the versions supported?

or we store internally as integers and convert to string in the eip-712 domain, and this returns a an integer which acts as a max version.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String is fine for alignment for EIP-712. Another option would be to stringify an integer to come up.

if (creatorContract.supportsInterface(type(IZoraCreator1155DelegatedCreation).interfaceId)) {
return IZoraCreator1155DelegatedCreation(contractAddress).supportedPremintSignatureVersions();
}

// try get token id for uid 0 - if call fails, we know this didn't support premint
try ERC1155DelegationStorageV1(contractAddress).delegatedTokenId(uint32(0)) returns (uint256) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we somehow ensuring that the first premint executed on a contract is uid 0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't really matter here - this is really just checking if that function exists on the contract. even if the uid is not 0, this will return 0. It will revert if the function doesn't exist on the contract

versions = new string[](1);
versions[0] = ZoraCreator1155Attribution.VERSION_1;
} catch {
versions = new string[](0);
}
}

// upgrade related functionality

/// @notice The name of the contract for upgrade purposes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pragma solidity 0.8.17;
interface IZoraCreator1155DelegatedCreation {
event CreatorAttribution(bytes32 structHash, string domainName, string version, address creator, bytes signature);

function supportedPremintSignatureVersions() external pure returns (string[] memory);

function delegateSetupNewToken(
bytes memory premintConfigEncoded,
bytes32 premintVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,6 @@ interface IZoraCreator1155PremintExecutor is
function zora1155Factory() external view returns (IZoraCreator1155Factory);

function getContractAddress(ContractCreationConfig calldata contractConfig) external view returns (address);

function supportedPremintSignatureVersions(address contractAddress) external view returns (string[] memory);
}
4 changes: 4 additions & 0 deletions packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,10 @@ contract ZoraCreator1155Impl is
return _getImplementation();
}

function supportedPremintSignatureVersions() external pure returns (string[] memory) {
return DelegatedTokenCreation.supportedPremintSignatureVersions();
}

/// Sets up a new token using a token configuration and a signature created for the token creation parameters.
/// The signature must be created by an account with the PERMISSION_BIT_MINTER role on the contract.
/// @param premintConfig abi encoded configuration of token to be created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ contract Zora1155PremintExecutorProxyTest is Test, IHasContractName {
forkedPreminterProxy.upgradeTo(address(newImplementation));

// 3. create premint on old version of contract using new version of preminter
// verify the 1155 supports up to version 1
string[] memory supportedVersions = forkedPreminterProxy.supportedPremintSignatureVersions(deterministicAddress);
assertEq(supportedVersions.length, 1);
assertEq(supportedVersions[0], "1");

uint32 existingUid = premintConfig.uid;
premintConfig = Zora1155PremintFixtures.makeDefaultV1PremintConfig(fixedPriceMinter, creator);
premintConfig.uid = existingUid + 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,54 @@ contract ZoraCreator1155PreminterTest is Test {
preminter.premintV2{value: mintCost}(contractConfig, premintConfig2, newCreatorSignature, quantityToMint, defaultMintArguments);
}

function test_premintVersion_whenCreatedBeforePremint_returnsZero() external {
vm.createSelectFork("zora", 5_789_193);

// create preminter on fork
vm.startPrank(zora);
(, , factoryProxy, ) = Zora1155FactoryFixtures.setup1155AndFactoryProxy(zora, zora);
vm.stopPrank();

factory = ZoraCreator1155FactoryImpl(address(factoryProxy));

preminter = new ZoraCreator1155PremintExecutorImpl(factory);

// this is a known contract deployed from the legacy factory proxy on zora mainnet
// that does not support getting the uid or premint sig version (it is prior to version 2)
address erc1155BeforePremint = 0xcACBbee9C2C703274BE026B62860cF56361410f3;
assertFalse(erc1155BeforePremint.code.length == 0);

// if contract is not a known 1155 contract that supports getting uid or premint sig version,
// this should return 0
assertEq(preminter.supportedPremintSignatureVersions(erc1155BeforePremint).length, 0);
}

function test_premintVersion_beforeCreated_returnsAllVersion() external {
// build a premint
string[] memory supportedVersions = preminter.supportedPremintSignatureVersions(makeAddr("randomContract"));

assertEq(supportedVersions.length, 2);
assertEq(supportedVersions[0], "1");
assertEq(supportedVersions[1], "2");
}

function test_premintVersion_whenCreated_returnsAllVersion() external {
// build a premint
ContractCreationConfig memory contractConfig = makeDefaultContractCreationConfig();
PremintConfigV2 memory premintConfig = makeDefaultPremintConfig();

// sign and execute premint
address deterministicAddress = preminter.getContractAddress(contractConfig);

_signAndExecutePremint(contractConfig, premintConfig, creatorPrivateKey, block.chainid, premintExecutor, 1, "hi");

string[] memory supportedVersions = preminter.supportedPremintSignatureVersions(deterministicAddress);

assertEq(supportedVersions.length, 2);
assertEq(supportedVersions[0], "1");
assertEq(supportedVersions[1], "2");
}

function testPremintWithCreateReferral() public {
address createReferral = makeAddr("createReferral");

Expand Down
Loading