FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,37 @@
import type { ErrorType } from '../../errors/utils.js'
import type { CompactSignature, Signature } from '../../types/misc.js'
import { type HexToBytesErrorType, hexToBytes } from '../encoding/toBytes.js'
import { type BytesToHexErrorType, bytesToHex } from '../encoding/toHex.js'
export type CompactSignatureToSignatureErrorType =
| BytesToHexErrorType
| HexToBytesErrorType
| ErrorType
/**
* @description Converts an [EIP-2098 compact signature](https://eips.ethereum.org/EIPS/eip-2098) into signature format.
*
* @param signature The compact signature to convert.
* @returns The compact signature in signature format.
*
* @example
* compactSignatureToSignature({
* r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* yParityAndS: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
* })
* // {
* // r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* // s: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
* // v: 27n
* // }
*/
export function compactSignatureToSignature({
r,
yParityAndS,
}: CompactSignature): Signature {
const yParityAndS_bytes = hexToBytes(yParityAndS)
const yParity = yParityAndS_bytes[0] & 0x80 ? 1 : 0
const s = yParityAndS_bytes
if (yParity === 1) s[0] &= 0x7f
return { r, s: bytesToHex(s), yParity }
}

19
node_modules/viem/utils/signature/hashMessage.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, SignableMessage } from '../../types/misc.js'
import { type Keccak256ErrorType, keccak256 } from '../hash/keccak256.js'
import { toPrefixedMessage } from './toPrefixedMessage.js'
type To = 'hex' | 'bytes'
export type HashMessageReturnType<to extends To> =
| (to extends 'bytes' ? ByteArray : never)
| (to extends 'hex' ? Hex : never)
export type HashMessageErrorType = Keccak256ErrorType | ErrorType
export function hashMessage<to extends To = 'hex'>(
message: SignableMessage,
to_?: to | undefined,
): HashMessageReturnType<to> {
return keccak256(toPrefixedMessage(message), to_)
}

276
node_modules/viem/utils/signature/hashTypedData.ts generated vendored Normal file
View File

