{"version":3,"file":"ledger-dmk-bridge.cjs","sourceRoot":"","sources":["../../src/dmk/ledger-dmk-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n  CloseAppCommand,\n  DeviceActionStatus,\n  DeviceManagementKitBuilder,\n  DeviceStatus,\n  GetAppAndVersionCommand,\n  isSuccessCommandResult,\n  OpenAppCommand,\n} from '@ledgerhq/device-management-kit';\nimport type {\n  DeviceActionState,\n  DeviceManagementKit,\n} from '@ledgerhq/device-management-kit';\nimport type { Signature } from '@ledgerhq/device-signer-kit-ethereum';\nimport type Transport from '@ledgerhq/hw-transport';\nimport type { Observable } from 'rxjs';\nimport {\n  concat,\n  defer,\n  firstValueFrom,\n  of,\n  Subject,\n  Subscription,\n  timer,\n} from 'rxjs';\nimport {\n  catchError,\n  distinctUntilChanged,\n  endWith,\n  filter,\n  map,\n  switchMap,\n} from 'rxjs/operators';\n\nimport {\n  AppConfigurationResponse,\n  GetAppNameAndVersionResponse,\n  GetPublicKeyParams,\n  GetPublicKeyResponse,\n  LedgerBridge,\n  LedgerSignDelegationAuthorizationParams,\n  LedgerSignDelegationAuthorizationResponse,\n  LedgerSignMessageParams,\n  LedgerSignMessageResponse,\n  LedgerSignTransactionParams,\n  LedgerSignTransactionResponse,\n  LedgerSignTypedDataParams,\n  LedgerSignTypedDataResponse,\n} from '../ledger-bridge';\nimport {\n  isDeviceExchangeError,\n  translateDmkError,\n} from './dmk-error-translator';\nimport { EthGetAppConfigurationCommand } from './eth-get-app-configuration-command';\nimport {\n  hexToBytes,\n  stripHexPrefix,\n  stripPathPrefix,\n  toHexString,\n} from './internal-utils';\nimport { LedgerDmkTransportMiddleware } from './ledger-dmk-transport-middleware';\n\nexport type LedgerDmkBridgeOptions = {\n  transportFactory: Parameters<DeviceManagementKitBuilder['addTransport']>[0];\n};\n\ntype PublicKeyOutput = Pick<\n  GetPublicKeyResponse,\n  'address' | 'chainCode' | 'publicKey'\n>;\n\n/**\n * LedgerDmkBridge is a bridge between the LedgerKeyring and the\n * LedgerDmkTransportMiddleware.\n * It initializes and manages the DeviceManagementKit internally.\n * The transport factory is injected via constructor, making it platform-agnostic.\n */\nexport class LedgerDmkBridge implements LedgerBridge<LedgerDmkBridgeOptions> {\n  readonly #transportMiddleware: LedgerDmkTransportMiddleware;\n\n  readonly #sdk: DeviceManagementKit;\n\n  #opts: LedgerDmkBridgeOptions;\n\n  #isConnected = false;\n\n  #sessionState$ = new Subject<{ connected: boolean }>();\n\n  get onSessionStateChange(): Observable<{ connected: boolean }> {\n    return this.#sessionState$.asObservable();\n  }\n\n  #sessionSubscription: Subscription | null = null;\n\n  get isDeviceConnected(): boolean {\n    return this.#isConnected;\n  }\n\n  constructor(opts: LedgerDmkBridgeOptions) {\n    this.#sdk = new DeviceManagementKitBuilder()\n      .addTransport(opts.transportFactory)\n      .build();\n    this.#opts = opts;\n    this.#transportMiddleware = new LedgerDmkTransportMiddleware(this.#sdk);\n  }\n\n  /**\n   * Compatibility shim for the shared {@link LedgerBridge} interface.\n   *\n   * DMK session setup happens externally via `updateSessionId` or `connect`,\n   * so this method is a no-op.\n   *\n   * @returns A promise that resolves immediately.\n   */\n  async init(): Promise<void> {\n    return undefined;\n  }\n\n  /**\n   * Destroys the bridge and cleans up resources.\n   *\n   * Unsubscribes session monitoring, disposes the transport middleware, and\n   * completes the session-state subject so all subscribers are released. A\n   * fresh subject is installed afterward so the bridge can be reconnected\n   * after destroy. State cleanup happens in a `finally` block so the bridge\n   * is marked disconnected even when middleware `dispose()` rejects.\n   *\n   * @returns A promise that resolves when cleanup is complete.\n   */\n  async destroy(): Promise<void> {\n    this.#sessionSubscription?.unsubscribe();\n    this.#sessionSubscription = null;\n\n    try {\n      await this.#transportMiddleware.dispose();\n    } finally {\n      this.#isConnected = false;\n      this.#sessionState$.next({ connected: false });\n      this.#sessionState$.complete();\n      this.#sessionState$ = new Subject<{ connected: boolean }>();\n    }\n  }\n\n  /**\n   * Returns the bridge options captured at construction.\n   *\n   * Compatibility shim for the shared {@link LedgerBridge} interface. The DMK\n   * bridge does not use runtime-reconfigurable options; this method exists\n   * only to satisfy the interface contract.\n   *\n   * @returns A promise that resolves with the current bridge options.\n   */\n  async getOptions(): Promise<LedgerDmkBridgeOptions> {\n    return this.#opts;\n  }\n\n  /**\n   * Replaces the stored bridge options.\n   *\n   * Compatibility shim for the shared {@link LedgerBridge} interface. Stored\n   * options are not re-applied to the underlying DMK instance or transport\n   * middleware; the values used at construction time remain in effect.\n   *\n   * @param opts - The options to set for the bridge.\n   * @returns A promise that resolves when options are set.\n   */\n  async setOptions(opts: LedgerDmkBridgeOptions): Promise<void> {\n    this.#opts = opts;\n  }\n\n  /**\n   * Updates the session ID used for communication.\n   *\n   * @param sessionId - The session ID from DMK.\n   * @returns A promise that resolves with true if the session was updated successfully.\n   */\n  async updateSessionId(sessionId: string): Promise<boolean> {\n    await this.#transportMiddleware.setSessionId(sessionId);\n    this.#isConnected = true;\n    this.#startSessionMonitoring(sessionId);\n    return true;\n  }\n\n  /**\n   * Starts device discovery for the configured DMK transport.\n   *\n   * @param args - Optional DMK discovery options.\n   * @returns An observable that emits discovered devices.\n   */\n  startDiscovering(\n    ...args: Parameters<LedgerDmkTransportMiddleware['startDiscovering']>\n  ): ReturnType<LedgerDmkTransportMiddleware['startDiscovering']> {\n    return this.#transportMiddleware.startDiscovering(...args);\n  }\n\n  /**\n   * Connects to a discovered device using the configured DMK transport.\n   *\n   * @param args - The DMK connection arguments.\n   * @returns The created session ID.\n   */\n  async connect(\n    ...args: Parameters<LedgerDmkTransportMiddleware['connect']>\n  ): ReturnType<LedgerDmkTransportMiddleware['connect']> {\n    const sessionId = await this.#transportMiddleware.connect(...args);\n    this.#isConnected = true;\n    this.#startSessionMonitoring(sessionId);\n\n    return sessionId;\n  }\n\n  /**\n   * Compatibility shim for the shared {@link LedgerBridge} interface.\n   *\n   * DMK transport selection happens through the injected transport factory\n   * at construction time, so this method is a no-op that always succeeds.\n   *\n   * @param _transportType - The requested transport type (ignored).\n   * @returns A promise that resolves with `true`.\n   */\n  async updateTransportMethod(\n    _transportType: string | Transport,\n  ): Promise<boolean> {\n    return true;\n  }\n\n  async openEthApp(): Promise<void> {\n    const sessionId = this.#transportMiddleware.getSessionId();\n    const result = await this.#sdk.sendCommand({\n      sessionId,\n      command: new OpenAppCommand({ appName: 'Ethereum' }),\n    });\n\n    if (!isSuccessCommandResult(result)) {\n      throw this.#toError(result.error);\n    }\n  }\n\n  async closeApps(): Promise<void> {\n    const sessionId = this.#transportMiddleware.getSessionId();\n    const result = await this.#sdk.sendCommand({\n      sessionId,\n      command: new CloseAppCommand(),\n    });\n\n    if (!isSuccessCommandResult(result)) {\n      throw this.#toError(result.error);\n    }\n  }\n\n  /**\n   * Compatibility shim for the shared {@link LedgerBridge} interface.\n   *\n   * The Ethereum signer kit automatically opens the Ethereum app before each\n   * signing operation via DMK's `CallTaskInAppDeviceAction`, so this method\n   * is a no-op that always succeeds.\n   *\n   * @returns A promise that resolves with `true`.\n   */\n  async attemptMakeApp(): Promise<boolean> {\n    return true;\n  }\n\n  /**\n   * Retrieves public key/address for a given HD path.\n   *\n   * @param options0 - The parameters object.\n   * @param options0.hdPath - The HD path to derive the public key from.\n   * @returns A promise that resolves with the public key response.\n   */\n  async getPublicKey({\n    hdPath,\n  }: GetPublicKeyParams): Promise<GetPublicKeyResponse> {\n    const { observable } = this.#transportMiddleware\n      .getEthSigner()\n      .getAddress(stripPathPrefix(hdPath), {\n        checkOnDevice: false,\n        returnChainCode: true,\n      });\n    const response =\n      await this.#waitForDeviceAction<PublicKeyOutput>(observable);\n\n    return {\n      publicKey: response.publicKey,\n      address: response.address,\n      chainCode: response.chainCode,\n    };\n  }\n\n  /**\n   * Signs an Ethereum transaction.\n   *\n   * @param options0 - The parameters object.\n   * @param options0.tx - The transaction hex string to sign.\n   * @param options0.hdPath - The HD path for signing.\n   * @returns A promise that resolves with the transaction signature.\n   */\n  async deviceSignTransaction({\n    tx,\n    hdPath,\n  }: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse> {\n    const { observable } = this.#transportMiddleware\n      .getEthSigner()\n      .signTransaction(stripPathPrefix(hdPath), hexToBytes(tx));\n    const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n    return {\n      v: toHexString(signature.v),\n      r: stripHexPrefix(signature.r),\n      s: stripHexPrefix(signature.s),\n    };\n  }\n\n  /**\n   * Signs a personal message.\n   *\n   * @param options0 - The parameters object.\n   * @param options0.hdPath - The HD path for signing.\n   * @param options0.message - The message to sign.\n   * @returns A promise that resolves with the message signature.\n   */\n  async deviceSignMessage({\n    hdPath,\n    message,\n  }: LedgerSignMessageParams): Promise<LedgerSignMessageResponse> {\n    const { observable } = this.#transportMiddleware\n      .getEthSigner()\n      .signMessage(stripPathPrefix(hdPath), hexToBytes(message));\n    const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n    return {\n      v: signature.v,\n      r: stripHexPrefix(signature.r),\n      s: stripHexPrefix(signature.s),\n    };\n  }\n\n  /**\n   * Signs EIP-712 typed data.\n   *\n   * @param options0 - The parameters object.\n   * @param options0.hdPath - The HD path for signing.\n   * @param options0.message - The typed data message to sign.\n   * @returns A promise that resolves with the typed data signature.\n   */\n  async deviceSignTypedData({\n    hdPath,\n    message,\n  }: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse> {\n    const { observable } = this.#transportMiddleware\n      .getEthSigner()\n      .signTypedData(stripPathPrefix(hdPath), message);\n    const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n    return {\n      v: signature.v,\n      r: stripHexPrefix(signature.r),\n      s: stripHexPrefix(signature.s),\n    };\n  }\n\n  async deviceSignDelegationAuthorization({\n    hdPath,\n    chainId,\n    contractAddress,\n    nonce,\n  }: LedgerSignDelegationAuthorizationParams): Promise<LedgerSignDelegationAuthorizationResponse> {\n    const { observable } = this.#transportMiddleware\n      .getEthSigner()\n      .signDelegationAuthorization(\n        stripPathPrefix(hdPath),\n        chainId,\n        contractAddress,\n        nonce,\n      );\n    const signature = await this.#waitForDeviceAction<Signature>(observable);\n\n    return {\n      v: toHexString(signature.v),\n      r: stripHexPrefix(signature.r),\n      s: stripHexPrefix(signature.s),\n    };\n  }\n\n  /**\n   * Retrieves the current app name and version.\n   *\n   * @returns A promise that resolves with the app name and version.\n   */\n  async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n    const sessionId = this.#transportMiddleware.getSessionId();\n    const command = new GetAppAndVersionCommand();\n    const result = await this.#sdk.sendCommand({\n      sessionId,\n      command,\n    });\n\n    if (!isSuccessCommandResult(result)) {\n      throw this.#toError(result.error);\n    }\n\n    return {\n      appName: result.data.name,\n      version: result.data.version,\n    };\n  }\n\n  /**\n   * Retrieves the Ethereum app configuration using the eth-specific\n   * GetAppConfiguration APDU command (CLA 0xE0, INS 0x06).\n   *\n   * @returns A promise that resolves with the app configuration.\n   */\n  async getAppConfiguration(): Promise<AppConfigurationResponse> {\n    const sessionId = this.#transportMiddleware.getSessionId();\n    const command = new EthGetAppConfigurationCommand();\n    const result = await this.#sdk.sendCommand({\n      sessionId,\n      command,\n    });\n\n    if (!isSuccessCommandResult(result)) {\n      throw this.#toError(result.error);\n    }\n\n    const { data } = result;\n\n    // The `ethapp.adoc` spec for `getAppConfiguration`\n    // (https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc#get-app-configuration)\n    // defines four flag bits. This bridge only consumes three (blind signing,\n    // web3 checks enabled, web3 checks opt-in). The fourth — `0x02` *ERC 20\n    // Token information needs to be provided externally* — is intentionally\n    // mapped to `erc20ProvisioningNecessary: 0` because the rest of the\n    // keyring does not implement the `PROVIDE ERC 20 TOKEN INFORMATION`\n    // provisioning flow.\n    //\n    // TODO: The shared `AppConfigurationResponse` interface also requires\n    // `starkEnabled` and `starkv2Supported`, which are not exposed by the\n    // `getAppConfiguration` APDU at all. They are stubbed to 0 to satisfy\n    // the interface contract.\n    return {\n      arbitraryDataEnabled: data.blindSigningEnabled ? 1 : 0,\n      erc20ProvisioningNecessary: 0,\n      starkEnabled: 0,\n      starkv2Supported: 0,\n      version: data.version,\n    };\n  }\n\n  async #waitForDeviceAction<TOutput>(\n    observable: Observable<DeviceActionState<TOutput, unknown, unknown>>,\n  ): Promise<TOutput> {\n    const state = await firstValueFrom(\n      observable.pipe(\n        catchError((error: unknown) => {\n          throw translateDmkError(error);\n        }),\n        filter(\n          ({ status }) =>\n            status === DeviceActionStatus.Completed ||\n            status === DeviceActionStatus.Error,\n        ),\n      ),\n    );\n\n    if (state.status === DeviceActionStatus.Completed) {\n      return state.output;\n    }\n\n    if (state.status === DeviceActionStatus.Error) {\n      throw translateDmkError(state.error);\n    }\n\n    // Unreachable: the filter above only lets Completed or Error states\n    // through. Defensive guard retained for type safety.\n    throw new Error('Ledger device action ended without completion.');\n  }\n\n  #toError(error: unknown): Error {\n    if (isDeviceExchangeError(error)) {\n      return translateDmkError(error);\n    }\n\n    if (error instanceof Error) {\n      return error;\n    }\n\n    return new Error('Ledger command failed.');\n  }\n\n  /**\n   * Monitors the DMK session connection state with exponential backoff retries.\n   *\n   * This is necessary because the DMK does not emit disconnection events on its\n   * own — the bridge must actively poll the session state to detect when a\n   * Ledger device is unplugged, the Bluetooth/WUSB link drops, or the session\n   * is invalidated. Without this monitoring the keyring would retain a stale\n   * `isDeviceConnected = true` and subsequent signing requests would hang or\n   * fail with cryptic transport errors.\n   *\n   * Subscribes to the device session state and emits connection changes through\n   * {@link #sessionState$}. On error, retries up to 10 times with exponential\n   * backoff (capped at 30 s) and emits a `connected: false` state in between\n   * attempts. Once the retry limit is exhausted the stream ends with a final\n   * `connected: false`. Duplicate consecutive states are suppressed via\n   * `distinctUntilChanged`.\n   *\n   * Any previous monitoring subscription is cancelled before a new one is created.\n   *\n   * @param sessionId - The DMK session ID to monitor.\n   */\n  #startSessionMonitoring(sessionId: string): void {\n    this.#sessionSubscription?.unsubscribe();\n\n    const MAX_BACKOFF_MS = 30_000;\n    const BASE_DELAY_MS = 1_000;\n    const MAX_RETRIES = 10;\n\n    const createMonitoringStream = (\n      retryCount = 0,\n    ): Observable<{ connected: boolean }> =>\n      this.#sdk.getDeviceSessionState({ sessionId }).pipe(\n        map((state) => ({\n          connected: state.deviceStatus !== DeviceStatus.NOT_CONNECTED,\n        })),\n        catchError(() => {\n          if (retryCount >= MAX_RETRIES) {\n            return of({ connected: false });\n          }\n          const delay = Math.min(\n            BASE_DELAY_MS * 2 ** retryCount,\n            MAX_BACKOFF_MS,\n          );\n          return concat(\n            of({ connected: false }),\n            defer(() =>\n              timer(delay).pipe(\n                switchMap(() => createMonitoringStream(retryCount + 1)),\n              ),\n            ),\n          );\n        }),\n        endWith({ connected: false } as { connected: boolean }),\n      );\n\n    this.#sessionSubscription = createMonitoringStream()\n      .pipe(\n        distinctUntilChanged(\n          (a: { connected: boolean }, b: { connected: boolean }) =>\n            a.connected === b.connected,\n        ),\n      )\n      .subscribe((state) => {\n        this.#isConnected = state.connected;\n        this.#sessionState$.next(state);\n      });\n  }\n}\n"]}