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

WIP - premint v2 sdk #364

Closed
wants to merge 5 commits into from
Closed
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/rare-wolves-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/protocol-sdk": patch
---

support parsing and recovering signature from premint config version 2
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.
13 changes: 11 additions & 2 deletions .changeset/violet-starfishes-visit.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ struct TokenCreationConfig {
* new function `premintV1` - takes a `PremintConfig`, and premint v1 signature, and executes a premint, with added functionality of being able to specify mint referral and mint recipient
* new function `premintV2` - takes a `PremintConfigV2` 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.
* new function

```solidity
isAuthorizedToCreatePremint(
address signer,
address premintContractConfigContractAdmin,
address contractAddress
) public view returns (bool isAuthorized)
```

takes a signer, contractConfig.contractAdmin, and 1155 address, and determines if the signer is authorized to sign premints on the given contract. Replaces `isValidSignature` - by putting the burden on clients to first decode the signature, then pass the recovered signer to this function to determine if the signer has premint authorization on the contract.
* deprecated function `isValidSignature` - call `isValidSignatureV1` instead
5 changes: 5 additions & 0 deletions .changeset/wicked-dolphins-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/premint-sdk": patch
---

`preminter` exposes new function isValidSignatureV1 that recovers a signer from a signed premint and determines if that signer is authorized to sign
Original file line number Diff line number Diff line change
Expand Up @@ -234,25 +234,17 @@ library ZoraCreator1155Attribution {
/// @dev copied from ZoraCreator1155Impl
uint256 constant PERMISSION_BIT_MINTER = 2 ** 2;

function isValidSignature(
address originalPremintCreator,
address contractAddress,
bytes32 structHash,
bytes32 hashedVersion,
bytes calldata signature
) internal view returns (bool isValid, address recoveredSigner) {
recoveredSigner = recoverSignerHashed(structHash, signature, contractAddress, hashedVersion, block.chainid);

if (recoveredSigner == address(0)) {
return (false, address(0));
}

// if contract hasn't been created, signer must be the contract admin on the config
function isAuthorizedToCreatePremint(
address signer,
address premintContractConfigContractAdmin,
address contractAddress
) internal view returns (bool authorized) {
// if contract hasn't been created, signer must be the contract admin on the premint config
if (contractAddress.code.length == 0) {
isValid = recoveredSigner == originalPremintCreator;
return signer == premintContractConfigContractAdmin;
} else {
// if contract has been created, signer must have mint new token permission
isValid = IZoraCreator1155(contractAddress).isAdminOrRole(recoveredSigner, CONTRACT_BASE_ID, PERMISSION_BIT_MINTER);
authorized = IZoraCreator1155(contractAddress).isAdminOrRole(signer, CONTRACT_BASE_ID, PERMISSION_BIT_MINTER);
}
}
}
Expand Down Expand Up @@ -420,6 +412,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 @@ -152,65 +153,67 @@ contract ZoraCreator1155PremintExecutorImpl is
return (true, ERC1155DelegationStorageV1(contractAddress).delegatedTokenId(uid));
}

// @custom:deprecated use isValidSignatureV1 instead
// @custom:deprecated use isAuthorizedToCreatePremint instead
function isValidSignature(
ContractCreationConfig calldata contractConfig,
PremintConfig calldata premintConfig,
bytes calldata signature
) public view returns (bool isValid, address contractAddress, address recoveredSigner) {
contractAddress = getContractAddress(contractConfig);

(isValid, recoveredSigner) = isValidSignatureV1(contractConfig.contractAdmin, contractAddress, premintConfig, signature);
}

/// @notice Recovers the signer of a premint, and checks if the signer is authorized to sign the premint.
/// @dev for use with v1 of premint config, PremintConfig
/// @param premintContractConfigContractAdmin If this contract was created via premint, the original contractConfig.contractAdmin. Otherwise, set to address(0)
/// @param contractAddress The determinstic 1155 contract address the premint is for
/// @param premintConfig The premint config
/// @param signature The signature of the premint
/// @return isValid Whether the signature is valid
/// @return recoveredSigner The signer of the premint
function isValidSignatureV1(
address premintContractConfigContractAdmin,
address contractAddress,
PremintConfig calldata premintConfig,
bytes calldata signature
) public view returns (bool isValid, address recoveredSigner) {
bytes32 hashedPremint = ZoraCreator1155Attribution.hashPremint(premintConfig);

(isValid, recoveredSigner) = ZoraCreator1155Attribution.isValidSignature(
premintContractConfigContractAdmin,
recoveredSigner = ZoraCreator1155Attribution.recoverSignerHashed(
ZoraCreator1155Attribution.hashPremint(premintConfig),
signature,
contractAddress,
hashedPremint,
ZoraCreator1155Attribution.HASHED_VERSION_1,
signature
block.chainid
);

if (recoveredSigner == address(0)) {
return (false, address(0), recoveredSigner);
}

isValid = isAuthorizedToCreatePremint(recoveredSigner, contractConfig.contractAdmin, contractAddress);
}

/// @notice Recovers the signer of a premint, and checks if the signer is authorized to sign the premint.
/// @dev for use with v2 of premint config, PremintConfig
/// @notice Checks if the signer of a premint is authorized to sign a premint for a given contract. If the contract hasn't been created yet,
/// then the signer is authorized if the signer's address matches contractConfig.contractAdmin. Otherwise, the signer must have the PERMISSION_BIT_MINTER
/// role on the contract
/// @param signer The signer of the premint
/// @param premintContractConfigContractAdmin If this contract was created via premint, the original contractConfig.contractAdmin. Otherwise, set to address(0)
/// @param contractAddress The determinstic 1155 contract address the premint is for
/// @param premintConfig The premint config
/// @param signature The signature of the premint
/// @return isValid Whether the signature is valid
/// @return recoveredSigner The signer of the premint
function isValidSignatureV2(
/// @return isAuthorized Whether the signer is authorized
function isAuthorizedToCreatePremint(
address signer,
address premintContractConfigContractAdmin,
address contractAddress,
PremintConfigV2 calldata premintConfig,
bytes calldata signature
) public view returns (bool isValid, address recoveredSigner) {
bytes32 hashedPremint = ZoraCreator1155Attribution.hashPremint(premintConfig);
address contractAddress
) public view returns (bool isAuthorized) {
return ZoraCreator1155Attribution.isAuthorizedToCreatePremint(signer, premintContractConfigContractAdmin, contractAddress);
}

(isValid, recoveredSigner) = ZoraCreator1155Attribution.isValidSignature(
premintContractConfigContractAdmin,
contractAddress,
hashedPremint,
ZoraCreator1155Attribution.HASHED_VERSION_2,
signature
);
/// @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);
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) {
versions = new string[](1);
versions[0] = ZoraCreator1155Attribution.VERSION_1;
} catch {
versions = new string[](0);
}
}

// upgrade related functionality
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 @@ -27,6 +27,12 @@ interface ILegacyZoraCreator1155PremintExecutor {
uint256 quantityToMint,
string calldata mintComment
) external payable returns (uint256 newTokenId);

function isAuthorizedToCreatePremint(
address signer,
address premintContractConfigContractAdmin,
address contractAddress
) external view returns (bool isAuthorized);
}

interface IZoraCreator1155PremintExecutorV1 {
Expand All @@ -37,13 +43,6 @@ interface IZoraCreator1155PremintExecutorV1 {
uint256 quantityToMint,
IZoraCreator1155PremintExecutor.MintArguments calldata mintArguments
) external payable returns (IZoraCreator1155PremintExecutor.PremintResult memory);

function isValidSignatureV1(
address originalContractAdmin,
address contractAddress,
PremintConfig calldata premintConfig,
bytes calldata signature
) external view returns (bool isValid, address recoveredSigner);
}

interface IZoraCreator1155PremintExecutorV2 {
Expand All @@ -54,13 +53,6 @@ interface IZoraCreator1155PremintExecutorV2 {
uint256 quantityToMint,
IZoraCreator1155PremintExecutor.MintArguments calldata mintArguments
) external payable returns (IZoraCreator1155PremintExecutor.PremintResult memory);

function isValidSignatureV2(
address originalContractAdmin,
address contractAddress,
PremintConfigV2 calldata premintConfig,
bytes calldata signature
) external view returns (bool isValid, address recoveredSigner);
}

interface IZoraCreator1155PremintExecutor is
Expand Down Expand Up @@ -93,4 +85,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
Loading
Loading