@@ -0,0 +1,276 @@
// Implementation forked and adapted from https://github.com/MetaMask/eth-sig-util/blob/main/src/sign-typed-data.ts
import type { AbiParameter, TypedData } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex } from '../../types/misc.js'
import type {
EIP712DomainDefinition,
MessageDefinition,
TypedDataDefinition,
} from '../../types/typedData.js'
import type { UnionOmit } from '../../types/utils.js'
import {
type EncodeAbiParametersErrorType,
encodeAbiParameters,
} from '../abi/encodeAbiParameters.js'
import { concat } from '../data/concat.js'
import { type ToHexErrorType, toHex } from '../encoding/toHex.js'
import { type Keccak256ErrorType, keccak256 } from '../hash/keccak256.js'
import {
type GetTypesForEIP712DomainErrorType,
getTypesForEIP712Domain,
type ValidateTypedDataErrorType,
validateTypedData,
} from '../typedData.js'
type MessageTypeProperty = {
name: string
type: string
}
export type HashTypedDataParameters<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = TypedDataDefinition<typedData, primaryType>
export type HashTypedDataReturnType = Hex
export type HashTypedDataErrorType =
| GetTypesForEIP712DomainErrorType
| HashDomainErrorType
| HashStructErrorType
| ValidateTypedDataErrorType
| ErrorType
export function hashTypedData<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(
parameters: HashTypedDataParameters<typedData, primaryType>,
): HashTypedDataReturnType {
const {
domain = {},
message,
primaryType,
} = parameters as HashTypedDataParameters
const types = {
EIP712Domain: getTypesForEIP712Domain({ domain }),
...parameters.types,
}
// Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc
// as we can't statically check this with TypeScript.
validateTypedData({
domain,
message,
primaryType,
types,
})
const parts: Hex[] = ['0x1901']
if (domain)
parts.push(
hashDomain({
domain,
types: types as Record<string, MessageTypeProperty[]>,
}),
)
if (primaryType !== 'EIP712Domain')
parts.push(
hashStruct({
data: message,
primaryType,
types: types as Record<string, MessageTypeProperty[]>,
}),
)
return keccak256(concat(parts))
}
export type HashDomainErrorType = HashStructErrorType | ErrorType
export function hashDomain<
const typedData extends TypedData | Record<string, unknown> = TypedData,
>({
domain,
types,
}: UnionOmit<EIP712DomainDefinition<typedData>, 'primaryType'>) {
return hashStruct({
data: domain as Record<string, unknown>,
primaryType: 'EIP712Domain',
types: types as Record<string, readonly MessageTypeProperty[]>,
})
}
export type HashStructErrorType =
| EncodeDataErrorType
| Keccak256ErrorType
| ErrorType
export function hashStruct<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>({
data,
primaryType,
types,
}: MessageDefinition<typedData, primaryType, 'data'>) {
const encoded = encodeData({
data: data as Record<string, unknown>,
primaryType,
types: types as Record<string, readonly MessageTypeProperty[]>,
})
return keccak256(encoded)
}
type EncodeDataErrorType =
| EncodeAbiParametersErrorType
| EncodeFieldErrorType
| HashTypeErrorType
| ErrorType
function encodeData({
data,
primaryType,
types,
}: {
data: Record<string, unknown>
primaryType: string
types: Record<string, readonly MessageTypeProperty[]>
}) {
const encodedTypes: AbiParameter[] = [{ type: 'bytes32' }]
const encodedValues: unknown[] = [hashType({ primaryType, types })]
for (const field of types[primaryType]) {
const [type, value] = encodeField({
types,
name: field.name,
type: field.type,
value: data[field.name],
})
encodedTypes.push(type)
encodedValues.push(value)
}
return encodeAbiParameters(encodedTypes, encodedValues)
}
type HashTypeErrorType =
| ToHexErrorType
| EncodeTypeErrorType
| Keccak256ErrorType
| ErrorType
function hashType({
primaryType,
types,
}: {
primaryType: string
types: Record<string, readonly MessageTypeProperty[]>
}) {
const encodedHashType = toHex(encodeType({ primaryType, types }))
return keccak256(encodedHashType)
}
type EncodeTypeErrorType = FindTypeDependenciesErrorType
export function encodeType({
primaryType,
types,
}: {
primaryType: string
types: Record<string, readonly MessageTypeProperty[]>
}) {
let result = ''
const unsortedDeps = findTypeDependencies({ primaryType, types })
unsortedDeps.delete(primaryType)
const deps = [primaryType, ...Array.from(unsortedDeps).sort()]
for (const type of deps) {
result += `${type}(${types[type]
.map(({ name, type: t }) => `${t} ${name}`)
.join(',')})`
}
return result
}
type FindTypeDependenciesErrorType = ErrorType
function findTypeDependencies(
{
primaryType: primaryType_,
types,
}: {
primaryType: string
types: Record<string, readonly MessageTypeProperty[]>
},
results: Set<string> = new Set(),
): Set<string> {
const match = primaryType_.match(/^\w*/u)
const primaryType = match?.[0]!
if (results.has(primaryType) || types[primaryType] === undefined) {
return results
}
results.add(primaryType)
for (const field of types[primaryType]) {
findTypeDependencies({ primaryType: field.type, types }, results)
}
return results
}
type EncodeFieldErrorType =
| Keccak256ErrorType
| EncodeAbiParametersErrorType
| ToHexErrorType
| ErrorType
function encodeField({
types,
name,
type,
value,
}: {
types: Record<string, readonly MessageTypeProperty[]>
name: string
type: string
value: any
}): [type: AbiParameter, value: any] {
if (types[type] !== undefined) {
return [
{ type: 'bytes32' },
keccak256(encodeData({ data: value, primaryType: type, types })),
]
}
if (type === 'bytes') return [{ type: 'bytes32' }, keccak256(value)]
if (type === 'string') return [{ type: 'bytes32' }, keccak256(toHex(value))]
if (type.lastIndexOf(']') === type.length - 1) {
const parsedType = type.slice(0, type.lastIndexOf('['))
const typeValuePairs = (value as [AbiParameter, any][]).map((item) =>
encodeField({
name,
type: parsedType,
types,
value: item,
}),
)
return [
{ type: 'bytes32' },
keccak256(
encodeAbiParameters(
typeValuePairs.map(([t]) => t),
typeValuePairs.map(([, v]) => v),
),
),
]
}
return [{ type }, value]
}

View File

@@ -0,0 +1,15 @@
import { erc6492MagicBytes } from '../../constants/bytes.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex } from '../../types/misc.js'
import { type SliceHexErrorType, sliceHex } from '../data/slice.js'
export type IsErc6492SignatureParameters = Hex
export type IsErc6492SignatureReturnType = boolean
export type IsErc6492SignatureErrorType = SliceHexErrorType | ErrorType
/** Whether or not the signature is an ERC-6492 formatted signature. */
export function isErc6492Signature(
signature: IsErc6492SignatureParameters,
): IsErc6492SignatureReturnType {
return sliceHex(signature, -32) === erc6492MagicBytes
}

