import type { ExtensionInjectedProvider, IntegratedBrowserInjectedProvider } from './UWC-state' /** * EIP-712 typed structured data for eth_signTypedData_v4. * Used by ERC-3009 (Transfer With Authorization), EIP-2612 (Permit), and similar standards. */ export interface EIP712TypedData { domain: { name?: string version?: string chainId?: number verifyingContract?: string salt?: string } types: Record> primaryType: string message: Record } /** * Ensures the EIP712Domain type entry is present in `types`, derived from the * fields actually set on `domain`, in EIP-712's canonical order. * * Why: some wallets (notably Trust Wallet and several mobile wallets over * WalletConnect) parse the `types` object strictly and reject an * eth_signTypedData_v4 request that omits EIP712Domain. Desktop MetaMask derives * it implicitly, so callers tend to leave it out — this normalizes both. * * If the caller already supplied EIP712Domain, theirs is authoritative and the * input is returned untouched. Otherwise a new object is returned (input is not * mutated) with EIP712Domain inserted first. * * @see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator */ export function withEIP712Domain(typedData: EIP712TypedData): EIP712TypedData { if (Object.hasOwn(typedData.types, 'EIP712Domain')) return typedData const { domain } = typedData const domainFields: Array<{ name: string; type: string }> = [] // Canonical field order — the on-chain domainSeparator hash depends on it. if (domain.name !== undefined) domainFields.push({ name: 'name', type: 'string' }) if (domain.version !== undefined) domainFields.push({ name: 'version', type: 'string' }) if (domain.chainId !== undefined) domainFields.push({ name: 'chainId', type: 'uint256' }) if (domain.verifyingContract !== undefined) domainFields.push({ name: 'verifyingContract', type: 'address' }) if (domain.salt !== undefined) domainFields.push({ name: 'salt', type: 'bytes32' }) return { ...typedData, types: { EIP712Domain: domainFields, ...typedData.types } } } /** * Standard signature format for most blockchains (EVM, Solana, etc.) */ export interface StandardSignature { type: 'standard' signature: string } /** * Tron-specific signature format */ export interface TronSignature { type: 'tron' signature: string[] txID: string } /** * The three payload types supported by TON Connect's signData method. */ export type TonSignDataPayload = | { type: 'text'; text: string } | { type: 'cell'; schema: string; cell: string } | { type: 'binary'; bytes: string } /** * TON-specific signature format returned by TON Connect signData. * * @remarks Consumers MUST verify that `domain` matches their expected domain * and that `timestamp` is within an acceptable window to prevent replay attacks. */ export interface TonSignature { type: 'tvm' signature: string timestamp: number domain: string payload: TonSignDataPayload } /** * Discriminated union type for all signature formats */ export type SignatureType = StandardSignature | TronSignature | TonSignature /** * Result interface for signature operations */ export interface SignatureResult { signature: SignatureType address: string } /** * Error types for signature operations */ export interface SignatureError { code: number message: string } /** * Signature service interface */ export interface SignatureService { /** * Sign a message with the connected wallet * @param message The message to sign * @param provider The wallet provider to use for signing * @returns A promise that resolves to the signature result */ signMessage( message: string, provider: ExtensionInjectedProvider | IntegratedBrowserInjectedProvider ): Promise }