-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Changed premint executor to use simpler method for determining if sig…
…ner is authorized to sign a premint (#344) * Simplified authorization determining methods for premint; Instead of having a bunch of methods that need to decode a signature and determine if a creator is authorized to create premints, just have a single method that determines if the creator is authorized, and put the burden on external clients to decode the signature. * added new premint sdk method to replace existing `isAuthorizedToSign` function that existed on the contract`
- Loading branch information
1 parent
36eea20
commit 43ffa60
Showing
7 changed files
with
205 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { Address } from "abitype"; | ||
import { ExtractAbiFunction, AbiParametersToPrimitiveTypes } from "abitype"; | ||
import { | ||
zoraCreator1155PremintExecutorImplABI as preminterAbi, | ||
zoraCreator1155PremintExecutorImplAddress, | ||
} from "@zoralabs/protocol-deployments"; | ||
import { | ||
TypedDataDefinition, | ||
recoverTypedDataAddress, | ||
Hex, | ||
PublicClient, | ||
} from "viem"; | ||
|
||
type PremintInputs = ExtractAbiFunction< | ||
typeof preminterAbi, | ||
"premint" | ||
>["inputs"]; | ||
|
||
type PreminterHashDataTypes = AbiParametersToPrimitiveTypes<PremintInputs>; | ||
|
||
export type ContractCreationConfig = PreminterHashDataTypes[0]; | ||
export type PremintConfig = PreminterHashDataTypes[1]; | ||
export type TokenCreationConfig = PremintConfig["tokenConfig"]; | ||
|
||
// Convenience method to create the structured typed data | ||
// needed to sign for a premint contract and token | ||
export const preminterTypedDataDefinition = ({ | ||
verifyingContract, | ||
premintConfig, | ||
chainId, | ||
}: { | ||
verifyingContract: Address; | ||
premintConfig: PremintConfig; | ||
chainId: number; | ||
}) => { | ||
const { tokenConfig, uid, version, deleted } = premintConfig; | ||
const types = { | ||
CreatorAttribution: [ | ||
{ name: "tokenConfig", type: "TokenCreationConfig" }, | ||
// unique id scoped to the contract and token to create. | ||
// ensure that a signature can be replaced, as long as the replacement | ||
// has the same uid, and a newer version. | ||
{ name: "uid", type: "uint32" }, | ||
{ name: "version", type: "uint32" }, | ||
// if this update should result in the signature being deleted. | ||
{ name: "deleted", type: "bool" }, | ||
], | ||
TokenCreationConfig: [ | ||
{ name: "tokenURI", type: "string" }, | ||
{ name: "maxSupply", type: "uint256" }, | ||
{ name: "maxTokensPerAddress", type: "uint64" }, | ||
{ name: "pricePerToken", type: "uint96" }, | ||
{ name: "mintStart", type: "uint64" }, | ||
{ name: "mintDuration", type: "uint64" }, | ||
{ name: "royaltyMintSchedule", type: "uint32" }, | ||
{ name: "royaltyBPS", type: "uint32" }, | ||
{ name: "royaltyRecipient", type: "address" }, | ||
{ name: "fixedPriceMinter", type: "address" }, | ||
], | ||
}; | ||
|
||
const result: TypedDataDefinition<typeof types, "CreatorAttribution"> = { | ||
domain: { | ||
chainId, | ||
name: "Preminter", | ||
version: "1", | ||
verifyingContract: verifyingContract, | ||
}, | ||
types, | ||
message: { | ||
tokenConfig, | ||
uid, | ||
version, | ||
deleted, | ||
}, | ||
primaryType: "CreatorAttribution", | ||
}; | ||
|
||
return result; | ||
}; | ||
|
||
export async function isValidSignatureV1({ | ||
contractAddress, | ||
originalContractAdmin, | ||
premintConfig, | ||
signature, | ||
chainId, | ||
publicClient, | ||
}: { | ||
contractAddress: Address; | ||
originalContractAdmin: Address; | ||
premintConfig: PremintConfig; | ||
signature: Hex; | ||
chainId: number; | ||
publicClient: PublicClient; | ||
}): Promise<{ | ||
isAuthorized: boolean; | ||
recoveredAddress?: Address; | ||
}> { | ||
const typedData = preminterTypedDataDefinition({ | ||
verifyingContract: contractAddress, | ||
premintConfig, | ||
chainId, | ||
}); | ||
|
||
// recover the address from the signature | ||
let recoveredAddress: Address; | ||
|
||
try { | ||
recoveredAddress = await recoverTypedDataAddress({ | ||
...typedData, | ||
signature, | ||
}); | ||
} catch (error) { | ||
console.error(error); | ||
|
||
return { | ||
isAuthorized: false, | ||
}; | ||
} | ||
|
||
// premint executor is same address on all chains | ||
const premintExecutorAddress = zoraCreator1155PremintExecutorImplAddress[999]; | ||
|
||
const isAuthorized = await publicClient.readContract({ | ||
abi: preminterAbi, | ||
address: premintExecutorAddress, | ||
functionName: "isAuthorizedToCreatePremint", | ||
args: [recoveredAddress, originalContractAdmin, contractAddress], | ||
}); | ||
|
||
return { | ||
isAuthorized, | ||
recoveredAddress, | ||
}; | ||
} |