View File

@@ -0,0 +1,14 @@
import { SignatureErc8010 } from 'ox/erc8010'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex } from '../../types/misc.js'
export type IsErc8010SignatureParameters = Hex
export type IsErc8010SignatureReturnType = boolean
export type IsErc8010SignatureErrorType = ErrorType
/** Whether or not the signature is an ERC-8010 formatted signature. */
export function isErc8010Signature(
signature: IsErc8010SignatureParameters,
): IsErc8010SignatureReturnType {
return SignatureErc8010.validate(signature)
}

View File

@@ -0,0 +1,25 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import type { ErrorType } from '../../errors/utils.js'
import type { CompactSignature, Hex } from '../../types/misc.js'
import { type NumberToHexErrorType, numberToHex } from '../encoding/toHex.js'
export type ParseCompactSignatureErrorType = NumberToHexErrorType | ErrorType
/**
* @description Parses a hex formatted compact signature into a structured compact signature.
*
* @param signatureHex Signature in hex format.
* @returns The structured signature.
*
* @example
* parseCompactSignature('0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c')
* // { r: '0x...', yParityAndS: '0x...' }
*/
export function parseCompactSignature(signatureHex: Hex): CompactSignature {
const { r, s } = secp256k1.Signature.fromCompact(signatureHex.slice(2, 130))
return {
r: numberToHex(r, { size: 32 }),
yParityAndS: numberToHex(s, { size: 32 }),
}
}

View File

@@ -0,0 +1,65 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex } from '../../types/misc.js'
import type { OneOf, Prettify } from '../../types/utils.js'
import {
type DecodeAbiParametersErrorType,
decodeAbiParameters,
} from '../abi/decodeAbiParameters.js'
import {
type IsErc6492SignatureErrorType,
isErc6492Signature,
} from './isErc6492Signature.js'
export type ParseErc6492SignatureParameters = Hex
export type ParseErc6492SignatureReturnType = Prettify<
OneOf<
| {
/**
* The ERC-4337 Account Factory or preparation address to use for counterfactual verification.
* `undefined` if the signature is not in ERC-6492 format.
*/
address: Address
/**
* Calldata to pass to deploy account (if not deployed) for counterfactual verification.
* `undefined` if the signature is not in ERC-6492 format.
*/
data: Hex
/** The original signature. */
signature: Hex
}
| {
/** The original signature. */
signature: Hex
}
>
>
export type ParseErc6492SignatureErrorType =
| IsErc6492SignatureErrorType
| DecodeAbiParametersErrorType
| ErrorType
/**
* @description Parses a hex-formatted ERC-6492 flavoured signature.
* If the signature is not in ERC-6492 format, then the underlying (original) signature is returned.
*
* @param signature ERC-6492 signature in hex format.
* @returns The parsed ERC-6492 signature.
*
* @example
* parseSignature('0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492')
* // { address: '0x...', data: '0x...', signature: '0x...' }
*/
export function parseErc6492Signature(
signature: ParseErc6492SignatureParameters,
): ParseErc6492SignatureReturnType {
if (!isErc6492Signature(signature)) return { signature }
const [address, data, signature_] = decodeAbiParameters(
[{ type: 'address' }, { type: 'bytes' }, { type: 'bytes' }],
signature,
)
return { address, data, signature: signature_ }
}

View File

