/** * ledger.ts — Ledger hardware wallet signer for AirAccount M7. * * Produces an ECDSA (algId=0x02) UserOp signature using a Ledger device * connected via WebHID in the browser. * * Signature format (66 bytes): * [0x02][r(32)][s(32)][v(1)] * * The contract's _validateECDSA applies EIP-191 prefix, so Ledger's * signPersonalMessage (which also adds EIP-191 prefix) matches exactly. * * Requirements: * - Browser environment with WebHID support (Chrome/Edge 89+) * - @ledgerhq/hw-transport-webhid * - @ledgerhq/hw-app-eth */ interface LedgerSignerConfig { /** * BIP-44 derivation path. Defaults to the first Ethereum account. * Use Ledger Live's "m/44'/60'/0'/0/0" for the default account. */ derivationPath?: string; } /** Ledger signer instance returned by connectLedger(). */ interface LedgerSigner { /** * Returns the account address for the configured derivation path. * Use this to verify the Ledger matches the expected account owner. */ getAddress(): Promise; /** * Signs the UserOp hash and returns a 66-byte hex signature * formatted as [0x02][r(32)][s(32)][v(1)] for algId=0x02 (ECDSA). * * Compatible with the `signer` field of AirAccountProviderConfig. */ sign(userOpHash: `0x${string}`): Promise<`0x${string}`>; /** Disconnect and release the WebHID device. */ disconnect(): Promise; } /** * Connect to a Ledger device via WebHID and return a LedgerSigner. * * Must be called in response to a user gesture (button click, etc.) because * WebHID requestDevice() requires user activation. * * @example * ```ts * const signer = await connectLedger(); * const address = await signer.getAddress(); * const provider = new AirAccountEIP1193Provider({ * ..., * accountAddress: myAirAccountAddress, * signer: (hash) => signer.sign(hash), * }); * ``` */ declare function connectLedger(config?: LedgerSignerConfig): Promise; /** * yubikey.ts — YubiKey / FIDO2 hardware wallet signer for AirAccount M7. * * Uses navigator.credentials.get() (WebAuthn CTAP2) to produce a P256 * signature from a YubiKey or any FIDO2 security key that stores a P-256 * credential. * * Signature format (65 bytes): * [0x03][r(32)][s(32)] * * Compatible with AirAccount algId=0x03 (P256) when the account has been * initialized with the matching P256 public key via setP256Key(x, y). * * ⚠ WebAuthn authentication note: * Standard WebAuthn signs `authData || SHA256(clientDataJSON)`, not the * raw userOpHash. The P256 signature is VALID for the WebAuthn assertion * but NOT directly verifiable by the contract's _validateP256() which * expects a signature directly over `userOpHash`. * * Use cases: * 1. Tier 2/3 composite signatures (server-verifies WebAuthn assertion). * 2. Standalone algId=0x03: requires EIP-7212 raw P256 signing, which is * NOT standard WebAuthn. For this use case, pair with a server that * relays the FIDO2 assertion and verifies it off-chain, or use a * purpose-built Ethereum app on the YubiKey (e.g. Keystone firmware). * * Requirements: * - Browser environment with WebAuthn support * - YubiKey or FIDO2 device with a P-256 credential registered */ interface YubiKeySigner { /** * Trigger a WebAuthn assertion and return the raw P256 signature bytes * formatted as [0x03][r(32)][s(32)] for AirAccount algId=0x03. * * The `challenge` is set to the userOpHash bytes so the assertion is * cryptographically bound to this specific UserOp. * * Compatible with the `signer` field of AirAccountProviderConfig (for * Tier 2/3 flows where the server validates the WebAuthn assertion). */ sign(userOpHash: `0x${string}`): Promise<`0x${string}`>; } interface YubiKeySignerConfig { /** * The credential ID(s) of the registered YubiKey P256 credential. * If empty, any FIDO2 resident credential is allowed (discoverable mode). */ credentialIds?: Uint8Array[]; /** * Relying Party ID (rpId), typically the website's eTLD+1. * Defaults to window.location.hostname. */ rpId?: string; /** * Timeout for the WebAuthn request in milliseconds. Default: 60 000. */ timeout?: number; } /** * Create a YubiKey / FIDO2 P256 signer using WebAuthn. * * @example Tier 2/3 server-composite signing (server verifies the WebAuthn assertion) * ```ts * const signer = createYubiKeySigner({ * credentialIds: [base64UrlToBuffer(storedCredentialId)], * }); * // signer.sign() returns the raw WebAuthn P256 signature bytes. * // ⚠ This is NOT directly valid for standalone algId=0x03 on-chain verification * // because the contract expects a signature over userOpHash directly, but * // WebAuthn signs authData || SHA256(clientDataJSON) instead. * // For standalone algId=0x03 you need an EIP-7212-compatible Ethereum app on * // the security key (e.g. Keystone firmware), NOT standard WebAuthn CTAP2. * // * // Correct Tier 2/3 flow: * const webAuthnAssertion = await signer.sign(userOpHash); * // Send webAuthnAssertion to your Tier 2/3 server, which verifies the WebAuthn * // assertion off-chain and returns a composite signature for the UserOp. * ``` */ declare function createYubiKeySigner(config?: YubiKeySignerConfig): YubiKeySigner; export { type LedgerSigner, type LedgerSignerConfig, type YubiKeySigner, type YubiKeySignerConfig, connectLedger, createYubiKeySigner };