UNPKG

viem

Version:

TypeScript Interface for Ethereum

109 lines (101 loc) 3.19 kB
import type { TypedData } from 'abitype' import { serializeSignature } from '../../../accounts/index.js' import type { ByteArray, Hex, Signature } from '../../../types/misc.js' import type { TypedDataDefinition } from '../../../types/typedData.js' import { encodePacked } from '../../../utils/abi/encodePacked.js' import { type IsHexErrorType, isHex } from '../../../utils/data/isHex.js' import { size } from '../../../utils/data/size.js' import { bytesToHex, stringToHex } from '../../../utils/encoding/toHex.js' import { encodeType, hashStruct, } from '../../../utils/signature/hashTypedData.js' import { getTypesForEIP712Domain } from '../../../utils/typedData.js' export type WrapTypedDataSignatureParameters< typedData extends TypedData | Record<string, unknown> = TypedData, primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData, /// primaryTypes = typedData extends TypedData ? keyof typedData : string, > = TypedDataDefinition<typedData, primaryType, primaryTypes> & { signature: Hex | ByteArray | Signature } export type WrapTypedDataSignatureReturnType = Hex export type WrapTypedDataSignatureErrorType = IsHexErrorType /** * Wraps a typed data signature for ERC-7739. * * @example * ```ts * const signature = wrapTypedDataSignature({ * domain: { * name: 'Ether Mail', * version: '1', * chainId: 1, * verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', * }, * types: { * Person: [ * { name: 'name', type: 'string' }, * { name: 'wallet', type: 'address' }, * ], * Mail: [ * { name: 'from', type: 'Person' }, * { name: 'to', type: 'Person' }, * { name: 'contents', type: 'string' }, * ], * }, * primaryType: 'Mail', * message: { * from: { * name: 'Cow', * wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', * }, * to: { * name: 'Bob', * wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', * }, * contents: 'Hello, Bob!', * }, * signature: '0x...', * }) * ``` */ export function wrapTypedDataSignature( parameters: WrapTypedDataSignatureParameters, ): WrapTypedDataSignatureReturnType { const { domain, message, primaryType, signature, types } = parameters const signatureHex = (() => { if (isHex(signature)) return signature if (typeof signature === 'object' && 'r' in signature && 's' in signature) return serializeSignature(signature) return bytesToHex(signature) })() // Compute dependencies for wrapped signature. const hashedDomain = hashStruct({ data: domain ?? {}, types: { EIP712Domain: getTypesForEIP712Domain({ domain }), }, primaryType: 'EIP712Domain', }) const hashedContents = hashStruct({ data: message, types: types as any, primaryType, }) const encodedType = encodeType({ primaryType, types: types as any, }) // Construct wrapped signature. return encodePacked( ['bytes', 'bytes32', 'bytes32', 'bytes', 'uint16'], [ signatureHex, hashedDomain, hashedContents, stringToHex(encodedType), size(stringToHex(encodedType)), ], ) }