@@ -0,0 +1,67 @@
import type { Address } from 'abitype'
import { SignatureErc8010 } from 'ox/erc8010'
import type { ErrorType } from '../../errors/utils.js'
import type { SignedAuthorization } from '../../types/authorization.js'
import type { Hex } from '../../types/misc.js'
import type { OneOf, Prettify } from '../../types/utils.js'
import { numberToHex } from '../encoding/toHex.js'
import {
type IsErc8010SignatureErrorType,
isErc8010Signature,
} from './isErc8010Signature.js'
export type ParseErc8010SignatureParameters = Hex
export type ParseErc8010SignatureReturnType = Prettify<
OneOf<
| {
/** Address of the initializer. */
address?: Address | undefined
/** Authorization signed by the delegatee. */
authorization: SignedAuthorization
/** Data to initialize the delegation. */
data?: Hex | undefined
/** The original signature. */
signature: Hex
}
| {
/** The original signature. */
signature: Hex
}
>
>
export type ParseErc8010SignatureErrorType =
| IsErc8010SignatureErrorType
| ErrorType
/**
* @description Parses a hex-formatted ERC-8010 flavoured signature.
* If the signature is not in ERC-8010 format, then the underlying (original) signature is returned.
*
* @param signature ERC-8010 signature in hex format.
* @returns The parsed ERC-8010 signature.
*/
export function parseErc8010Signature(
signature: ParseErc8010SignatureParameters,
): ParseErc8010SignatureReturnType {
if (!isErc8010Signature(signature)) return { signature }
const {
authorization: authorization_ox,
to,
...rest
} = SignatureErc8010.unwrap(signature)
return {
authorization: {
address: authorization_ox.address,
chainId: authorization_ox.chainId,
nonce: Number(authorization_ox.nonce),
r: numberToHex(authorization_ox.r, { size: 32 }),
s: numberToHex(authorization_ox.s, { size: 32 }),
yParity: authorization_ox.yParity,
},
...(to ? { address: to } : {}),
...rest,
}
}

44
node_modules/viem/utils/signature/parseSignature.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex, Signature } from '../../types/misc.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
export type ParseSignatureErrorType = NumberToHexErrorType | ErrorType
/**
* @description Parses a hex formatted signature into a structured signature.
*
* @param signatureHex Signature in hex format.
* @returns The structured signature.
*
* @example
* parseSignature('0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c')
* // { r: '0x...', s: '0x...', v: 28n }
*/
export function parseSignature(signatureHex: Hex) {
const { r, s } = secp256k1.Signature.fromCompact(signatureHex.slice(2, 130))
const yParityOrV = Number(`0x${signatureHex.slice(130)}`)
const [v, yParity] = (() => {
if (yParityOrV === 0 || yParityOrV === 1) return [undefined, yParityOrV]
if (yParityOrV === 27) return [BigInt(yParityOrV), 0]
if (yParityOrV === 28) return [BigInt(yParityOrV), 1]
throw new Error('Invalid yParityOrV value')
})()
if (typeof v !== 'undefined')
return {
r: numberToHex(r, { size: 32 }),
s: numberToHex(s, { size: 32 }),
v,
yParity,
} satisfies Signature
return {
r: numberToHex(r, { size: 32 }),
s: numberToHex(s, { size: 32 }),
yParity,
} satisfies Signature
}

22
node_modules/viem/utils/signature/recoverAddress.ts generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import type { Address } from 'abitype'
import { publicKeyToAddress } from '../../accounts/utils/publicKeyToAddress.js'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import { recoverPublicKey } from './recoverPublicKey.js'
export type RecoverAddressParameters = {
hash: Hex | ByteArray
signature: Hex | ByteArray | Signature
}
export type RecoverAddressReturnType = Address
export type RecoverAddressErrorType = ErrorType
export async function recoverAddress({
hash,
signature,
}: RecoverAddressParameters): Promise<RecoverAddressReturnType> {
return publicKeyToAddress(await recoverPublicKey({ hash, signature }))
}

View File

@@ -0,0 +1,32 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type {
ByteArray,
Hex,
SignableMessage,
Signature,
} from '../../types/misc.js'
import { type HashMessageErrorType, hashMessage } from './hashMessage.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from './recoverAddress.js'
export type RecoverMessageAddressParameters = {
message: SignableMessage
signature: Hex | ByteArray | Signature
}
export type RecoverMessageAddressReturnType = Address
export type RecoverMessageAddressErrorType =
| HashMessageErrorType
| RecoverAddressErrorType
| ErrorType
export async function recoverMessageAddress({
message,
signature,
}: RecoverMessageAddressParameters): Promise<RecoverMessageAddressReturnType> {
return recoverAddress({ hash: hashMessage(message), signature })
}

