diff --git a/.changeset/lucky-books-know.md b/.changeset/lucky-books-know.md new file mode 100644 index 000000000..a5ed4e4e1 --- /dev/null +++ b/.changeset/lucky-books-know.md @@ -0,0 +1,6 @@ +--- +"@zoralabs/protocol-deployments": patch +"@zoralabs/protocol-sdk": patch +--- + +Moved typed data definitions from protocol-sdk to protocol-deployments diff --git a/packages/protocol-deployments/package.json b/packages/protocol-deployments/package.json index 7e9e68fe5..06f7a736c 100644 --- a/packages/protocol-deployments/package.json +++ b/packages/protocol-deployments/package.json @@ -23,13 +23,13 @@ }, "dependencies": {}, "devDependencies": { - "zoralabs-tsconfig": "*", - "typescript": "^5.2.2", - "tsx": "^3.13.0", - "tsup": "^7.2.0", - "glob": "^10.2.2", - "es-main": "^1.2.0", + "@lavamoat/preinstall-always-fail": "2.0.0", "@types/node": "^20.1.2", - "@lavamoat/preinstall-always-fail": "2.0.0" + "es-main": "^1.2.0", + "tsup": "^7.2.0", + "tsx": "^3.13.0", + "typescript": "^5.2.2", + "viem": "^2.9.18", + "zoralabs-tsconfig": "*" } } diff --git a/packages/protocol-deployments/src/index.ts b/packages/protocol-deployments/src/index.ts index 8c57e1275..5591596d0 100644 --- a/packages/protocol-deployments/src/index.ts +++ b/packages/protocol-deployments/src/index.ts @@ -2,5 +2,6 @@ // built at build time. They are not checked in to git. // The can be generated by running `yarn prepack` in the root export * from "./generated/wagmi"; +export * from "./typedData"; export * as contracts1155 from "./generated/1155"; export * as mints from "./generated/mints"; diff --git a/packages/protocol-deployments/src/typedData.ts b/packages/protocol-deployments/src/typedData.ts new file mode 100644 index 000000000..11a7fecd4 --- /dev/null +++ b/packages/protocol-deployments/src/typedData.ts @@ -0,0 +1,226 @@ +import { + Address, + TypedDataDomain, + TypedData, + TypedDataToPrimitiveTypes, +} from "abitype"; +import { TypedDataDefinition } from "viem"; +import { zoraMints1155Address } from "./generated/wagmi"; + +const premintTypedDataDomain = ({ + chainId, + version, + creator1155Contract: verifyingContract, +}: { + chainId: number; + version: "1" | "2"; + creator1155Contract: Address; +}): TypedDataDomain => ({ + chainId, + name: "Preminter", + version, + verifyingContract, +}); + +const premintV1TypedDataType = { + 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" }, + ], +} as const satisfies TypedData; + +/** + * Builds a typed data definition for a PremintConfigV1 to be signed + * @returns + */ +export const premintV1TypedDataDefinition = ({ + chainId, + creator1155Contract, + message, +}: { + chainId: number; + creator1155Contract: Address; + message: TypedDataToPrimitiveTypes< + typeof premintV1TypedDataType + >["CreatorAttribution"]; +}): TypedDataDefinition< + typeof premintV1TypedDataType, + "CreatorAttribution" +> => ({ + types: premintV1TypedDataType, + primaryType: "CreatorAttribution", + domain: premintTypedDataDomain({ + chainId, + version: "1", + creator1155Contract, + }), + message, +}); + +const premintV2TypedDataType = { + 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: "royaltyBPS", type: "uint32" }, + { name: "payoutRecipient", type: "address" }, + { name: "fixedPriceMinter", type: "address" }, + { name: "createReferral", type: "address" }, + ], +} as const satisfies TypedData; + +/** + * Builds a typed data definition for a PremintConfigV2 to be signed + */ +export const premintV2TypedDataDefinition = ({ + chainId, + creator1155Contract, + message, +}: { + chainId: number; + creator1155Contract: Address; + message: TypedDataToPrimitiveTypes< + typeof premintV2TypedDataType + >["CreatorAttribution"]; +}): TypedDataDefinition< + typeof premintV2TypedDataType, + "CreatorAttribution" +> => ({ + types: premintV2TypedDataType, + primaryType: "CreatorAttribution", + domain: premintTypedDataDomain({ + chainId, + version: "2", + creator1155Contract, + }), + message, +}); + +const permitSafeTransferTypedDataType = { + PermitSafeTransfer: [ + { name: "owner", type: "address" }, + { name: "to", type: "address" }, + { name: "tokenId", type: "uint256" }, + { name: "quantity", type: "uint256" }, + { name: "safeTransferData", type: "bytes" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], +} as const; + +/** + * Builds a typed data definition for a PermitSafeTransfer on the Mints1155 contract to be signed + */ +export const mintsSafeTransferTypedDataDefinition = ({ + chainId, + message, +}: { + chainId: keyof typeof zoraMints1155Address; + message: TypedDataToPrimitiveTypes< + typeof permitSafeTransferTypedDataType + >["PermitSafeTransfer"]; +}): TypedDataDefinition< + typeof permitSafeTransferTypedDataType, + "PermitSafeTransfer" +> => ({ + types: permitSafeTransferTypedDataType, + message, + primaryType: "PermitSafeTransfer", + domain: { + chainId, + name: "Mints", + version: "1", + verifyingContract: zoraMints1155Address[chainId], + }, +}); + +const permitSafeBatchTransferTypedDataType = { + Permit: [ + { + name: "owner", + type: "address", + }, + { + name: "to", + type: "address", + }, + { + name: "tokenIds", + type: "uint256[]", + }, + { + name: "quantities", + type: "uint256[]", + }, + { + name: "safeTransferData", + type: "bytes", + }, + { + name: "nonce", + type: "uint256", + }, + { + name: "deadline", + type: "uint256", + }, + ], +} as const; + +/** + * Builds a typed data definition for a PermitSafeTransferBatch on the Mints1155 contract to be signed + * @returns + */ +export const mintsSafeTransferBatchTypedDataDefinition = ({ + chainId, + message, +}: { + chainId: keyof typeof zoraMints1155Address; + message: TypedDataToPrimitiveTypes< + typeof permitSafeBatchTransferTypedDataType + >["Permit"]; +}): TypedDataDefinition< + typeof permitSafeBatchTransferTypedDataType, + "Permit" +> => ({ + types: permitSafeBatchTransferTypedDataType, + message, + primaryType: "Permit", + domain: { + chainId, + name: "Mints", + version: "1", + verifyingContract: zoraMints1155Address[chainId], + }, +}); diff --git a/packages/protocol-sdk/src/mints/mints-contracts.ts b/packages/protocol-sdk/src/mints/mints-contracts.ts index f6228c6d6..d4119ac37 100644 --- a/packages/protocol-sdk/src/mints/mints-contracts.ts +++ b/packages/protocol-sdk/src/mints/mints-contracts.ts @@ -1,4 +1,6 @@ import { + mintsSafeTransferBatchTypedDataDefinition, + mintsSafeTransferTypedDataDefinition, zoraMints1155Config, zoraMintsManagerImplABI, zoraMintsManagerImplAddress, @@ -19,7 +21,6 @@ import { PublicClient, ReadContractParameters, SignTypedDataParameters, - TypedData, decodeErrorResult, encodeFunctionData, zeroAddress, @@ -230,11 +231,13 @@ export function makePermitTransferBatchAndTypeData({ safeTransferData, }; - const typedData = permitBatchTypedDataDefinition({ - chainId, - permit, + const typedData: SignTypedDataParameters = { + ...mintsSafeTransferBatchTypedDataDefinition({ + chainId, + message: permit, + }), account: mintsOwner, - }); + }; return { permit, @@ -283,11 +286,13 @@ export function makePermitTransferTypeData({ safeTransferData, }; - const typedData = permitTransferTypedDataDefinition({ - chainId, - permit, + const typedData: SignTypedDataParameters = { + ...mintsSafeTransferTypedDataDefinition({ + chainId, + message: permit, + }), account: mintsOwner, - }); + }; return { permit, @@ -439,123 +444,6 @@ export type CollectMintArguments = AbiParametersToPrimitiveTypes< ExtractAbiFunction["inputs"] >[3]; -function makeTypeData< - const TTypedData extends TypedData | { [key: string]: unknown }, - TPrimaryType extends string, ->(args: SignTypedDataParameters) { - return args; -} - -export function permitBatchTypedDataDefinition({ - permit, - chainId, - account, -}: { - permit: PermitSafeTransferBatch; - chainId: keyof typeof zoraMints1155Config.address; - account: Account | Address; -}) { - return makeTypeData({ - primaryType: "Permit", - types: { - Permit: [ - { - name: "owner", - type: "address", - }, - { - name: "to", - type: "address", - }, - { - name: "tokenIds", - type: "uint256[]", - }, - { - name: "quantities", - type: "uint256[]", - }, - { - name: "safeTransferData", - type: "bytes", - }, - { - name: "nonce", - type: "uint256", - }, - { - name: "deadline", - type: "uint256", - }, - ], - }, - message: permit, - domain: { - chainId, - name: "Mints", - version: "1", - verifyingContract: zoraMints1155Config.address[chainId], - }, - // signing account must be permit owner - account, - }); -} - -export function permitTransferTypedDataDefinition({ - permit, - chainId, - account, -}: { - permit: PermitSafeTransfer; - chainId: keyof typeof zoraMints1155Config.address; - account: Account | Address; -}) { - return makeTypeData({ - primaryType: "PermitSafeTransfer", - types: { - PermitSafeTransfer: [ - { - name: "owner", - type: "address", - }, - { - name: "to", - type: "address", - }, - { - name: "tokenId", - type: "uint256", - }, - { - name: "quantity", - type: "uint256", - }, - { - name: "safeTransferData", - type: "bytes", - }, - { - name: "nonce", - type: "uint256", - }, - { - name: "deadline", - type: "uint256", - }, - ], - }, - message: permit, - domain: { - chainId, - name: "Mints", - version: "1", - verifyingContract: zoraMints1155Config.address[chainId], - }, - // signing account must be permit owner - account, - }); -} - /** * Can be used to decode an a CallFailed error from the ZoraMints1155 contract when it has called a function on the ZoraMintsManager. * @param error diff --git a/packages/protocol-sdk/src/premint/contract-types.ts b/packages/protocol-sdk/src/premint/contract-types.ts index 91e70ddcb..2704d139a 100644 --- a/packages/protocol-sdk/src/premint/contract-types.ts +++ b/packages/protocol-sdk/src/premint/contract-types.ts @@ -25,58 +25,6 @@ type PremintV2HashDataTypes = AbiParametersToPrimitiveTypes; export type PremintConfigV2 = PremintV2HashDataTypes[1]; export type TokenCreationConfigV2 = PremintConfigV2["tokenConfig"]; -export const v1Types = { - 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" }, - ], -} as const; - -export const v2Types = { - 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: "royaltyBPS", type: "uint32" }, - { name: "payoutRecipient", type: "address" }, - { name: "fixedPriceMinter", type: "address" }, - { name: "createReferral", type: "address" }, - ], -} as const; - -export const PreminterDomain = "Preminter"; - export enum PremintConfigVersion { V1 = "1", V2 = "2", diff --git a/packages/protocol-sdk/src/premint/preminter.ts b/packages/protocol-sdk/src/premint/preminter.ts index 97175f9dd..bd666a5f8 100644 --- a/packages/protocol-sdk/src/premint/preminter.ts +++ b/packages/protocol-sdk/src/premint/preminter.ts @@ -27,11 +27,12 @@ import { PremintConfigV2, PremintConfigVersion, PremintConfigWithVersion, - PreminterDomain, TokenCreationConfig, - v1Types, - v2Types, } from "./contract-types"; +import { + premintV1TypedDataDefinition, + premintV2TypedDataDefinition, +} from "@zoralabs/protocol-deployments"; import { MintCosts } from "src/mint/mint-client"; export const getPremintExecutorAddress = () => @@ -55,27 +56,18 @@ export const premintTypedDataDefinition = ({ verifyingContract: Address; chainId: number; } & PremintConfigWithVersion): TypedDataDefinition => { - const domain = { - chainId, - name: PreminterDomain, - version, - verifyingContract: verifyingContract, - }; - if (version === PremintConfigVersion.V1) - return { - domain, - types: v1Types, + return premintV1TypedDataDefinition({ + chainId, + creator1155Contract: verifyingContract, message: premintConfig as PremintConfigV1, - primaryType: "CreatorAttribution", - } satisfies TypedDataDefinition; + }); if (version === PremintConfigVersion.V2) { - return { - domain, - types: v2Types, + return premintV2TypedDataDefinition({ + chainId, + creator1155Contract: verifyingContract, message: premintConfig as PremintConfigV2, - primaryType: "CreatorAttribution", - } satisfies TypedDataDefinition; + }); } throw new Error(`Invalid version ${version}`); diff --git a/yarn.lock b/yarn.lock index cd641ecb6..c7a553807 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8164,6 +8164,20 @@ viem@^1.0.0: isows "1.0.3" ws "8.13.0" +viem@^2.9.18: + version "2.9.18" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.18.tgz#5f24982fd4f186e90f1ed304e05054ebb4f263b9" + integrity sha512-QULuau6DWDVRjGDVIUPuUybqiYu8mxscvwkKQ7dqNRl6w/t8RWs92aJZSQpqEULoERlKYyFFlj7cz4mWFEchsg== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "1.0.0" + isows "1.0.3" + ws "8.13.0" + viem@^2.9.19: version "2.9.19" resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.19.tgz#095cd0331930e10ba82c32a046d704ef8d349e94"