64
node_modules/viem/utils/signature/recoverPublicKey.ts generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import { type IsHexErrorType, isHex } from '../data/isHex.js'
import { size } from '../data/size.js'
import {
type HexToNumberErrorType,
hexToBigInt,
hexToNumber,
} from '../encoding/fromHex.js'
import { toHex } from '../encoding/toHex.js'
export type RecoverPublicKeyParameters = {
hash: Hex | ByteArray
signature: Hex | ByteArray | Signature
}
export type RecoverPublicKeyReturnType = Hex
export type RecoverPublicKeyErrorType =
| HexToNumberErrorType
| IsHexErrorType
| ErrorType
export async function recoverPublicKey({
hash,
signature,
}: RecoverPublicKeyParameters): Promise<RecoverPublicKeyReturnType> {
const hashHex = isHex(hash) ? hash : toHex(hash)
const { secp256k1 } = await import('@noble/curves/secp256k1')
const signature_ = (() => {
// typeof signature: `Signature`
if (typeof signature === 'object' && 'r' in signature && 's' in signature) {
const { r, s, v, yParity } = signature
const yParityOrV = Number(yParity ?? v)!
const recoveryBit = toRecoveryBit(yParityOrV)
return new secp256k1.Signature(
hexToBigInt(r),
hexToBigInt(s),
).addRecoveryBit(recoveryBit)
}
// typeof signature: `Hex | ByteArray`
const signatureHex = isHex(signature) ? signature : toHex(signature)
if (size(signatureHex) !== 65) throw new Error('invalid signature length')
const yParityOrV = hexToNumber(`0x${signatureHex.slice(130)}`)
const recoveryBit = toRecoveryBit(yParityOrV)
return secp256k1.Signature.fromCompact(
signatureHex.substring(2, 130),
).addRecoveryBit(recoveryBit)
})()
const publicKey = signature_
.recoverPublicKey(hashHex.substring(2))
.toHex(false)
return `0x${publicKey}`
}
function toRecoveryBit(yParityOrV: number) {
if (yParityOrV === 0 || yParityOrV === 1) return yParityOrV
if (yParityOrV === 27) return 0
if (yParityOrV === 28) return 1
throw new Error('Invalid yParityOrV value')
}

View File

@@ -0,0 +1,58 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { TransactionSerialized } from '../../types/transaction.js'
import { type Keccak256ErrorType, keccak256 } from '../hash/keccak256.js'
import { parseTransaction } from '../transaction/parseTransaction.js'
import {
type SerializeTransactionErrorType,
serializeTransaction,
} from '../transaction/serializeTransaction.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from './recoverAddress.js'
import type { SerializeSignatureErrorType } from './serializeSignature.js'
export type RecoverTransactionAddressParameters = {
serializedTransaction: TransactionSerialized
signature?: Hex | ByteArray | Signature
}
export type RecoverTransactionAddressReturnType = Address
export type RecoverTransactionAddressErrorType =
| SerializeTransactionErrorType
| RecoverAddressErrorType
| Keccak256ErrorType
| SerializeSignatureErrorType
| ErrorType
export async function recoverTransactionAddress(
parameters: RecoverTransactionAddressParameters,
): Promise<RecoverTransactionAddressReturnType> {
const { serializedTransaction, signature: signature_ } = parameters
const transaction = parseTransaction(serializedTransaction)
const signature = signature_ ?? {
r: transaction.r!,
s: transaction.s!,
v: transaction.v!,
yParity: transaction.yParity!,
}
const serialized = serializeTransaction({
...transaction,
r: undefined,
s: undefined,
v: undefined,
yParity: undefined,
sidecars: undefined,
})
return await recoverAddress({
hash: keccak256(serialized),
signature,
})
}

View File

@@ -0,0 +1,42 @@
import type { Address, TypedData } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { TypedDataDefinition } from '../../types/typedData.js'
import { type HashTypedDataErrorType, hashTypedData } from './hashTypedData.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from './recoverAddress.js'
export type RecoverTypedDataAddressParameters<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = TypedDataDefinition<typedData, primaryType> & {
signature: Hex | ByteArray | Signature
}
export type RecoverTypedDataAddressReturnType = Address
export type RecoverTypedDataAddressErrorType =
| RecoverAddressErrorType
| HashTypedDataErrorType
| ErrorType
export async function recoverTypedDataAddress<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(
parameters: RecoverTypedDataAddressParameters<typedData, primaryType>,
): Promise<RecoverTypedDataAddressReturnType> {
const { domain, message, primaryType, signature, types } =
parameters as unknown as RecoverTypedDataAddressParameters
return recoverAddress({
hash: hashTypedData({
domain,
message,
primaryType,
types,
}),
signature,
})
}

View File

@@ -0,0 +1,31 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import type { ErrorType } from '../../errors/utils.js'
import type { CompactSignature, Hex } from '../../types/misc.js'
import { type HexToBigIntErrorType, hexToBigInt } from '../encoding/fromHex.js'
export type SerializeCompactSignatureErrorType =
| HexToBigIntErrorType
| ErrorType
/**
* @description Converts an [EIP-2098 compact signature](https://eips.ethereum.org/EIPS/eip-2098) into hex format.
*
* @param signature The compact signature to convert.
* @returns The compact signature in hex format.
*
* @example
* serializeCompactSignature({
* r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* yParityAndS: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
* })
* // "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c"
*/
export function serializeCompactSignature({
r,
yParityAndS,
}: CompactSignature): Hex {
return `0x${new secp256k1.Signature(
hexToBigInt(r),
hexToBigInt(yParityAndS),
).toCompactHex()}`
}

View File

@@ -0,0 +1,51 @@
import type { Address } from 'abitype'
import { erc6492MagicBytes } from '../../constants/bytes.js'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex } from '../../types/misc.js'
import { encodeAbiParameters } from '../abi/encodeAbiParameters.js'
import { concatHex } from '../data/concat.js'
import { hexToBytes } from '../encoding/toBytes.js'
type To = 'bytes' | 'hex'
export type SerializeErc6492SignatureParameters<to extends To = 'hex'> = {
/** The ERC-4337 Account Factory address to use for counterfactual verification. */
address: Address
/** Calldata to pass to deploy account (if not deployed) for counterfactual verification. */
data: Hex
/** The original signature. */
signature: Hex
to?: to | To | undefined
}
export type SerializeErc6492SignatureReturnType<to extends To = 'hex'> =
| (to extends 'hex' ? Hex : never)
| (to extends 'bytes' ? ByteArray : never)
export type SerializeErc6492SignatureErrorType = ErrorType
/**
* @description Serializes a ERC-6492 flavoured signature into hex format.
*
* @param signature ERC-6492 signature in object format.
* @returns ERC-6492 signature in hex format.
*
* @example
* serializeSignature({ address: '0x...', data: '0x...', signature: '0x...' })
* // '0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492'
*/
export function serializeErc6492Signature<to extends To = 'hex'>(
parameters: SerializeErc6492SignatureParameters<to>,
): SerializeErc6492SignatureReturnType<to> {
const { address, data, signature, to = 'hex' } = parameters
const signature_ = concatHex([
encodeAbiParameters(
[{ type: 'address' }, { type: 'bytes' }, { type: 'bytes' }],
[address, data, signature],
),
erc6492MagicBytes,
])
if (to === 'hex') return signature_ as SerializeErc6492SignatureReturnType<to>
return hexToBytes(signature_) as SerializeErc6492SignatureReturnType<to>
}

View File

@@ -0,0 +1,53 @@
import type { Address } from 'abitype'
import { SignatureErc8010 } from 'ox/erc8010'
import type { ErrorType } from '../../errors/utils.js'
import type { SignedAuthorization } from '../../types/authorization.js'
import type { ByteArray, Hex } from '../../types/misc.js'
import { hexToBytes } from '../encoding/toBytes.js'
type To = 'bytes' | 'hex'
export type SerializeErc8010SignatureParameters<to extends To = 'hex'> = {
/** Address of the initializer. */
address?: Address | undefined
/** Authorization signed by the delegatee. */
authorization: SignedAuthorization
/** Data to initialize the delegation. */
data?: Hex | undefined
/** The original signature. */
signature: Hex
to?: to | To | undefined
}
export type SerializeErc8010SignatureReturnType<to extends To = 'hex'> =
| (to extends 'hex' ? Hex : never)
| (to extends 'bytes' ? ByteArray : never)
export type SerializeErc8010SignatureErrorType = ErrorType
/**
* @description Serializes a ERC-8010 flavoured signature into hex format.
*
* @param signature ERC-8010 signature in object format.
* @returns ERC-8010 signature in hex format.
*/
export function serializeErc8010Signature<to extends To = 'hex'>(
parameters: SerializeErc8010SignatureParameters<to>,
): SerializeErc8010SignatureReturnType<to> {
const { address, data, signature, to = 'hex' } = parameters
const signature_ = SignatureErc8010.wrap({
authorization: {
address: parameters.authorization.address,
chainId: parameters.authorization.chainId,
nonce: BigInt(parameters.authorization.nonce),
r: BigInt(parameters.authorization.r),
s: BigInt(parameters.authorization.s),
yParity: parameters.authorization.yParity!,
},
data,
signature,
to: address,
})
if (to === 'hex') return signature_ as SerializeErc8010SignatureReturnType<to>
return hexToBytes(signature_) as SerializeErc8010SignatureReturnType<to>
}

View File

@@ -0,0 +1,57 @@
import { secp256k1 } from '@noble/curves/secp256k1'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import { type HexToBigIntErrorType, hexToBigInt } from '../encoding/fromHex.js'
import { hexToBytes } from '../encoding/toBytes.js'
import type { ToHexErrorType } from '../encoding/toHex.js'
type To = 'bytes' | 'hex'
export type SerializeSignatureParameters<to extends To = 'hex'> = Signature & {
to?: to | To | undefined
}
export type SerializeSignatureReturnType<to extends To = 'hex'> =
| (to extends 'hex' ? Hex : never)
| (to extends 'bytes' ? ByteArray : never)
export type SerializeSignatureErrorType =
| HexToBigIntErrorType
| ToHexErrorType
| ErrorType
/**
* @description Converts a signature into hex format.
*
* @param signature The signature to convert.
* @returns The signature in hex format.
*
* @example
* serializeSignature({
* r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf',
* s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8',
* yParity: 1
* })
* // "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c"
*/
export function serializeSignature<to extends To = 'hex'>({
r,
s,
to = 'hex',
v,
yParity,
}: SerializeSignatureParameters<to>): SerializeSignatureReturnType<to> {
const yParity_ = (() => {
if (yParity === 0 || yParity === 1) return yParity
if (v && (v === 27n || v === 28n || v >= 35n)) return v % 2n === 0n ? 1 : 0
throw new Error('Invalid `v` or `yParity` value')
})()
const signature = `0x${new secp256k1.Signature(
hexToBigInt(r),
hexToBigInt(s),
).toCompactHex()}${yParity_ === 0 ? '1b' : '1c'}` as const
if (to === 'hex') return signature as SerializeSignatureReturnType<to>
return hexToBytes(signature) as SerializeSignatureReturnType<to>
}

View File

@@ -0,0 +1,40 @@
import type { ErrorType } from '../../errors/utils.js'
import type { CompactSignature, Signature } from '../../types/misc.js'
import { type HexToBytesErrorType, hexToBytes } from '../encoding/toBytes.js'
import { type BytesToHexErrorType, bytesToHex } from '../encoding/toHex.js'
export type SignatureToCompactSignatureErrorType =
| HexToBytesErrorType
| BytesToHexErrorType
| ErrorType
/**
* @description Converts a signature into an [EIP-2098 compact signature](https://eips.ethereum.org/EIPS/eip-2098).
*
* @param signature The signature to convert.
* @returns The signature in compact format.
*
* @example
* signatureToCompactSignature({
* r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* s: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
* yParity: 0
* })
* // {
* // r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
* // yParityAndS: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'
* // }
*/
export function signatureToCompactSignature(
signature: Signature,
): CompactSignature {
const { r, s, v, yParity } = signature
const yParity_ = Number(yParity ?? v! - 27n)
let yParityAndS = s
if (yParity_ === 1) {
const bytes = hexToBytes(s)
bytes[0] |= 0x80
yParityAndS = bytesToHex(bytes)
}
return { r, yParityAndS }
}

27
node_modules/viem/utils/signature/toPrefixedMessage.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import { presignMessagePrefix } from '../../constants/strings.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex, SignableMessage } from '../../types/misc.js'
import { type ConcatErrorType, concat } from '../data/concat.js'
import { size } from '../data/size.js'
import {
type BytesToHexErrorType,
bytesToHex,
type StringToHexErrorType,
stringToHex,
} from '../encoding/toHex.js'
export type ToPrefixedMessageErrorType =
| ConcatErrorType
| StringToHexErrorType
| BytesToHexErrorType
| ErrorType
export function toPrefixedMessage(message_: SignableMessage): Hex {
const message = (() => {
if (typeof message_ === 'string') return stringToHex(message_)
if (typeof message_.raw === 'string') return message_.raw
return bytesToHex(message_.raw)
})()
const prefix = stringToHex(`${presignMessagePrefix}${size(message)}`)
return concat([prefix, message])
}

52
node_modules/viem/utils/signature/verifyHash.ts generated vendored Normal file
View File

@@ -0,0 +1,52 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hash, Hex, Signature } from '../../types/misc.js'
import { type GetAddressErrorType, getAddress } from '../address/getAddress.js'
import {
type IsAddressEqualErrorType,
isAddressEqual,
} from '../address/isAddressEqual.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from './recoverAddress.js'
export type VerifyHashParameters = {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hash
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex | ByteArray | Signature
}
export type VerifyHashReturnType = boolean
export type VerifyHashErrorType =
| IsAddressEqualErrorType
| GetAddressErrorType
| RecoverAddressErrorType
| ErrorType
/**
* Verify that a message was signed by the provided address.
*
* Note: Only supports Externally Owned Accounts. Does not support Contract Accounts.
* It is highly recommended to use `publicClient.verifyHash` instead to ensure
* wallet interoperability.
*
* - Docs {@link https://viem.sh/docs/utilities/verifyHash}
*
* @param parameters - {@link VerifyHashParameters}
* @returns Whether or not the signature is valid. {@link VerifyHashReturnType}
*/
export async function verifyHash({
address,
hash,
signature,
}: VerifyHashParameters): Promise<VerifyHashReturnType> {
return isAddressEqual(
getAddress(address),
await recoverAddress({ hash, signature }),
)
}

57
node_modules/viem/utils/signature/verifyMessage.ts generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type {
ByteArray,
Hex,
SignableMessage,
Signature,
} from '../../types/misc.js'
import { type GetAddressErrorType, getAddress } from '../address/getAddress.js'
import {
type IsAddressEqualErrorType,
isAddressEqual,
} from '../address/isAddressEqual.js'
import {
type RecoverMessageAddressErrorType,
recoverMessageAddress,
} from './recoverMessageAddress.js'
export type VerifyMessageParameters = {
/** The address that signed the original message. */
address: Address
/** The message to be verified. */
message: SignableMessage
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex | ByteArray | Signature
}
export type VerifyMessageReturnType = boolean
export type VerifyMessageErrorType =
| IsAddressEqualErrorType
| GetAddressErrorType
| RecoverMessageAddressErrorType
| ErrorType
/**
* Verify that a message was signed by the provided address.
*
* Note: Only supports Externally Owned Accounts. Does not support Contract Accounts.
* It is highly recommended to use `publicClient.verifyMessage` instead to ensure
* wallet interoperability.
*
* - Docs {@link https://viem.sh/docs/utilities/verifyMessage}
*
* @param parameters - {@link VerifyMessageParameters}
* @returns Whether or not the signature is valid. {@link VerifyMessageReturnType}
*/
export async function verifyMessage({
address,
message,
signature,
}: VerifyMessageParameters): Promise<VerifyMessageReturnType> {
return isAddressEqual(
getAddress(address),
await recoverMessageAddress({ message, signature }),
)
}

63
node_modules/viem/utils/signature/verifyTypedData.ts generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import type { Address, TypedData } from 'abitype'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { TypedDataDefinition } from '../../types/typedData.js'
import { type GetAddressErrorType, getAddress } from '../address/getAddress.js'
import {
type IsAddressEqualErrorType,
isAddressEqual,
} from '../address/isAddressEqual.js'
import {
type RecoverTypedDataAddressParameters,
recoverTypedDataAddress,
} from './recoverTypedDataAddress.js'
export type VerifyTypedDataParameters<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = TypedDataDefinition<typedData, primaryType> & {
/** The address to verify the typed data for. */
address: Address
/** The signature to verify */
signature: Hex | ByteArray | Signature
}
export type VerifyTypedDataReturnType = boolean
export type VerifyTypedDataErrorType =
| IsAddressEqualErrorType
| GetAddressErrorType
| RecoverTypedDataAddressParameters
| ErrorType
/**
* Verify that typed data was signed by the provided address.
*
* Note: Only supports Externally Owned Accounts. Does not support Contract Accounts.
* It is highly recommended to use `publicClient.verifyTypedData` instead to ensure
* wallet interoperability.
*
* - Docs {@link https://viem.sh/docs/utilities/verifyTypedData}
*
* @param parameters - {@link VerifyTypedDataParameters}
* @returns Whether or not the signature is valid. {@link VerifyTypedDataReturnType}
*/
export async function verifyTypedData<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
>(
parameters: VerifyTypedDataParameters<typedData, primaryType>,
): Promise<VerifyTypedDataReturnType> {
const { address, domain, message, primaryType, signature, types } =
parameters as unknown as VerifyTypedDataParameters
return isAddressEqual(
getAddress(address),
await recoverTypedDataAddress({
domain,
message,
primaryType,
signature,
types,
} as RecoverTypedDataAddressParameters),
)
}