@onekeyfe/hwk-trezor-adapter 1.2.3-alpha.8 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-trezor-adapter/dist/index.js","../src/adapter/TrezorAdapter.ts","../src/deviceAuthenticity/index.ts","../src/deviceAuthenticity/config.ts","../src/deviceAuthenticity/findSubjectContentByOid.ts","../src/deviceAuthenticity/validateCaCertExtensions.ts","../src/deviceAuthenticity/verifySignatures.ts","../src/deviceAuthenticity/x509certificate.ts","../src/deviceAuthenticity/verifyAuthenticityProof.ts","../src/utils/sdkEventBus.ts","../src/utils/debugLog.ts","../src/utils/queueKey.ts","../src/utils/ethereumDefinitions.ts","../src/utils/solanaTokenDefinition.ts","../src/constants.ts","../src/utils/bleIdentity.ts"],"names":[],"mappings":"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","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-trezor-adapter/dist/index.js","sourcesContent":[null,"import {\n DEVICE,\n DeviceJobQueue,\n HardwareErrorCode,\n OperationRegistry,\n SDK,\n TypedEventEmitter,\n UI_REQUEST,\n UI_RESPONSE,\n UiRequestRegistry,\n canReplayHardwareMethodAfterTransportFailure,\n createHwkError,\n defaultOriginForCode,\n failure,\n isConnectionLost,\n isHardwareOperationId,\n isHwkRecoveryHint,\n isUserRefusal,\n operationMayHaveCompletedParams,\n rehydrateConnectorError,\n requestBleDeviceSelection,\n requestSaveDeviceBinding,\n resolveHardwareOperationTarget,\n resolveSearchTargetReusePolicy,\n runAllNetworkGetAddress,\n success,\n} from '@onekeyfe/hwk-adapter-core';\nimport { randomBytes } from '@noble/hashes/utils';\n\nimport { authenticateDeviceFromProof } from '../deviceAuthenticity';\nimport { debugLog } from '../utils/debugLog';\nimport { trezorQueueKey } from '../utils/queueKey';\n\nimport type { AuthenticityProof } from '../deviceAuthenticity';\nimport type {\n AllNetworkAddressParams,\n AllNetworkAddressResponse,\n AllNetworkGetAddressParams,\n AllNetworkMethodName,\n BindBleDeviceParams,\n BtcAddress,\n BtcGetAddressParams,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignMsgParams,\n BtcSignPsbtParams,\n BtcSignTxParams,\n BtcSignature,\n BtcSignedPsbt,\n BtcSignedTx,\n ChainForFingerprint,\n ConnectionTarget,\n ConnectionType,\n ConnectorCallResult,\n ConnectorDevice,\n ConnectorUiEvent,\n DeviceAuthenticityParams,\n DeviceAuthenticityResult,\n DeviceEventListener,\n DeviceInfo,\n DeviceSearchTarget,\n EvmAddress,\n EvmGetAddressParams,\n EvmSignMsgParams,\n EvmSignTxTrezorParams,\n EvmSignTypedDataParams,\n EvmSignature,\n EvmSignedTx,\n HardwareEvent,\n HardwareEventMap,\n IBtcMethods,\n ICommonCallParams,\n IConnector,\n IDeviceManagerMethods,\n IDeviceManagerOperationContext,\n IEvmMethods,\n IHardwareConnectionContext,\n IHardwareWallet,\n ISolMethods,\n ITronMethods,\n Response,\n SearchDevicesOptions,\n SolAddress,\n SolGetAddressParams,\n SolSignMsgParams,\n SolSignTxParams,\n SolSignature,\n SolSignedTx,\n TransportType,\n TrezorBrightnessParams,\n TrezorChangePinParams,\n TrezorDeviceSettingsParams,\n TronAddress,\n TronGetAddressParams,\n TronSignMsgParams,\n TronSignTxParams,\n TronSignature,\n TronSignedTx,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\n\n// Valid HardwareErrorCode numbers. Used to reject foreign numeric `code`s (e.g.\n// a DOMException's `code: 20` on a WebUSB AbortError) that must NOT be trusted\n// as HardwareErrorCodes — otherwise they leak through as Unknown.\nconst KNOWN_HARDWARE_ERROR_CODES = new Set<number>(\n Object.values(HardwareErrorCode).filter((value): value is number => typeof value === 'number')\n);\n\ntype NullableCallArg<T> = T | null | undefined;\n\ntype TrezorPassphraseCallParams = {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n};\n\ntype TrezorPassphraseRequestContext = {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n};\n\ntype TrezorVerifiedPassphraseSession = {\n sessionId: string;\n protocol: 'thp' | 'v1';\n thpSessionId?: string;\n};\n\ntype TrezorCallParams<T> = (T & ICommonCallParams & TrezorPassphraseCallParams) | null | undefined;\n\ntype TrezorCommonParams = (ICommonCallParams & TrezorPassphraseCallParams) | null | undefined;\n\ntype AsyncMethodName<T> = Extract<\n {\n [K in keyof T]-?: NonNullable<T[K]> extends (\n ...args: infer _Args\n ) => Promise<Response<infer _Payload>>\n ? K\n : never;\n }[keyof T],\n string\n>;\n\ntype TrezorWalletMethods = IEvmMethods & IBtcMethods & ISolMethods & ITronMethods;\n\ntype TrezorWalletMethodName = AsyncMethodName<TrezorWalletMethods>;\n\ntype TrezorDeviceManagerMethodName = AsyncMethodName<IDeviceManagerMethods>;\n\ntype TrezorMethodName = TrezorWalletMethodName | TrezorDeviceManagerMethodName;\n\ntype TrezorBundleContext = {\n connection?: { connectId: string; sessionId: string };\n};\n\nconst TREZOR_BTC_NETWORK_COIN_MAP: Partial<Record<string, string>> = {\n btc: 'Bitcoin',\n bitcoin: 'Bitcoin',\n tbtc: 'Testnet',\n testnet: 'Testnet',\n sbtc: 'Signet',\n signet: 'Signet',\n ltc: 'Litecoin',\n litecoin: 'Litecoin',\n doge: 'Dogecoin',\n dogecoin: 'Dogecoin',\n bch: 'Bcash',\n bcash: 'Bcash',\n dash: 'Dash',\n};\n\nexport interface TrezorKnownDeviceConnection {\n deviceId: string;\n usbConnectId?: string;\n bleConnectId?: string;\n}\n\nexport interface TrezorAdapterOptions {\n /** Persisted endpoints are routing hints, never proof of device identity. */\n knownDeviceConnections?: readonly TrezorKnownDeviceConnection[];\n}\n\nexport class TrezorAdapter implements IHardwareWallet {\n readonly vendor = 'trezor' as const;\n\n // The connector has no protocol-level cancel: the adapter stops waiting and\n // drops the late response, the device carries on.\n readonly cancelCapability = 'stops-waiting' as const;\n\n private readonly _connector: IConnector;\n\n private readonly _emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private readonly _operations = new OperationRegistry({\n vendor: 'trezor',\n onEnded: (operation, reason) => {\n this._emitter.emit(SDK.OPERATION_ENDED, {\n type: SDK.OPERATION_ENDED,\n payload: { operationId: operation.operationId, reason },\n });\n if (reason === 'timeout') {\n void this._releaseOperationConnection(operation).catch(() => undefined);\n }\n },\n });\n\n private readonly _devices = new Map<string, DeviceInfo>();\n\n private readonly _sessions = new Map<string, string>();\n\n private readonly _connectingPromises = new Map<string, Promise<string>>();\n\n // connectIds disconnected mid-connect; the session they produce is torn down, not cached.\n private readonly _disconnectRequested = new Set<string>();\n\n private readonly _uiRegistry = new UiRequestRegistry();\n\n private readonly _passphraseRequestContextByConnectId = new Map<\n string,\n TrezorPassphraseRequestContext\n >();\n\n private readonly _verifiedPassphraseSessionsByConnectId = new Map<\n string,\n Map<string, TrezorVerifiedPassphraseSession>\n >();\n\n /** Raw connector calls that outlive an aborted caller, keyed by session. */\n private readonly _unsettledConnectorOperations = new Map<string, number>();\n\n private readonly _connectorIdleWaiters = new Set<() => void>();\n\n private _resetPromise: Promise<void> | null = null;\n\n private _connectorTeardownTail: Promise<void> = Promise.resolve();\n\n private _pendingConnectorTeardowns = 0;\n\n private _stateGeneration = 0;\n\n // Per-device queue with preemption + AbortSignal. Same-device chain calls\n // serialize (Trezor's protocol is single-request-response — interleaving\n // desyncs THP nonce). 'safe' read methods auto-cancel each other; 'confirm'\n // sign methods emit REQUEST_PREEMPTION so the consumer can decide.\n private readonly _jobQueue: DeviceJobQueue;\n\n private readonly _knownDeviceConnections = new Map<string, TrezorKnownDeviceConnection>();\n\n constructor(connector: IConnector, options?: TrezorAdapterOptions) {\n this._connector = connector;\n for (const connection of options?.knownDeviceConnections ?? []) {\n if (connection.deviceId) {\n this._knownDeviceConnections.set(connection.deviceId, { ...connection });\n }\n }\n // Upstream DeviceJobQueue is now a global FIFO with no built-in\n // preemption — interruptibility lives at the application layer.\n this._jobQueue = new DeviceJobQueue();\n this._registerConnectorEvents();\n }\n\n private static _createDeviceBusyError(method: string): Error {\n // Our own queued request blocks this one → DeviceBusyInternal, not \"another app\".\n return Object.assign(new Error(`Trezor is busy with another request (${method})`), {\n code: HardwareErrorCode.DeviceBusyInternal,\n });\n }\n\n /**\n * Split a Trezor-only `passphraseState` routing hint off the chain params so\n * it never reaches the protobuf layer. The connector/firmware only sees the\n * real op fields; the adapter uses `passphraseState` to align the session.\n */\n private static _normalizeCallArgs(\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>\n ): {\n connectId: string;\n params: unknown;\n } {\n return {\n connectId: connectId || deviceId || '',\n params: params ?? {},\n };\n }\n\n private static _splitCommonParams(params: unknown): {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n operationId?: string;\n connectionContext?: IHardwareConnectionContext;\n rest: unknown;\n } {\n if (params && typeof params === 'object') {\n const {\n passphraseState,\n autoInstallApp: _autoInstallApp,\n operationId,\n useEmptyPassphrase,\n knownConnections,\n extra,\n allowDeviceSelection,\n ...rest\n } = params as Record<string, unknown>;\n return {\n passphraseState: typeof passphraseState === 'string' ? passphraseState : undefined,\n useEmptyPassphrase:\n typeof useEmptyPassphrase === 'boolean' ? useEmptyPassphrase : undefined,\n operationId: typeof operationId === 'string' ? operationId : undefined,\n connectionContext: {\n knownConnections: knownConnections as IHardwareConnectionContext['knownConnections'],\n extra: extra as IHardwareConnectionContext['extra'],\n allowDeviceSelection:\n typeof allowDeviceSelection === 'boolean' ? allowDeviceSelection : undefined,\n },\n rest,\n };\n }\n return { rest: params ?? {} };\n }\n\n private static _withAllNetworkRequestCommonParams(\n item: AllNetworkAddressParams,\n commonParams: TrezorCommonParams\n ): AllNetworkAddressParams {\n const autoInstallApp = commonParams?.autoInstallApp;\n const passphraseState = commonParams?.passphraseState;\n const useEmptyPassphrase = commonParams?.useEmptyPassphrase;\n const operationId = commonParams?.operationId;\n const knownConnections = commonParams?.knownConnections;\n const extra = commonParams?.extra;\n const allowDeviceSelection = commonParams?.allowDeviceSelection;\n if (\n autoInstallApp === undefined &&\n passphraseState === undefined &&\n useEmptyPassphrase === undefined &&\n operationId === undefined &&\n knownConnections === undefined &&\n extra === undefined &&\n allowDeviceSelection === undefined\n ) {\n return item;\n }\n return {\n ...item,\n ...(autoInstallApp !== undefined ? { autoInstallApp } : {}),\n ...(passphraseState !== undefined ? { passphraseState } : {}),\n ...(useEmptyPassphrase !== undefined ? { useEmptyPassphrase } : {}),\n ...(operationId !== undefined ? { operationId } : {}),\n ...(knownConnections !== undefined ? { knownConnections } : {}),\n ...(extra !== undefined ? { extra } : {}),\n ...(allowDeviceSelection !== undefined ? { allowDeviceSelection } : {}),\n };\n }\n\n // Keys are matched after normalizeLogKey, so snake_case/camelCase both hit.\n private static readonly _sensitiveLogKeys = new Set([\n 'extra',\n 'knownconnections',\n 'credential',\n 'credentials',\n 'entropy',\n 'hoststatickey',\n 'mnemonic',\n 'mnemonics',\n 'passphrase',\n 'passphrasestate',\n 'password',\n 'pin',\n 'privatekey',\n 'seed',\n 'session',\n 'sessionid',\n 'trezorstaticpublickey',\n 'word',\n 'words',\n 'xprv',\n ]);\n\n private static _normalizeLogKey(key: string): string {\n return key.replace(/[_-]/g, '').toLowerCase();\n }\n\n // Mirrors hd-core's logBlockEvent: a signing method's body is the user's\n // transaction, so it is dropped wholesale; other methods redact by key.\n private static _sanitizeForLog(value: unknown, methodName?: string): unknown {\n if (methodName && /sign/i.test(methodName)) return '[redacted]';\n return TrezorAdapter._redactForLog(value, new WeakSet());\n }\n\n private static _redactForLog(value: unknown, seen: WeakSet<object>): unknown {\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n return `[BINARY:${value.byteLength}]`;\n }\n if (!value || typeof value !== 'object') return value;\n if (seen.has(value)) return '[CIRCULAR]';\n seen.add(value);\n const out = Array.isArray(value)\n ? value.map(item => TrezorAdapter._redactForLog(item, seen))\n : Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n TrezorAdapter._sensitiveLogKeys.has(TrezorAdapter._normalizeLogKey(key)) &&\n item !== null &&\n item !== undefined\n ? '[redacted]'\n : TrezorAdapter._redactForLog(item, seen),\n ])\n );\n seen.delete(value);\n return out;\n }\n\n private static _errorForLog(error: unknown): unknown {\n if (!error || typeof error !== 'object') return error;\n const typed = error as {\n code?: unknown;\n errorCode?: unknown;\n message?: unknown;\n name?: unknown;\n response?: unknown;\n statusCode?: unknown;\n };\n return TrezorAdapter._sanitizeForLog({\n name: typed.name,\n message: typed.message,\n code: typed.code,\n errorCode: typed.errorCode,\n statusCode: typed.statusCode,\n response: typed.response,\n });\n }\n\n private _setPassphraseRequestContext(\n connectId: string,\n context: TrezorPassphraseRequestContext\n ): () => void {\n const previous = this._passphraseRequestContextByConnectId.get(connectId);\n if (context.passphraseState !== undefined || context.useEmptyPassphrase !== undefined) {\n this._passphraseRequestContextByConnectId.set(connectId, context);\n } else {\n this._passphraseRequestContextByConnectId.delete(connectId);\n }\n return () => {\n if (previous) {\n this._passphraseRequestContextByConnectId.set(connectId, previous);\n } else {\n this._passphraseRequestContextByConnectId.delete(connectId);\n }\n };\n }\n\n private static _trezorFailureMessage(error: unknown): {\n code?: unknown;\n message?: unknown;\n } {\n const response = (error as { response?: unknown } | null | undefined)?.response;\n const message = (response as { message?: unknown } | null | undefined)?.message;\n if (!message || typeof message !== 'object') return {};\n const failureMessage = message as { code?: unknown; message?: unknown };\n return {\n code: failureMessage.code,\n message: failureMessage.message,\n };\n }\n\n private static _mapTrezorFailureCode(error: unknown): HardwareErrorCode | undefined {\n const directCode = (error as { code?: unknown } | null | undefined)?.code;\n if (directCode === 'Device_InitializeFailed') {\n return HardwareErrorCode.PinCancelled;\n }\n if (directCode === 'Failure_ActionCancelled') {\n return HardwareErrorCode.UserRejected;\n }\n if (directCode === 'ThpPairingRequired') {\n return HardwareErrorCode.ThpPairingRequired;\n }\n if (directCode === 'Failure_UnexpectedMessage') {\n return HardwareErrorCode.MethodNotSupported;\n }\n const message = (error as { message?: unknown } | null | undefined)?.message;\n if (\n typeof message === 'string' &&\n message.includes(\"Failed to execute 'transfer\") &&\n message.includes(\"on 'USBDevice'\")\n ) {\n return HardwareErrorCode.TransportError;\n }\n const failure = TrezorAdapter._trezorFailureMessage(error);\n if (failure.code === 'Failure_PinCancelled') {\n return HardwareErrorCode.PinCancelled;\n }\n if (failure.code === 'Failure_PinInvalid') {\n return HardwareErrorCode.PinInvalid;\n }\n if (failure.code === 'Failure_PinMismatch') {\n return HardwareErrorCode.PinMismatch;\n }\n if (failure.code === 'Failure_ActionCancelled') {\n return HardwareErrorCode.UserRejected;\n }\n if (failure.code === 'Failure_ProcessError' && failure.message === 'Unsupported script type') {\n return HardwareErrorCode.MethodNotSupported;\n }\n // Device rejected the derivation path (e.g. an index outside its allowed\n // range) — distinct path-specific surface, not a generic \"method\" error.\n if (failure.code === 'Failure_DataError' && failure.message === 'Forbidden key path') {\n return HardwareErrorCode.DevicePathForbidden;\n }\n // Match the stable setting name instead of the full firmware message.\n if (\n failure.code === 'Failure_DataError' &&\n typeof failure.message === 'string' &&\n failure.message.includes('PASSPHRASE_ALWAYS_ON_DEVICE')\n ) {\n return HardwareErrorCode.PassphraseAlwaysOnDevice;\n }\n // Firmware can't process this request (e.g. EIP-712 typed data the device\n // firmware doesn't support) → surface as \"method not supported\".\n if (failure.code === 'Failure_FirmwareError') {\n return HardwareErrorCode.MethodNotSupported;\n }\n // Device firmware doesn't recognize the message (e.g. an older device asked\n // for a coin/app it lacks) → \"method not supported\", not a generic unknown.\n if (failure.code === 'Failure_UnexpectedMessage') {\n return HardwareErrorCode.MethodNotSupported;\n }\n if (failure.code === 'Failure_NotInitialized') {\n return HardwareErrorCode.DeviceNotInitialized;\n }\n // Device busy with its own op, not another app → DeviceBusyInternal.\n if (failure.code === 'Failure_Busy' || failure.code === 'Failure_InProgress') {\n return HardwareErrorCode.DeviceBusyInternal;\n }\n return undefined;\n }\n\n /**\n * Whether a device-side error code means the THP application session we\n * selected is gone (the device evicted it from its limited slot pool). The\n * caller drops the stale cache entry and recreates from scratch.\n *\n * Match only the protocol's explicit unallocated-channel code. Guessing from\n * an error message could replay a request after an unrelated business error.\n */\n private static _isStaleSessionError(code: unknown): boolean {\n return code === 'ThpUnallocatedChannel';\n }\n\n private static _errorCode(error: unknown): unknown {\n return (error as { code?: unknown }).code ?? TrezorAdapter._trezorFailureMessage(error).code;\n }\n\n private static _isConnectionUnavailableError(error: unknown): boolean {\n const { code } = error as { code?: unknown };\n return (\n code === HardwareErrorCode.DeviceNotFound || code === HardwareErrorCode.DeviceDisconnected\n );\n }\n\n private static _isRecoverableProtocolResidueError(error: unknown): boolean {\n const protocolError = error as {\n name?: unknown;\n code?: unknown;\n message?: unknown;\n };\n return (\n protocolError.name === 'TrezorProtocolError' &&\n protocolError.code === 'Malformed protocol format' &&\n protocolError.message === 'Malformed protocol format'\n );\n }\n\n /**\n * Race a promise against an abort signal. IConnector.call() can't actually\n * be cancelled at the protocol level, so the caller gets the abort while the\n * adapter keeps the transport exclusively reserved until the raw call drains.\n */\n private static _abortable<T>(signal: AbortSignal, promise: Promise<T>): Promise<T> {\n if (signal.aborted) {\n // The operation may already have started before its signal was checked.\n void promise.catch(() => undefined);\n return Promise.reject(\n (signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted')\n );\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n reject((signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n err => {\n signal.removeEventListener('abort', onAbort);\n reject(err);\n }\n );\n });\n }\n\n private async _connectSession(\n connectId: string,\n signal: AbortSignal | undefined,\n stateGeneration: number,\n transportType?: ConnectionType\n ): Promise<string> {\n const connectOnce = async () => {\n if (signal?.aborted) {\n throw (signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted');\n }\n this._assertConnectorIdle('connectDevice');\n const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);\n let connectPromise: ReturnType<IConnector['connect']>;\n try {\n connectPromise = transportType\n ? this._connector.connect(connectId, { transportType })\n : this._connector.connect(connectId);\n } catch (error) {\n releaseOperation();\n throw error;\n }\n if (!signal) {\n try {\n return await connectPromise;\n } finally {\n releaseOperation();\n }\n }\n try {\n const session = await TrezorAdapter._abortable(signal, connectPromise);\n releaseOperation();\n return session;\n } catch (error) {\n if (signal.aborted) {\n // The underlying connect cannot be cancelled. Keep the connector\n // reserved until its late session has been disconnected.\n void connectPromise\n .then(orphan => this._connector.disconnect(orphan.sessionId).catch(() => undefined))\n .catch(() => undefined)\n .finally(releaseOperation);\n } else {\n releaseOperation();\n }\n throw error;\n }\n };\n let session;\n try {\n session = await connectOnce();\n } catch (error) {\n if (signal?.aborted || !TrezorAdapter._isRecoverableProtocolResidueError(error)) {\n throw error;\n }\n // An interrupted THP handshake may leave exactly one v2 frame queued on\n // the shared USB pipe. The connector intentionally drains it as a loud\n // v1 malformed-frame failure; retry once now that the residue is gone.\n debugLog('[TrezorAdapter] retrying connect after draining a stale THP frame', {\n connectId,\n });\n session = await connectOnce();\n }\n // releaseOperation()/resetState() ran mid-connect: tear down the now-\n // unwanted session instead of caching it (else it leaks a limited THP slot\n // or lets stale state reappear after reset).\n if (stateGeneration !== this._stateGeneration || this._disconnectRequested.delete(connectId)) {\n const releaseCleanup = this._retainConnectorOperation(`disconnect:${session.sessionId}`);\n try {\n await this._connector.disconnect(session.sessionId).catch(() => undefined);\n } finally {\n releaseCleanup();\n }\n throw Object.assign(new Error('Trezor connection aborted'), {\n code: HardwareErrorCode.UserAborted,\n });\n }\n this._sessions.set(connectId, session.sessionId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n this._devices.set(connectId, session.deviceInfo);\n return session.sessionId;\n }\n\n get activeTransport(): TransportType | null {\n return this._connector.connectionType;\n }\n\n async init(_config?: unknown): Promise<void> {}\n\n async dispose(): Promise<void> {\n await this._resetStateAndDisconnectSessions();\n this._unregisterConnectorEvents();\n this._connector.reset();\n this._emitter.removeAllListeners();\n }\n\n /**\n * Clear cached state without tearing down the adapter or unregistering\n * listeners. Mirrors LedgerAdapter.resetState() — useful for retry-after-\n * error flows. Aborts active jobs and releases UI waits.\n */\n resetState(): void {\n void this._resetStateAndDisconnectSessions();\n }\n\n private _resetStateAndDisconnectSessions(): Promise<void> {\n if (this._resetPromise) return this._resetPromise;\n\n const sessionIds = new Set(this._sessions.values());\n this._stateGeneration += 1;\n this._operations.endAll('runtime-reset');\n this._uiRegistry.reset();\n this._jobQueue.clear();\n this._devices.clear();\n this._sessions.clear();\n this._verifiedPassphraseSessionsByConnectId.clear();\n this._connectingPromises.clear();\n\n const resetPromise = this._runConnectorTeardown(async () => {\n for (const sessionId of sessionIds) {\n await this._connector.disconnect(sessionId).catch(() => undefined);\n }\n });\n this._resetPromise = resetPromise;\n return resetPromise.finally(() => {\n if (this._resetPromise === resetPromise) {\n this._resetPromise = null;\n }\n });\n }\n\n getAvailableTransports(): TransportType[] {\n return this.activeTransport ? [this.activeTransport] : [];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {}\n\n async searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]> {\n return this._searchDevices(options);\n }\n\n private async _searchDevices(\n options?: SearchDevicesOptions,\n signal?: AbortSignal\n ): Promise<DeviceInfo[]> {\n if (\n options?.transportType &&\n !(this._connector.availableTransports ?? [this._connector.connectionType]).includes(\n options.transportType\n )\n )\n return [];\n if (options?.resetSession) {\n await this._resetStateAndDisconnectSessions();\n } else {\n await this._connectorTeardownTail;\n }\n if (signal?.aborted) throw signal.reason;\n const stateGeneration = this._stateGeneration;\n const scanned = await this._connector.searchDevices(\n options?.waitForAllTransports || options?.transportType\n ? {\n ...(options.waitForAllTransports ? { waitForAll: true } : {}),\n ...(options.transportType ? { transportType: options.transportType } : {}),\n }\n : undefined\n );\n if (signal?.aborted) throw signal.reason;\n if (stateGeneration !== this._stateGeneration) {\n throw createHwkError({\n code: HardwareErrorCode.UserAborted,\n message: 'Trezor discovery belongs to an ended operation',\n });\n }\n const scannedIds = new Set(scanned.map(d => d.connectId));\n // A rescan that misses a currently-connected device shouldn't evict it —\n // otherwise getDeviceInfo would return DeviceNotFound for an active session.\n for (const connectId of [...this._devices.keys()]) {\n if (\n (!options?.transportType ||\n this._devices.get(connectId)?.connectionType === options.transportType) &&\n !scannedIds.has(connectId) &&\n !this._sessions.has(connectId)\n ) {\n this._devices.delete(connectId);\n }\n }\n for (const device of scanned) {\n const info = this._connectorDeviceToDeviceInfo(device);\n // Discovery descriptors do not carry the firmware-verified identity.\n if (!this._sessions.has(info.connectId)) this._devices.set(info.connectId, info);\n }\n return Array.from(this._devices.values()).filter(\n device => !options?.transportType || device.connectionType === options.transportType\n );\n }\n\n async searchDeviceTargets(options?: SearchDevicesOptions): Promise<DeviceSearchTarget[]> {\n const devices = await this.searchDevices(options);\n return devices.map(device => ({\n searchTargetId: device.connectId,\n searchTargetReusePolicy: resolveSearchTargetReusePolicy(device),\n vendor: 'trezor',\n connectionType: device.connectionType,\n kind: 'physical',\n label: device.label,\n model: device.model,\n modelName: device.modelName,\n serialNumber: device.serialNumber,\n }));\n }\n\n async listConnectionTargets(options?: SearchDevicesOptions): Promise<ConnectionTarget[]> {\n const targets = await this.searchDeviceTargets(options);\n return targets.map(({ searchTargetId, ...target }) => ({\n ...target,\n targetId: searchTargetId,\n }));\n }\n\n async bindBleDevice(params: BindBleDeviceParams): Promise<Response<string>> {\n if (params.identity.vendor !== 'trezor' || !params.identity.value) {\n return failure(HardwareErrorCode.InvalidParams, 'Trezor device identity is required');\n }\n const { value: deviceId } = params.identity;\n try {\n return await this._jobQueue.enqueue(\n deviceId,\n async signal => {\n const selected = await this._selectBleDeviceForBinding(\n deviceId,\n signal,\n { extra: params.extra },\n 'manual-rebind'\n );\n try {\n const persisted = await this._emitVerifiedBinding(\n deviceId,\n selected.connectId,\n selected.selectionRequestId,\n { extra: params.extra },\n signal\n );\n if (!persisted) {\n // A business call can shrug off an unsaved binding, but here\n // saving the binding IS the operation.\n throw createHwkError({\n code: HardwareErrorCode.UnknownError,\n message: 'Bluetooth binding could not be saved',\n origin: 'host',\n });\n }\n this._rememberVerifiedConnection(deviceId, selected.connectId);\n return success(selected.connectId);\n } catch (error) {\n await this._releaseProvisionalConnection(selected.connectId, signal);\n throw error;\n }\n },\n {\n label: 'bindBleDevice',\n rejectIfBusy: true,\n busyError: TrezorAdapter._createDeviceBusyError('bindBleDevice'),\n }\n );\n } catch (error) {\n return this._errorToFailure(error);\n }\n }\n\n async connectDevice(searchTargetId: string): Promise<Response<string>> {\n try {\n await this._ensureDevicePermission(\n searchTargetId,\n undefined,\n this._devices.get(searchTargetId)?.connectionType\n );\n await this._ensureSession(searchTargetId);\n const device = this._devices.get(searchTargetId);\n if (!device) {\n return failure(HardwareErrorCode.DeviceNotFound, 'Trezor device not found after connect');\n }\n this._operations.endByConnectionKey(searchTargetId, 'explicit');\n const operation = this._operations.create({\n searchTargetId,\n connectId: searchTargetId,\n device,\n connectionType: device.connectionType,\n connectionKeys: [this._sessions.get(searchTargetId) ?? ''],\n });\n return success(operation.operationId);\n } catch (error) {\n return this._errorToFailure(error);\n }\n }\n\n async releaseOperation(operationId: string): Promise<void> {\n const operation = this._operations.find(operationId);\n if (!operation) {\n this._operations.resolve(operationId);\n return;\n }\n const endedOperation = this._operations.end(operationId, 'explicit');\n if (!endedOperation) return;\n await this._releaseOperationConnection(endedOperation);\n }\n\n private async _releaseOperationConnection(\n operation: NonNullable<ReturnType<OperationRegistry['find']>>\n ): Promise<void> {\n const { connectId } = operation;\n const connecting = this._connectingPromises.has(connectId);\n this._connectingPromises.delete(connectId);\n const sessionId = this._sessions.get(connectId);\n if (!sessionId) {\n // Connect may be in flight (session not recorded yet) — mark it so\n // _connectSession tears down the session it produces instead of caching it.\n if (connecting) this._disconnectRequested.add(connectId);\n return;\n }\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n await this._runConnectorTeardown(() => this._connector.disconnect(sessionId));\n }\n\n async getDeviceInfo(\n connectIdOrOperationId: string,\n deviceId: string\n ): Promise<Response<DeviceInfo>> {\n let connectId: string;\n try {\n connectId = isHardwareOperationId(connectIdOrOperationId)\n ? this._operations.resolve(connectIdOrOperationId).connectId\n : connectIdOrOperationId;\n } catch (error) {\n return this._errorToFailure(error);\n }\n const device =\n this._devices.get(connectId) ??\n Array.from(this._devices.values()).find(item => item.deviceId === deviceId);\n if (!device) return failure(HardwareErrorCode.DeviceNotFound, 'Trezor device not found');\n return success(device);\n }\n\n async allNetworkGetAddress(\n connectId: string,\n deviceId: string,\n params: AllNetworkGetAddressParams\n ): Promise<Response<AllNetworkAddressResponse[]>> {\n const target = resolveHardwareOperationTarget(connectId, params.operationId, 'trezor');\n if (!target.success) return target;\n\n let effectiveTargetId = target.payload.targetId ?? '';\n let releaseOperationRetention: (() => void) | undefined;\n try {\n releaseOperationRetention = target.payload.operationId\n ? this._operations.retain(target.payload.operationId)\n : undefined;\n } catch (error) {\n return this._errorToFailure(error);\n }\n\n // Each item enqueues its own job, so a cancel landing between two items has\n // no job to abort. The scope survives that gap; same key `_callMethod`\n // enqueues under, so `cancel()` reaches it with the key it already computes.\n const cancelScope = this._jobQueue.createCancelScope(\n trezorQueueKey({ operationId: target.payload.operationId, connectId: effectiveTargetId })\n );\n\n let liveDeviceId = '';\n const bundleContext: TrezorBundleContext = {};\n const topLevelFailureIndexes = new Set<number>();\n const isSingleNetworkBundle = params.bundle.every(\n item => item.network === params.bundle[0]?.network\n );\n const getLiveDeviceId = async (expectedDeviceId?: string): Promise<Response<string>> => {\n if (liveDeviceId) return success(liveDeviceId);\n const deviceIdResponse = await this._getTrezorDeviceId(\n effectiveTargetId,\n expectedDeviceId || deviceId,\n params,\n bundleContext\n );\n if (deviceIdResponse.success) {\n liveDeviceId = deviceIdResponse.payload;\n if (!target.payload.operationId) {\n effectiveTargetId = bundleContext.connection?.connectId ?? effectiveTargetId;\n }\n }\n return deviceIdResponse;\n };\n\n try {\n return await runAllNetworkGetAddress({\n connectId: effectiveTargetId,\n deviceId,\n params,\n normalizeItem: TrezorAdapter._normalizeAllNetworkItem,\n callItem: async ({ method, item, index }) => {\n if (cancelScope.signal.aborted) {\n topLevelFailureIndexes.add(index);\n return TrezorAdapter._buildCancelledFailure(cancelScope.signal);\n }\n const expectedDeviceId = TrezorAdapter._getItemDeviceId(item) ?? deviceId;\n if (expectedDeviceId) {\n const fingerprint = await getLiveDeviceId(expectedDeviceId);\n if (!fingerprint.success) {\n topLevelFailureIndexes.add(index);\n return fingerprint;\n }\n if (expectedDeviceId !== fingerprint.payload) {\n topLevelFailureIndexes.add(index);\n return failure(\n HardwareErrorCode.DeviceMismatch,\n `Wrong device: expected ${expectedDeviceId}, got ${fingerprint.payload}`,\n { expected: expectedDeviceId, actual: fingerprint.payload }\n );\n }\n }\n const callItem = TrezorAdapter._withAllNetworkRequestCommonParams(item, params);\n return this._callAllNetworkMethod(effectiveTargetId, method, callItem, bundleContext);\n },\n attachIdentity: async ({ item, chain, payload, index }) => {\n if (!liveDeviceId) {\n // Bootstrapping is another device round trip, so it needs the same\n // gap check.\n if (cancelScope.signal.aborted) {\n topLevelFailureIndexes.add(index);\n const cancelled = TrezorAdapter._buildCancelledFailure<never>(cancelScope.signal);\n return { ...item, success: false, payload: cancelled.payload };\n }\n const fingerprint = await getLiveDeviceId(deviceId);\n if (!fingerprint.success) {\n return { ...item, success: false, payload: fingerprint.payload };\n }\n }\n return {\n ...item,\n success: true,\n payload: {\n ...payload,\n deviceIdentity: {\n vendor: 'trezor',\n type: 'deviceId',\n value: liveDeviceId,\n },\n chainFingerprint: liveDeviceId,\n chainFingerprintChain: chain,\n },\n };\n },\n // One named boolean per abort reason.\n shouldAbortBundle: (response, { index }) => {\n const isSessionLevelFailure = topLevelFailureIndexes.has(index);\n // Mixed bundles must not abort — other chains can still derive.\n const isWholeChainForbidden =\n isSingleNetworkBundle &&\n response.payload?.code === HardwareErrorCode.DevicePathForbidden;\n const isPassphrasePolicyFailure =\n response.payload?.code === HardwareErrorCode.PassphraseAlwaysOnDevice;\n const { code } = response.payload ?? {};\n return (\n isSessionLevelFailure ||\n isWholeChainForbidden ||\n isPassphrasePolicyFailure ||\n isUserRefusal(code) ||\n isConnectionLost(code)\n );\n },\n });\n } finally {\n cancelScope.release();\n releaseOperationRetention?.();\n }\n }\n\n getFeatures(\n connectId: string,\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'getFeatures',\n connectId,\n {},\n operationContext\n );\n }\n\n /**\n * Device authenticity attestation. Sends a host-generated challenge, has the\n * device sign it with its secure-element key, then verifies the returned\n * certificate chain up to a trusted Trezor root CA. On success returns a\n * `deviceId` that uniquely identifies the physical device, survives wipe, and\n * cannot be forged from a seed. Only trust the result when `verified` is true\n * (and `usedDebugKey` is false in production).\n *\n * Requires a secure-element model (Safe 3 = T2B1/T3B1, Safe 5 = T3T1, T3W1)\n * and an on-device confirmation. Older models (T1B1, T2T1) will fail.\n *\n * `dangerouslyAllowDebugKeys` accepts simulator / development root keys — NEVER\n * enable it in a production accounting flow, it lets an emulator mint any id.\n */\n async verifyDeviceAuthenticity(\n connectId: string,\n params: DeviceAuthenticityParams = {}\n ): Promise<Response<DeviceAuthenticityResult>> {\n if (params.challenge && params.dangerouslyAllowDebugKeys) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Debug attestation roots cannot be used with a server challenge'\n );\n }\n if (params.challenge && !/^[0-9a-fA-F]{64}$/.test(params.challenge)) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Device authenticity challenge must be exactly 32 bytes encoded as hex'\n );\n }\n\n const featuresRes = await this.getFeatures(connectId);\n if (!featuresRes.success) return featuresRes;\n\n const internalModel = (featuresRes.payload as { internal_model?: string }).internal_model;\n if (!internalModel) {\n return failure(HardwareErrorCode.UnknownError, 'Device internal_model unavailable');\n }\n\n const challengeHex =\n params.challenge?.toLowerCase() ?? Buffer.from(randomBytes(32)).toString('hex');\n const challenge = Buffer.from(challengeHex, 'hex');\n const proofRes = await this._callDeviceManagerMethod<Record<string, unknown>>(\n 'authenticateDevice',\n connectId,\n { challenge: challengeHex }\n );\n if (!proofRes.success) return proofRes;\n\n const proof = proofRes.payload as unknown as AuthenticityProof;\n const verification = authenticateDeviceFromProof({\n proof,\n challenge,\n deviceModel: internalModel,\n allowDebugKeys: params.dangerouslyAllowDebugKeys,\n });\n\n return success({\n ...verification,\n vendor: 'trezor' as const,\n trezorProof: {\n challenge: challengeHex,\n deviceModel: internalModel,\n proof,\n },\n });\n }\n\n deviceSettings(\n connectId: string,\n params: TrezorDeviceSettingsParams,\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'deviceSettings',\n connectId,\n params,\n operationContext\n );\n }\n\n setBrightness(\n connectId: string,\n params: TrezorBrightnessParams = {},\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'setBrightness',\n connectId,\n params,\n operationContext\n );\n }\n\n changePin(\n connectId: string,\n params: TrezorChangePinParams = {},\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'changePin',\n connectId,\n params,\n operationContext\n );\n }\n\n wipeDevice(\n connectId: string,\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'wipeDevice',\n connectId,\n {},\n operationContext\n );\n }\n\n private async _getTrezorDeviceId(\n connectId: string,\n expectedDeviceId?: string,\n commonParams?: TrezorCommonParams,\n bundleContext?: TrezorBundleContext\n ): Promise<Response<string>> {\n const hasConnectionContext =\n commonParams?.knownConnections !== undefined || commonParams?.extra !== undefined;\n const features =\n bundleContext || hasConnectionContext\n ? await this._callMethod<Record<string, unknown>>(\n 'getFeatures',\n connectId,\n hasConnectionContext || !connectId ? expectedDeviceId : undefined,\n hasConnectionContext\n ? {\n operationId: commonParams.operationId,\n knownConnections: commonParams.knownConnections,\n extra: commonParams.extra,\n allowDeviceSelection: commonParams.allowDeviceSelection,\n passphraseState: commonParams.passphraseState,\n useEmptyPassphrase: commonParams.useEmptyPassphrase,\n }\n : {},\n false,\n bundleContext\n )\n : await this.getFeatures(\n connectId,\n !connectId && expectedDeviceId\n ? {\n expectedDeviceIdentity: {\n vendor: 'trezor',\n type: 'deviceId',\n value: expectedDeviceId,\n },\n }\n : undefined\n );\n if (!features.success) return features;\n const liveDeviceId = features.payload.device_id;\n if (typeof liveDeviceId !== 'string' || liveDeviceId.length === 0) {\n return failure(HardwareErrorCode.UnknownError, 'Trezor features did not include a device_id');\n }\n return success(liveDeviceId);\n }\n\n cancel(connectId?: string): void {\n // \"Cancel this one\" and \"cancel whatever is running\" are different\n // instructions. An operation id that has already ended names nothing, so\n // this call must leave no trace at all rather than decay into the\n // untargeted form and take down an unrelated job or someone else's pending\n // UI request. Decided before anything else.\n if (isHardwareOperationId(connectId)) {\n try {\n this._operations.resolve(connectId);\n } catch {\n // Ended (tombstoned) and never-existed both land here.\n return;\n }\n }\n const userAbortReason = Object.assign(new Error('User aborted operation'), {\n code: HardwareErrorCode.UserAborted,\n });\n const activeJobId = this._jobQueue.getActiveJob()?.deviceId;\n const targetId = connectId ?? activeJobId;\n if (targetId) {\n let resolvedConnectId = targetId;\n let operationId: string | undefined;\n if (isHardwareOperationId(targetId)) {\n try {\n operationId = targetId;\n resolvedConnectId = this._operations.resolve(targetId).connectId;\n } catch {\n resolvedConnectId = '';\n }\n }\n const interactionForPhysicalId =\n !operationId && connectId\n ? this._operations.findActiveByConnectionKey(connectId)\n : undefined;\n // A bundle called without an operationId queues its items — and opens its\n // cancel scope — under the raw connectId, while the operation that owns\n // that connection is a second live key. Both get cancelled. Pending jobs\n // and scopes go with the active one: between two bundle items nothing is\n // active, and only the scope carries the cancel across that gap.\n const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;\n // Release adapter-level UI waits (preemption, device selection) and\n // connector-level ones (THP pairing / PIN matrix). A named cancel keeps\n // the adapter-side clear inside its own operation, so cancelling one\n // signing call no longer closes another operation's PIN prompt. Named but\n // unresolvable clears nothing: falling through to the untargeted form is\n // what a named cancel must not do.\n if (!connectId) {\n this._uiRegistry.cancel();\n } else if (pendingOperationId) {\n this._uiRegistry.cancel(undefined, undefined, pendingOperationId);\n }\n this._connector.uiResponse({ type: UI_RESPONSE.CANCEL });\n const queueKeys = new Set<string>([trezorQueueKey({ connectId: targetId })]);\n if (pendingOperationId) queueKeys.add(trezorQueueKey({ operationId: pendingOperationId }));\n for (const key of queueKeys) {\n this._jobQueue.cancelActiveAndPending(key, userAbortReason);\n }\n if (resolvedConnectId) {\n void this._connector.cancel(this._sessions.get(resolvedConnectId) ?? resolvedConnectId);\n }\n return;\n }\n // Nothing to name: teardown clears every waiter on both sides.\n this._uiRegistry.cancel();\n this._connector.uiResponse({ type: UI_RESPONSE.CANCEL });\n this._jobQueue.cancelActiveAndPending(undefined, userAbortReason);\n for (const sessionId of this._sessions.values()) {\n void this._connector.cancel(sessionId);\n }\n }\n\n /**\n * The operation the running device job belongs to, so a UI request raised\n * mid-call can name it. A call pinned to an operation queues under its id\n * (`trezorQueueKey`); a call without one queues under the connectId, and the\n * live operation on that connection is still the owner. Only work with no\n * operation at all comes back undefined.\n */\n private _activeOperationId(): string | undefined {\n const activeJobId = this._jobQueue.getActiveJob()?.deviceId;\n if (!activeJobId) return undefined;\n if (isHardwareOperationId(activeJobId)) return activeJobId;\n return this._operations.findActiveByConnectionKey(activeJobId)?.operationId;\n }\n\n /**\n * Routes to BOTH the adapter's local UI registry (preemption decisions,\n * future SELECT_DEVICE / DEVICE_PERMISSION) AND the connector's registry\n * (THP pairing tag, PIN matrix). Each side ignores types it isn't waiting\n * for, so double-routing is harmless.\n */\n uiResponse(response: UiResponseEvent): void {\n this._uiRegistry.resolve(response.type, response.payload);\n if (response.type === UI_RESPONSE.RECEIVE_SELECT_DEVICE) return;\n this._connector.uiResponse(response);\n }\n\n /**\n * Returns the Trezor `device_id` from Features — a random 12-byte value the\n * device stores and regenerates on `wipe_device`. It identifies the PHYSICAL\n * DEVICE, not a seed/wallet: it is shared across passphrase wallets and\n * changes after wipe/restore, so it suits device-match checks but must NOT be\n * used as a wallet fingerprint (use `passphraseState` for wallet identity).\n * Unlike Ledger (which hashes a per-chain address), it is chain-global, so\n * `chain` is accepted for API parity but ignored.\n */\n async getChainFingerprint(\n connectId: string,\n deviceId: string,\n _chain: ChainForFingerprint\n ): Promise<Response<string>> {\n return this._getTrezorDeviceId(connectId, deviceId);\n }\n\n /**\n * Resolve the active passphrase wallet identity (`passphraseState`).\n * See {@link IHardwareWallet.getPassphraseState} for the discover/verify\n * semantics. Returns `null` for a standard wallet (no passphrase protection) —\n * there's nothing to pin. Serialized through the per-device job queue so it\n * can't interleave with a chain call on the same device (which would desync\n * the THP session selection).\n */\n getPassphraseState(\n connectId: string,\n passphraseState?: string,\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<string | null>> {\n const expectedIdentity = operationContext?.expectedDeviceIdentity;\n if (\n expectedIdentity &&\n (expectedIdentity.vendor !== 'trezor' || expectedIdentity.type !== 'deviceId')\n ) {\n return Promise.resolve(\n failure(HardwareErrorCode.InvalidParams, 'Trezor device identity is required')\n );\n }\n const target = resolveHardwareOperationTarget(\n connectId,\n operationContext?.operationId,\n 'trezor'\n );\n if (!target.success) return Promise.resolve(target);\n const { operationId } = target.payload;\n let resolvedConnectId = target.payload.targetId ?? '';\n let releaseOperationRetention: (() => void) | undefined;\n if (operationId) {\n try {\n resolvedConnectId = this._operations.resolve(operationId).connectId;\n releaseOperationRetention = this._operations.retain(operationId);\n } catch (error) {\n return Promise.resolve(this._errorToFailure(error));\n }\n }\n return this._jobQueue\n .enqueue(\n trezorQueueKey({ operationId, connectId: resolvedConnectId }),\n async signal => {\n let selectionRequestId: string | undefined;\n let verified = false;\n // One exit for the binding UI. Everything between picking an endpoint\n // and saving its binding can fail - identity mismatch, session\n // creation, unlock, passphrase derivation - and releasing the device\n // is not the same as closing the dialog the user is looking at. Left\n // to individual exits, the next failure added below would forget\n // again; here every one of them lands in the same finally.\n try {\n if (\n !operationId &&\n expectedIdentity?.value &&\n (!connectId || operationContext?.knownConnections !== undefined)\n ) {\n const resolved = await this._resolveExpectedDeviceConnectId(\n expectedIdentity.value,\n signal,\n operationContext\n );\n resolvedConnectId = resolved.connectId;\n selectionRequestId = resolved.selectionRequestId;\n }\n if (expectedIdentity?.value) {\n if (!operationId) await this._ensureSession(resolvedConnectId, signal);\n if (this._devices.get(resolvedConnectId)?.deviceId !== expectedIdentity.value) {\n return failure(\n HardwareErrorCode.DeviceMismatch,\n 'Trezor device identity does not match'\n );\n }\n }\n const restorePassphraseRequestContext = this._setPassphraseRequestContext(\n resolvedConnectId,\n {\n passphraseState,\n }\n );\n try {\n const result = await this._resolvePassphraseState(\n resolvedConnectId,\n passphraseState,\n signal,\n operationId\n );\n if (result.success && expectedIdentity?.value) {\n await this._emitVerifiedBinding(\n expectedIdentity.value,\n resolvedConnectId,\n selectionRequestId,\n operationContext,\n signal\n );\n verified = true;\n this._rememberVerifiedConnection(expectedIdentity.value, resolvedConnectId);\n }\n return result;\n } finally {\n restorePassphraseRequestContext();\n }\n } finally {\n if (selectionRequestId && !verified) {\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: {\n selectionRequestId,\n status: signal.aborted ? 'cancelled' : 'failed',\n },\n });\n await this._releaseProvisionalConnection(resolvedConnectId, signal);\n }\n }\n },\n {\n label: 'getPassphraseState',\n rejectIfBusy: true,\n busyError: TrezorAdapter._createDeviceBusyError('getPassphraseState'),\n }\n )\n .catch(error => this._errorToFailure(error))\n .finally(() => releaseOperationRetention?.());\n }\n\n evmGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmGetAddressParams>\n ) {\n return this._callWalletMethod<EvmAddress>('evmGetAddress', connectId, deviceId, params);\n }\n\n evmSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignTxTrezorParams>\n ) {\n return this._callWalletMethod<EvmSignedTx>('evmSignTransaction', connectId, deviceId, params);\n }\n\n evmSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignMsgParams>\n ) {\n return this._callWalletMethod<EvmSignature>('evmSignMessage', connectId, deviceId, params);\n }\n\n evmSignTypedData(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignTypedDataParams>\n ) {\n return this._callWalletMethod<EvmSignature>('evmSignTypedData', connectId, deviceId, params);\n }\n\n btcGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcGetAddressParams>\n ) {\n return this._callWalletMethod<BtcAddress>('btcGetAddress', connectId, deviceId, params);\n }\n\n btcGetPublicKey(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcGetPublicKeyParams>\n ) {\n return this._callWalletMethod<BtcPublicKey>('btcGetPublicKey', connectId, deviceId, params);\n }\n\n btcSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignTxParams>\n ) {\n return this._callWalletMethod<BtcSignedTx>('btcSignTransaction', connectId, deviceId, params);\n }\n\n btcSignPsbt(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignPsbtParams>\n ) {\n return this._callWalletMethod<BtcSignedPsbt>('btcSignPsbt', connectId, deviceId, params);\n }\n\n btcSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignMsgParams>\n ) {\n return this._callWalletMethod<BtcSignature>('btcSignMessage', connectId, deviceId, params);\n }\n\n btcGetMasterFingerprint(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCommonParams\n ) {\n return this._callWalletMethod<{ masterFingerprint: string }>(\n 'btcGetMasterFingerprint',\n connectId,\n deviceId,\n params\n );\n }\n\n solGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolGetAddressParams>\n ) {\n return this._callWalletMethod<SolAddress>('solGetAddress', connectId, deviceId, params);\n }\n\n solSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolSignTxParams>\n ) {\n return this._callWalletMethod<SolSignedTx>('solSignTransaction', connectId, deviceId, params);\n }\n\n solSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolSignMsgParams>\n ) {\n return this._callWalletMethod<SolSignature>('solSignMessage', connectId, deviceId, params);\n }\n\n tronGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronGetAddressParams>\n ) {\n return this._callWalletMethod<TronAddress>('tronGetAddress', connectId, deviceId, params);\n }\n\n tronSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronSignTxParams>\n ) {\n return this._callWalletMethod<TronSignedTx>('tronSignTransaction', connectId, deviceId, params);\n }\n\n tronSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronSignMsgParams>\n ) {\n return this._callWalletMethod<TronSignature>('tronSignMessage', connectId, deviceId, params);\n }\n\n private static _unwrapConnectorResult(result: unknown): unknown {\n if (\n result &&\n typeof result === 'object' &&\n 'success' in result &&\n (((result as ConnectorCallResult).success === true && 'payload' in result) ||\n ((result as ConnectorCallResult).success === false && 'error' in result))\n ) {\n const connectorResult = result as ConnectorCallResult;\n if (connectorResult.success) return connectorResult.payload;\n throw rehydrateConnectorError(connectorResult.error);\n }\n return result;\n }\n\n private async _callConnector(\n sessionId: string,\n method: string,\n params: unknown,\n signal?: AbortSignal\n ): Promise<unknown> {\n if (signal?.aborted) {\n throw (signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted');\n }\n this._assertConnectorIdle(method);\n const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);\n let promise: Promise<unknown>;\n try {\n promise = this._connector.call(sessionId, method, params).finally(() => {\n releaseOperation();\n });\n } catch (error) {\n releaseOperation();\n throw error;\n }\n const result = signal ? await TrezorAdapter._abortable(signal, promise) : await promise;\n return TrezorAdapter._unwrapConnectorResult(result);\n }\n\n private _assertConnectorIdle(method: string): void {\n // Trezor's connector owns one physical protocol pipe even when the public\n // adapter has multiple logical device ids.\n if (\n this._resetPromise ||\n this._pendingConnectorTeardowns > 0 ||\n this._unsettledConnectorOperations.size > 0\n ) {\n throw TrezorAdapter._createDeviceBusyError(method);\n }\n }\n\n private _runConnectorTeardown(task: () => Promise<void>): Promise<void> {\n const previous = this._connectorTeardownTail;\n let releaseTail: () => void = () => undefined;\n this._connectorTeardownTail = new Promise<void>(resolve => {\n releaseTail = resolve;\n });\n this._pendingConnectorTeardowns += 1;\n return (async () => {\n try {\n await previous;\n // Connector cancel is advisory. Do not close a Trezor transport while\n // its raw protocol request is still draining.\n await this._waitForConnectorOperationsToDrain();\n await task();\n } finally {\n this._pendingConnectorTeardowns -= 1;\n releaseTail();\n }\n })();\n }\n\n private async _releaseProvisionalConnection(\n connectId: string,\n signal: AbortSignal\n ): Promise<void> {\n const sessionId = this._sessions.get(connectId);\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n if (!sessionId) return;\n // Register the teardown barrier before returning cancellation. The raw\n // protocol call still owns the pipe until it drains, but not its caller.\n const teardown = this._runConnectorTeardown(() => this._connector.disconnect(sessionId)).catch(\n () => undefined\n );\n if (!signal.aborted) await teardown;\n }\n\n private _waitForConnectorOperationsToDrain(): Promise<void> {\n if (this._unsettledConnectorOperations.size === 0) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n this._connectorIdleWaiters.add(resolve);\n });\n }\n\n private _retainConnectorOperation(key: string): () => void {\n this._unsettledConnectorOperations.set(\n key,\n (this._unsettledConnectorOperations.get(key) ?? 0) + 1\n );\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;\n if (remaining > 0) {\n this._unsettledConnectorOperations.set(key, remaining);\n } else {\n this._unsettledConnectorOperations.delete(key);\n }\n if (this._unsettledConnectorOperations.size === 0) {\n for (const resolve of this._connectorIdleWaiters) resolve();\n this._connectorIdleWaiters.clear();\n }\n };\n }\n\n private static _normalizeAllNetworkItem(\n method: AllNetworkMethodName,\n item: AllNetworkAddressParams\n ): AllNetworkAddressParams {\n if (method !== 'btcGetAddress' && method !== 'btcGetPublicKey') {\n return item;\n }\n\n const itemWithCoin = item as AllNetworkAddressParams & { coin?: unknown };\n if (itemWithCoin.coin) {\n return item;\n }\n\n const network = item.network.toLowerCase();\n return {\n ...item,\n coin: TREZOR_BTC_NETWORK_COIN_MAP[network] ?? item.network,\n };\n }\n\n private static _getItemDeviceId(item: AllNetworkAddressParams): string | undefined {\n const { deviceId } = item as { deviceId?: unknown };\n return typeof deviceId === 'string' && deviceId.length > 0 ? deviceId : undefined;\n }\n\n /** UserAborted is a top-level abort code, so this ends the bundle. */\n private static _buildCancelledFailure<T>(signal: AbortSignal): Response<T> {\n const reason = signal.reason as { code?: unknown; message?: unknown } | undefined;\n const code =\n typeof reason?.code === 'number'\n ? (reason.code as HardwareErrorCode)\n : HardwareErrorCode.UserAborted;\n const message = typeof reason?.message === 'string' ? reason.message : '';\n return failure(code, message || 'All-network get-address cancelled');\n }\n\n private _callAllNetworkMethod(\n connectId: string,\n method: AllNetworkMethodName,\n item: AllNetworkAddressParams,\n bundleContext: TrezorBundleContext\n ): Promise<Response<unknown>> {\n switch (method) {\n case 'evmGetAddress':\n case 'btcGetAddress':\n case 'btcGetPublicKey':\n case 'solGetAddress':\n case 'tronGetAddress':\n return this._callMethod(method, connectId, '', item, true, bundleContext);\n default:\n return Promise.resolve(\n failure(\n HardwareErrorCode.InvalidParams,\n `Unsupported allNetwork method: ${String(method)}`\n )\n );\n }\n }\n\n on<K extends keyof HardwareEventMap>(\n event: K,\n listener: (event: HardwareEventMap[K]) => void\n ): void;\n\n on(event: string, listener: DeviceEventListener): void;\n\n on(event: string, listener: (event: HardwareEvent) => void): void {\n this._emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(\n event: K,\n listener: (event: HardwareEventMap[K]) => void\n ): void;\n\n off(event: string, listener: DeviceEventListener): void;\n\n off(event: string, listener: (event: HardwareEvent) => void): void {\n this._emitter.off(event, listener);\n }\n\n private _callWalletMethod<T>(\n methodName: TrezorWalletMethodName,\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>\n ): Promise<Response<T>> {\n return this._callMethod<T>(methodName, connectId, deviceId, params, true);\n }\n\n private _callDeviceManagerMethod<T>(\n methodName: TrezorDeviceManagerMethodName,\n connectId: NullableCallArg<string>,\n params: NullableCallArg<unknown>,\n operationContext?: IDeviceManagerOperationContext\n ): Promise<Response<T>> {\n const expectedIdentity = operationContext?.expectedDeviceIdentity;\n if (\n expectedIdentity &&\n (expectedIdentity.vendor !== 'trezor' || expectedIdentity.type !== 'deviceId')\n ) {\n return Promise.resolve(\n failure(\n HardwareErrorCode.InvalidParams,\n 'Trezor device-manager operations require a Trezor deviceId identity'\n )\n );\n }\n return this._callMethod<T>(\n methodName,\n connectId,\n expectedIdentity?.value,\n {\n ...(params && typeof params === 'object' ? params : {}),\n knownConnections: operationContext?.knownConnections,\n extra: operationContext?.extra,\n allowDeviceSelection: operationContext?.allowDeviceSelection,\n ...(operationContext?.operationId ? { operationId: operationContext.operationId } : {}),\n },\n false\n );\n }\n\n private async _callMethod<T>(\n methodName: TrezorMethodName,\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>,\n requiresWalletIntent: boolean,\n bundleContext?: TrezorBundleContext\n ): Promise<Response<T>> {\n const call = TrezorAdapter._normalizeCallArgs(connectId, deviceId, params);\n const commonParams = TrezorAdapter._splitCommonParams(call.params);\n const positionalOperationId = isHardwareOperationId(call.connectId)\n ? call.connectId\n : undefined;\n if (\n positionalOperationId &&\n commonParams.operationId &&\n positionalOperationId !== commonParams.operationId\n ) {\n return failure(HardwareErrorCode.InvalidParams, 'Conflicting Trezor operation ids', {\n positionalOperationId,\n commonOperationId: commonParams.operationId,\n });\n }\n const operationId = commonParams.operationId ?? positionalOperationId;\n let releaseOperationRetention: (() => void) | undefined;\n try {\n if (operationId) {\n call.connectId = this._operations.resolve(operationId).connectId;\n releaseOperationRetention = this._operations.retain(operationId);\n }\n } catch (error) {\n return this._errorToFailure(error);\n }\n debugLog('[TrezorAdapter][REQ]', {\n method: methodName,\n connectId: call.connectId || '(empty)',\n deviceId: deviceId || undefined,\n params: TrezorAdapter._sanitizeForLog(call.params, methodName),\n });\n try {\n const response = await this._jobQueue.enqueue(\n trezorQueueKey({ operationId, connectId: call.connectId }),\n async signal => {\n let effectiveConnectId = call.connectId;\n let selectionRequestId: string | undefined;\n try {\n if (\n !bundleContext?.connection &&\n !operationId &&\n deviceId &&\n (!connectId || commonParams.connectionContext?.knownConnections !== undefined)\n ) {\n const resolved = await this._resolveExpectedDeviceConnectId(\n deviceId,\n signal,\n commonParams.connectionContext\n );\n effectiveConnectId = resolved.connectId;\n selectionRequestId = resolved.selectionRequestId;\n }\n } catch (error) {\n return this._errorToFailure(error);\n }\n const response = await this._callWithRetry<T>(\n bundleContext?.connection?.connectId ?? effectiveConnectId,\n methodName,\n call.params,\n deviceId || '',\n requiresWalletIntent,\n true,\n signal,\n operationId,\n selectionRequestId,\n bundleContext\n );\n if (!response.success && selectionRequestId) {\n // A selected endpoint is provisional until wallet verification succeeds.\n // Release it so a later attempt gets its own explicit binding request.\n await this._releaseProvisionalConnection(effectiveConnectId, signal);\n }\n return response;\n },\n {\n label: methodName,\n rejectIfBusy: true,\n busyError: TrezorAdapter._createDeviceBusyError(methodName),\n }\n );\n debugLog('[TrezorAdapter][RES]', {\n method: methodName,\n success: response.success,\n payload: TrezorAdapter._sanitizeForLog(response.payload, methodName),\n });\n return response;\n } catch (error) {\n // The only way a Promise rejects out of `enqueue` is the busy-reject —\n // _callWithRetry never throws, it returns Response.failure. Convert to\n // the Response shape so chain method callers stay uniform.\n const response = this._errorToFailure(error);\n debugLog('[TrezorAdapter][RES]', {\n method: methodName,\n success: false,\n payload: TrezorAdapter._sanitizeForLog(response.payload, methodName),\n });\n return response;\n } finally {\n releaseOperationRetention?.();\n }\n }\n\n private async _callWithRetry<T>(\n connectId: string,\n methodName: TrezorMethodName,\n params: unknown,\n expectedDeviceId: string,\n requiresWalletIntent: boolean,\n allowRetry: boolean,\n signal: AbortSignal,\n operationId?: string,\n selectionRequestId?: string,\n bundleContext?: TrezorBundleContext\n ): Promise<Response<T>> {\n const { passphraseState, useEmptyPassphrase, rest, connectionContext } =\n TrezorAdapter._splitCommonParams(params);\n let pendingBindingRequestId = selectionRequestId;\n let businessCallStarted = false;\n const restorePassphraseRequestContext = this._setPassphraseRequestContext(connectId, {\n passphraseState,\n useEmptyPassphrase,\n });\n try {\n if (bundleContext?.connection) {\n const pinned = bundleContext.connection;\n if (this._sessions.get(pinned.connectId) !== pinned.sessionId) {\n return failure(\n HardwareErrorCode.DeviceDisconnected,\n 'Trezor all-network connection ended'\n );\n }\n }\n const sessionId = operationId\n ? this._sessions.get(this._operations.resolve(operationId).connectId)\n : await this._ensureSession(connectId, signal);\n if (!sessionId) {\n if (operationId) {\n this._operations.end(operationId, 'disconnect');\n return failure(\n HardwareErrorCode.OperationEnded,\n 'Trezor operation connection is no longer active',\n { operationId, reason: 'disconnect' }\n );\n }\n return failure(HardwareErrorCode.DeviceNotFound, 'Trezor session was not found');\n }\n if (bundleContext && !bundleContext.connection) {\n bundleContext.connection = { connectId, sessionId };\n }\n if (expectedDeviceId) {\n const actualDeviceId = this._devices.get(connectId)?.deviceId;\n if (!actualDeviceId || actualDeviceId !== expectedDeviceId) {\n return failure(\n HardwareErrorCode.DeviceMismatch,\n `Wrong device: expected ${expectedDeviceId}, got ${actualDeviceId || 'unknown'}`,\n { expected: expectedDeviceId, actual: actualDeviceId || '' }\n );\n }\n }\n if (requiresWalletIntent && !passphraseState && useEmptyPassphrase !== true) {\n return failure(\n HardwareErrorCode.InvalidParams,\n `Trezor ${methodName} requires an explicit wallet intent: passphraseState or useEmptyPassphrase`\n );\n }\n // Pin the call to the requested passphrase wallet. For THP this creates\n // a new application session; for v1 it re-initializes the device session.\n // Runs inside this queued job so the session alignment and the call can't\n // be interleaved by another request.\n if (passphraseState) {\n await TrezorAdapter._abortable(\n signal,\n this._alignAppSession(connectId, sessionId, passphraseState, signal)\n );\n } else if (useEmptyPassphrase === true) {\n await TrezorAdapter._abortable(signal, this._createFreshAppSession(sessionId, signal));\n }\n if (expectedDeviceId) {\n await this._emitVerifiedBinding(\n expectedDeviceId,\n connectId,\n pendingBindingRequestId,\n connectionContext,\n signal\n );\n pendingBindingRequestId = undefined;\n this._rememberVerifiedConnection(expectedDeviceId, connectId);\n }\n businessCallStarted = true;\n const result = await TrezorAdapter._abortable(\n signal,\n this._callConnector(sessionId, methodName, rest, signal)\n );\n return success(result as T);\n } catch (error) {\n // If we were aborted, surface as-is — don't take the retry/recovery path.\n if (signal.aborted) {\n if (pendingBindingRequestId) {\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: { selectionRequestId: pendingBindingRequestId, status: 'cancelled' },\n });\n pendingBindingRequestId = undefined;\n }\n return this._errorToFailure(error);\n }\n const code = TrezorAdapter._errorCode(error);\n const willRetryStaleSession =\n allowRetry &&\n (passphraseState || useEmptyPassphrase === true) &&\n TrezorAdapter._isStaleSessionError(code);\n if (pendingBindingRequestId && !willRetryStaleSession) {\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: { selectionRequestId: pendingBindingRequestId, status: 'failed' },\n });\n pendingBindingRequestId = undefined;\n }\n const ambiguousTransportFailure =\n code === HardwareErrorCode.DeviceDisconnected ||\n code === HardwareErrorCode.OperationTimeout ||\n code === HardwareErrorCode.TransportError;\n if (operationId && ambiguousTransportFailure) {\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n this._operations.end(operationId, 'disconnect');\n return failure(\n HardwareErrorCode.OperationEnded,\n businessCallStarted && !canReplayHardwareMethodAfterTransportFailure(methodName)\n ? `Trezor ${methodName} may have completed before the connection was lost`\n : 'Trezor operation connection was lost',\n businessCallStarted && !canReplayHardwareMethodAfterTransportFailure(methodName)\n ? operationMayHaveCompletedParams(methodName, {\n operationId,\n reason: 'disconnect',\n })\n : { operationId, reason: 'disconnect' },\n undefined,\n businessCallStarted && !canReplayHardwareMethodAfterTransportFailure(methodName)\n ? { scope: 'unknown' }\n : undefined\n );\n }\n // A one-shot operation also owns its connection once initialization starts.\n // Never reconnect or replay it after the transport is lost.\n if (!operationId && ambiguousTransportFailure) {\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n if (businessCallStarted && !canReplayHardwareMethodAfterTransportFailure(methodName)) {\n return failure(\n code as HardwareErrorCode,\n `Trezor ${methodName} may have completed before the connection was lost`,\n operationMayHaveCompletedParams(methodName),\n undefined,\n { scope: 'unknown' }\n );\n }\n }\n // The device evicted the passphrase session created for this call. Retry\n // once and recreate the requested wallet context.\n if (willRetryStaleSession) {\n if (passphraseState) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n }\n // The retry owns the binding request from here on.\n const retryBindingRequestId = pendingBindingRequestId;\n pendingBindingRequestId = undefined;\n return await this._callWithRetry<T>(\n connectId,\n methodName,\n params,\n expectedDeviceId,\n requiresWalletIntent,\n false,\n signal,\n operationId,\n retryBindingRequestId,\n bundleContext\n );\n }\n debugLog('[TrezorAdapter][ERROR]', {\n method: methodName,\n connectId,\n error: TrezorAdapter._errorForLog(error),\n });\n return this._errorToFailure(error);\n } finally {\n restorePassphraseRequestContext();\n // Early returns above leave the host dialog waiting; close the request here\n // so every exit that did not verify the binding reports a terminal status.\n if (pendingBindingRequestId) {\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: {\n selectionRequestId: pendingBindingRequestId,\n status: signal.aborted ? 'cancelled' : 'failed',\n },\n });\n pendingBindingRequestId = undefined;\n }\n }\n }\n\n private async _ensureSession(\n connectId: string,\n signal?: AbortSignal,\n transportType?: ConnectionType\n ): Promise<string> {\n const existing = this._sessions.get(connectId);\n if (existing) return existing;\n\n const pending = this._connectingPromises.get(connectId);\n if (pending) return pending;\n\n const stateGeneration = this._stateGeneration;\n const promise = (async () => {\n if (signal?.aborted) {\n throw Object.assign(new Error('Trezor connection aborted'), {\n code: HardwareErrorCode.UserAborted,\n });\n }\n // Fail fast: a single connect attempt. On an \"unavailable device\" error we\n // drop the cached session/passphrase state and rethrow (no retry loop).\n try {\n return await this._connectSession(connectId, signal, stateGeneration, transportType);\n } catch (error) {\n if (TrezorAdapter._isConnectionUnavailableError(error)) {\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n }\n throw error;\n }\n })();\n\n this._connectingPromises.set(connectId, promise);\n try {\n return await promise;\n } finally {\n if (this._connectingPromises.get(connectId) === promise) {\n this._connectingPromises.delete(connectId);\n }\n this._disconnectRequested.delete(connectId);\n }\n }\n\n private async _resolveExpectedDeviceConnectId(\n expectedDeviceId: string,\n signal: AbortSignal,\n context?: IHardwareConnectionContext\n ): Promise<{ connectId: string; selectionRequestId?: string }> {\n const connectedMatch = Array.from(this._devices.values()).find(\n device => device.deviceId === expectedDeviceId && this._sessions.has(device.connectId)\n );\n if (connectedMatch) return { connectId: connectedMatch.connectId };\n\n const availableTransports = this._connector.availableTransports ?? [\n this._connector.connectionType,\n ];\n if (availableTransports.includes('usb')) {\n await TrezorAdapter._abortable(\n signal,\n this._ensureDevicePermission(undefined, expectedDeviceId, 'usb')\n );\n }\n const candidates = await TrezorAdapter._abortable(\n signal,\n this._searchDevices({ transportType: 'usb' }, signal)\n );\n\n const mismatchedDeviceIds: string[] = [];\n const knownConnection = this._knownDeviceConnections.get(expectedDeviceId);\n const knownUsbIds =\n context?.knownConnections !== undefined\n ? context.knownConnections.flatMap(connection =>\n connection.transport === 'usb' ? [connection.connectId] : []\n )\n : [knownConnection?.usbConnectId].filter((id): id is string => Boolean(id));\n const suppliedBleIds = context?.knownConnections?.flatMap(connection =>\n connection.transport === 'ble' ? [connection.connectId] : []\n );\n const knownBleIds = suppliedBleIds?.length\n ? suppliedBleIds\n : [knownConnection?.bleConnectId].filter((id): id is string => Boolean(id));\n // A Trezor publishes its serial at enumeration, so a saved USB locator\n // answers \"is my wallet on this bus?\" without opening anything. When the\n // saved locator is absent from this round, the wallet is not plugged in:\n // go to BLE rather than initializing every other Trezor on the bus - which\n // on a Safe 7 means a THP handshake on a device that is not ours - only to\n // fail afterwards. A wallet that has never been reached over USB has no\n // locator to check, and there we do have to connect before we can tell.\n const usbCandidates = candidates.filter(\n device =>\n device.connectionType === 'usb' &&\n (!knownUsbIds.length || knownUsbIds.includes(device.connectId))\n );\n // USB discovery may expose only an ephemeral locator. Probe Features to\n // identify it, but never silently pair arbitrary nearby BLE devices.\n for (const candidate of usbCandidates) {\n let sessionId: string | undefined;\n try {\n // Connecting only initializes Features. No wallet or business method is\n // dispatched until the firmware device_id matches the stored identity.\n // eslint-disable-next-line no-await-in-loop\n sessionId = await this._ensureSession(candidate.connectId, signal, 'usb');\n const actualDeviceId = this._devices.get(candidate.connectId)?.deviceId ?? '';\n if (actualDeviceId === expectedDeviceId) return { connectId: candidate.connectId };\n mismatchedDeviceIds.push(actualDeviceId || 'unknown');\n } catch (error) {\n if (signal.aborted) throw error;\n // Connector initialization failures intentionally keep the transport\n // reusable for a same-device retry. Do not open another candidate on\n // the same protocol pipe until the caller resolves that failure.\n if (!TrezorAdapter._isConnectionUnavailableError(error)) throw error;\n }\n\n if (sessionId) {\n const mismatchedSessionId = sessionId;\n this._sessions.delete(candidate.connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(candidate.connectId);\n // eslint-disable-next-line no-await-in-loop\n await this._runConnectorTeardown(() => this._connector.disconnect(mismatchedSessionId));\n }\n }\n\n if (mismatchedDeviceIds.length) {\n // Every candidate answered and none is this wallet. Say so plainly: the\n // user can unplug it and connect the right one. This is not\n // DeviceMismatch — nothing about the known wallet changed.\n throw createHwkError({\n code: HardwareErrorCode.DeviceSearchMismatch,\n message:\n 'The connected Trezor is not the wallet this operation needs. Unplug it and connect the right device.',\n params: { connectedDeviceIds: mismatchedDeviceIds },\n });\n }\n\n if (usbCandidates.length > 0) {\n // Enumerated but not openable, so no identity was ever read. Claiming the\n // wrong device is plugged in would send the user after the wrong remedy.\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'Trezor devices are present but none could be opened to check its identity.',\n });\n }\n\n const [knownBleConnectId] = knownBleIds;\n if (knownBleConnectId && availableTransports.includes('ble')) {\n // A saved endpoint never opens a new binding session after failure.\n await TrezorAdapter._abortable(\n signal,\n this._ensureDevicePermission(knownBleConnectId, expectedDeviceId, 'ble')\n );\n await this._ensureSession(knownBleConnectId, signal, 'ble');\n const actualDeviceId = this._devices.get(knownBleConnectId)?.deviceId;\n if (actualDeviceId === expectedDeviceId) return { connectId: knownBleConnectId };\n const sessionId = this._sessions.get(knownBleConnectId);\n this._sessions.delete(knownBleConnectId);\n this._verifiedPassphraseSessionsByConnectId.delete(knownBleConnectId);\n if (sessionId) {\n await this._runConnectorTeardown(() => this._connector.disconnect(sessionId));\n }\n throw createHwkError({\n code: HardwareErrorCode.DeviceMismatch,\n message: 'The bound Trezor Bluetooth device has a different identity',\n });\n }\n\n if (context?.allowDeviceSelection === false) {\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No known Trezor connection is available',\n });\n }\n return this._selectBleDeviceForBinding(expectedDeviceId, signal, context, 'missing-binding');\n }\n\n private async _selectBleDeviceForBinding(\n expectedDeviceId: string,\n signal: AbortSignal,\n context: IHardwareConnectionContext | undefined,\n reason: 'missing-binding' | 'manual-rebind'\n ): Promise<{ connectId: string; selectionRequestId?: string }> {\n const availableTransports = this._connector.availableTransports ?? [\n this._connector.connectionType,\n ];\n const allowUsbFallback = reason !== 'manual-rebind' && availableTransports.includes('usb');\n const knownUsbIds = context?.knownConnections\n ? context.knownConnections.flatMap(connection =>\n connection.transport === 'usb' ? [connection.connectId] : []\n )\n : [this._knownDeviceConnections.get(expectedDeviceId)?.usbConnectId];\n if (availableTransports.includes('ble')) {\n await TrezorAdapter._abortable(\n signal,\n this._ensureDevicePermission(undefined, expectedDeviceId, 'ble')\n );\n }\n const bleCandidates = (\n await TrezorAdapter._abortable(\n signal,\n this._searchDevices({ transportType: 'ble', waitForAllTransports: true }, signal)\n )\n ).filter(device => device.connectionType === 'ble');\n if (signal.aborted) throw signal.reason;\n const rejectedConnectIds = new Set<string>();\n const bindingSessionId = this._uiRegistry.createRequestId();\n let rejectedConnectId: string | undefined;\n while (\n availableTransports.includes('ble') &&\n this._emitter.listenerCount(UI_REQUEST.REQUEST_SELECT_DEVICE)\n ) {\n const { device: selected, requestId } = await requestBleDeviceSelection({\n emitter: this._emitter,\n registry: this._uiRegistry,\n signal,\n allowUsbFallback,\n scan: async () => {\n if (allowUsbFallback) {\n const usbCandidates = (\n await this._searchDevices({ transportType: 'usb' }, signal)\n ).filter(\n device => device.connectionType === 'usb' && !rejectedConnectIds.has(device.connectId)\n );\n const candidate =\n usbCandidates.find(device => knownUsbIds.includes(device.connectId)) ??\n usbCandidates[0];\n if (candidate) return [candidate];\n }\n return (\n await this._searchDevices({ transportType: 'ble', waitForAllTransports: true }, signal)\n ).filter(\n device => device.connectionType === 'ble' && !rejectedConnectIds.has(device.connectId)\n );\n },\n request: {\n devices: bleCandidates.filter(device => !rejectedConnectIds.has(device.connectId)),\n bindingSessionId,\n rejectedConnectId,\n context: {\n kind: 'bind-connection',\n transport: 'ble',\n reason,\n },\n extra: context?.extra,\n operationId: this._activeOperationId(),\n },\n });\n try {\n if (reason === 'manual-rebind') {\n this._operations.endByConnectionKey(selected.connectId, 'explicit');\n await this._releaseProvisionalConnection(selected.connectId, signal);\n }\n await this._ensureSession(selected.connectId, signal, selected.connectionType);\n } catch (error) {\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: {\n selectionRequestId: requestId,\n status: signal.aborted ? 'cancelled' : 'failed',\n },\n });\n throw error;\n }\n if (this._devices.get(selected.connectId)?.deviceId !== expectedDeviceId) {\n const sessionId = this._sessions.get(selected.connectId);\n this._sessions.delete(selected.connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(selected.connectId);\n if (sessionId) {\n await this._runConnectorTeardown(() => this._connector.disconnect(sessionId));\n }\n rejectedConnectId = selected.connectId;\n rejectedConnectIds.add(selected.connectId);\n continue;\n }\n if (selected.connectionType === 'usb') {\n // End only the binding UI. The original operation continues on verified USB.\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: { selectionRequestId: requestId, status: 'cancelled' },\n });\n return { connectId: selected.connectId };\n }\n return { connectId: selected.connectId, selectionRequestId: requestId };\n }\n\n throw createHwkError({\n code: HardwareErrorCode.DeviceNotFound,\n message: 'No readable Trezor device is available',\n });\n }\n\n private _rememberVerifiedConnection(deviceId: string, connectId: string): void {\n const device = this._devices.get(connectId);\n if (!device || device.deviceId !== deviceId) return;\n const known = this._knownDeviceConnections.get(deviceId) ?? { deviceId };\n if (device.connectionType === 'ble') {\n known.bleConnectId = connectId;\n } else if (device.connectionType === 'usb' && device.capabilities?.persistentDeviceIdentity) {\n known.usbConnectId = connectId;\n }\n this._knownDeviceConnections.set(deviceId, known);\n }\n\n private async _emitVerifiedBinding(\n deviceId: string,\n connectId: string,\n selectionRequestId: string | undefined,\n context?: IHardwareConnectionContext,\n signal?: AbortSignal\n ): Promise<boolean> {\n if (!selectionRequestId) return false;\n const device = this._devices.get(connectId);\n if (!device || device.deviceId !== deviceId || device.connectionType !== 'ble') {\n // Every other exit reports a terminal status, this one has to as well:\n // callers clear the request id and would leave the host dialog waiting.\n // Cancelled, not failed - the call itself carries on, same as the USB\n // fallback that drops a binding without stopping the operation.\n this._emitter.emit(UI_REQUEST.DEVICE_BINDING_STATUS, {\n type: UI_REQUEST.DEVICE_BINDING_STATUS,\n payload: { selectionRequestId, status: 'cancelled' },\n });\n return false;\n }\n const outcome = await requestSaveDeviceBinding(\n this._emitter,\n this._uiRegistry,\n {\n selectionRequestId,\n connection: { transport: 'ble', connectId },\n identity: { vendor: 'trezor', type: 'deviceId', value: deviceId },\n extra: context?.extra,\n operationId: this._activeOperationId(),\n },\n signal\n );\n return outcome.saved;\n }\n\n /**\n * Pin the device's active wallet session to `passphraseState` (the target\n * wallet identity) before a wallet-bound op. THP has an app-session id; v1\n * does not, but it still binds passphrase to the device session, so the\n * connector re-initializes v1 before we derive and verify.\n *\n * SECURITY: a verified THP app session may be selected again, but the adapter\n * still derives and verifies the passphrase state before any chain method can\n * run. If the cache is stale, fall back to creating a fresh wallet context.\n */\n private async _alignAppSession(\n connectId: string,\n sessionId: string,\n passphraseState: string,\n signal: AbortSignal\n ): Promise<void> {\n const reused = await this._reuseVerifiedPassphraseSession(\n connectId,\n sessionId,\n passphraseState,\n signal\n );\n if (reused) return;\n\n const created = (await TrezorAdapter._abortable(\n signal,\n this._callConnector(\n sessionId,\n '__thpCreateSession',\n {\n passphraseMode: 'prompt',\n },\n signal\n )\n )) as { protocol?: string; thpSessionId?: string | null };\n // v1 has no host-managed app-session id, but the connector has just\n // re-initialized a fresh device session; continue with reactive\n // passphrase-state verification.\n if (\n (created?.protocol === 'thp' && !created.thpSessionId) ||\n (created?.protocol !== 'thp' && created?.protocol !== 'v1')\n ) {\n throw createHwkError({\n code: HardwareErrorCode.TransportError,\n message: 'Cannot verify the requested Trezor wallet session',\n });\n }\n const state = await this._deriveState(sessionId, signal);\n if (state !== passphraseState) {\n throw Object.assign(\n new Error(\n `Passphrase produced wallet ${state}, expected ${passphraseState} (passphraseState mismatch)`\n ),\n { code: HardwareErrorCode.PassphraseStateMismatch }\n );\n }\n this._rememberVerifiedPassphraseSession(connectId, passphraseState, sessionId, created);\n }\n\n private _rememberVerifiedPassphraseSession(\n connectId: string,\n passphraseState: string,\n sessionId: string,\n created: { protocol?: string; thpSessionId?: string | null } | undefined\n ): void {\n let session: TrezorVerifiedPassphraseSession | undefined;\n if (created?.protocol === 'thp' && typeof created.thpSessionId === 'string') {\n session = {\n sessionId,\n protocol: 'thp',\n thpSessionId: created.thpSessionId,\n };\n } else if (created?.protocol === 'v1') {\n session = {\n sessionId,\n protocol: 'v1',\n };\n }\n if (!session) return;\n\n const sessions =\n this._verifiedPassphraseSessionsByConnectId.get(connectId) ??\n new Map<string, TrezorVerifiedPassphraseSession>();\n sessions.set(passphraseState, session);\n this._verifiedPassphraseSessionsByConnectId.set(connectId, sessions);\n }\n\n private _forgetVerifiedPassphraseSession(connectId: string, passphraseState: string): void {\n const sessions = this._verifiedPassphraseSessionsByConnectId.get(connectId);\n if (!sessions) return;\n sessions.delete(passphraseState);\n if (!sessions.size) {\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n }\n }\n\n private async _reuseVerifiedPassphraseSession(\n connectId: string,\n sessionId: string,\n passphraseState: string,\n signal: AbortSignal\n ): Promise<boolean> {\n const cached = this._verifiedPassphraseSessionsByConnectId.get(connectId)?.get(passphraseState);\n if (!cached || cached.sessionId !== sessionId) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n return false;\n }\n\n try {\n if (cached.protocol === 'thp') {\n if (!cached.thpSessionId) return false;\n await TrezorAdapter._abortable(\n signal,\n this._callConnector(\n sessionId,\n '__thpSelectSession',\n {\n thpSessionId: cached.thpSessionId,\n },\n signal\n )\n );\n }\n const state = await this._deriveState(sessionId, signal);\n if (state !== passphraseState) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n return false;\n }\n return true;\n } catch (error) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n if (signal.aborted) throw error;\n return false;\n }\n }\n\n private async _createFreshAppSession(sessionId: string, signal: AbortSignal): Promise<void> {\n // Create a fresh standard-wallet context for this call. Empty passphrase is\n // enforced inside connector/core, not delegated to host UI handlers.\n await TrezorAdapter._abortable(\n signal,\n this._callConnector(\n sessionId,\n '__thpCreateSession',\n {\n passphraseMode: 'empty',\n },\n signal\n )\n );\n }\n\n /**\n * Derive the active session's passphrase state — the wallet identity used to\n * verify the right wallet is active: the compressed PUBLIC KEY at a fixed\n * account path (m/44'/0'/0'). It comes from the SAME GetPublicKey that also\n * carries the 4-byte fingerprint, but we use the FULL pubkey (not the truncated\n * fingerprint) so it's collision-resistant — the address we return can never\n * come from the wrong wallet — while avoiding OneKey's extra Testnet GetAddress.\n * Non-interactive (also unlocks via PIN as a protected derivation).\n */\n private async _deriveState(sessionId: string, signal: AbortSignal): Promise<string> {\n const derived = (await TrezorAdapter._abortable(\n signal,\n this._callConnector(\n sessionId,\n 'btcGetPublicKey',\n {\n path: \"m/44'/0'/0'\",\n showOnDevice: false,\n },\n signal\n )\n )) as { publicKey?: string };\n const state = derived?.publicKey;\n if (!state) {\n throw Object.assign(new Error('Failed to derive passphrase state (wallet public key)'), {\n code: HardwareErrorCode.UnknownError,\n });\n }\n return state;\n }\n\n private async _resolvePassphraseState(\n connectId: string,\n passphraseState: string | undefined,\n signal: AbortSignal,\n operationId?: string\n ): Promise<Response<string | null>> {\n try {\n const sessionId = operationId\n ? this._sessions.get(this._operations.resolve(operationId).connectId)\n : await this._ensureSession(connectId, signal);\n if (!sessionId) {\n return failure(\n HardwareErrorCode.OperationEnded,\n 'Trezor operation connection is no longer active'\n );\n }\n if (passphraseState) {\n // Verify mode: align (which always re-derives + confirms the state) so the\n // host can gate signing on the correct wallet being active.\n await this._alignAppSession(connectId, sessionId, passphraseState, signal);\n return success(passphraseState);\n }\n // Discover mode (OneKey-aligned). DON'T trust pre-read features — a LOCKED\n // device reports an unreliable `passphrase_protection`, and the connector's\n // plain getFeatures returns a CACHED blob, so checking `unlocked` up front\n // is meaningless. Instead derive first (which unlocks), then re-read fresh:\n // 1. Create a session + derive the state. This UNLOCKS the device (PIN) and,\n // for a passphrase wallet, prompts the passphrase (THP: proactively in\n // ThpCreateNewSession; v1: reactively).\n // 2. Re-read features FRESH from the device (now unlocked → trustworthy).\n // 3. passphrase_protection === true → return the current passphrase\n // state, even if the entered passphrase was empty. Otherwise →\n // standard wallet → return null (OneKey-aligned).\n const created = (await TrezorAdapter._abortable(\n signal,\n this._callConnector(\n sessionId,\n '__thpCreateSession',\n {\n passphraseMode: 'prompt',\n },\n signal\n )\n )) as { protocol?: string; thpSessionId?: string | null };\n const state = await this._deriveState(sessionId, signal);\n const features = (await TrezorAdapter._abortable(\n signal,\n this._callConnector(sessionId, 'getFeatures', { refresh: true }, signal)\n )) as Record<string, unknown> | undefined;\n if (features?.passphrase_protection !== true) {\n // Standard wallet — discard the derived state, return null (OneKey convention).\n return success(null);\n }\n this._rememberVerifiedPassphraseSession(connectId, state, sessionId, created);\n return success(state);\n } catch (error) {\n return this._errorToFailure(error);\n }\n }\n\n private _onDeviceConnect = (data: { device: ConnectorDevice }): void => {\n const device = this._connectorDeviceToDeviceInfo(data.device);\n this._devices.set(device.connectId, device);\n this._emitter.emit(DEVICE.CONNECT, { type: DEVICE.CONNECT, payload: device });\n };\n\n private _onDeviceDisconnect = (data: { connectId: string }): void => {\n this._operations.endByConnectionKey(data.connectId, 'disconnect');\n this._sessions.delete(data.connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(data.connectId);\n this._devices.delete(data.connectId);\n this._emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private _onSupportFeatures = (data: {\n device: ConnectorDevice & { features: Record<string, unknown> };\n }): void => {\n const device = {\n ...this._connectorDeviceToDeviceInfo(data.device),\n features: data.device.features,\n };\n this._emitter.emit(DEVICE.FEATURES, {\n type: DEVICE.FEATURES,\n device,\n payload: { device },\n });\n };\n\n // The one outlet for every connector-raised UI request (PIN, passphrase,\n // button, THP pairing), so the operation is stamped here instead of at each\n // connector call site.\n private _onUiRequest = (data: { type: string; payload?: unknown }): void => {\n const operationId = this._activeOperationId();\n const basePayload =\n data.payload && typeof data.payload === 'object'\n ? (data.payload as Record<string, unknown>)\n : {};\n const attribution = operationId === undefined ? {} : { operationId };\n if (data.type === UI_REQUEST.REQUEST_PASSPHRASE) {\n const connectId =\n typeof basePayload.connectId === 'string' ? basePayload.connectId : undefined;\n const context = connectId\n ? this._passphraseRequestContextByConnectId.get(connectId)\n : undefined;\n this._emitter.emit(\n data.type as keyof HardwareEventMap,\n {\n ...data,\n payload: {\n ...basePayload,\n ...(context?.passphraseState !== undefined\n ? { passphraseState: context.passphraseState }\n : {}),\n ...(context?.useEmptyPassphrase !== undefined\n ? { useEmptyPassphrase: context.useEmptyPassphrase }\n : {}),\n ...attribution,\n },\n } as never\n );\n return;\n }\n // Leave the payload exactly as the connector sent it when there is no\n // operation to name.\n const payload = operationId === undefined ? data.payload : { ...basePayload, ...attribution };\n this._emitter.emit(data.type as keyof HardwareEventMap, { ...data, payload } as never);\n };\n\n private _onUiEvent = (data: ConnectorUiEvent): void => {\n this._emitter.emit('ui-event', data);\n };\n\n private _onThpCredentialsChanged = (data: {\n connectId: string;\n deviceId?: string;\n credentials: Record<string, unknown>[];\n }): void => {\n this._emitter.emit(DEVICE.TREZOR_THP_CREDENTIALS_CHANGED, {\n type: DEVICE.TREZOR_THP_CREDENTIALS_CHANGED,\n payload: data,\n });\n };\n\n private _registerConnectorEvents(): void {\n this._connector.on('device-connect', this._onDeviceConnect);\n this._connector.on('device-disconnect', this._onDeviceDisconnect);\n this._connector.on(DEVICE.FEATURES, this._onSupportFeatures);\n this._connector.on('device-trezor-thp-credentials-changed', this._onThpCredentialsChanged);\n this._connector.on('ui-request', this._onUiRequest);\n this._connector.on('ui-event', this._onUiEvent);\n }\n\n private _unregisterConnectorEvents(): void {\n this._connector.off('device-connect', this._onDeviceConnect);\n this._connector.off('device-disconnect', this._onDeviceDisconnect);\n this._connector.off(DEVICE.FEATURES, this._onSupportFeatures);\n this._connector.off('device-trezor-thp-credentials-changed', this._onThpCredentialsChanged);\n this._connector.off('ui-request', this._onUiRequest);\n this._connector.off('ui-event', this._onUiEvent);\n }\n\n private _connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'trezor',\n model: device.model ?? 'unknown',\n firmwareVersion: 'unknown',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n // The per-device transport is authoritative (a combined USB+BLE\n // connector tags each discovered device); the connector's own\n // connectionType is only a nominal value, so fall back to it for\n // single-transport connectors that don't tag each device.\n connectionType: device.connectionType ?? this._connector.connectionType,\n capabilities: device.capabilities,\n };\n }\n\n private _errorToFailure(error: unknown) {\n const typed = error as {\n code?: unknown;\n message?: string;\n recovery?: unknown;\n params?: unknown;\n };\n // Map hwk-trezor-core's string markers to standard HardwareErrorCodes.\n // The core tags pairing-handshake rejections (e.g. mistyped CodeEntry code)\n // with `code: 'ThpPairingFailed'`; surface it as a proper code, not Unknown.\n if (typed.code === 'ThpPairingFailed') {\n return failure(HardwareErrorCode.ThpPairingFailed, typed.message ?? 'THP pairing failed');\n }\n // Only trust a numeric `code` if it is an actual HardwareErrorCode. A raw\n // WebUSB AbortError carries a DOMException `code: 20`, which is NOT one of\n // ours — fall through to message-based mapping (transferOut/USBDevice abort\n // → TransportError) so it surfaces as a recognizable, retryable transport\n // error instead of Unknown.\n const trustedNumericCode =\n typeof typed.code === 'number' && KNOWN_HARDWARE_ERROR_CODES.has(typed.code)\n ? typed.code\n : undefined;\n const code =\n trustedNumericCode ??\n TrezorAdapter._mapTrezorFailureCode(error) ??\n HardwareErrorCode.UnknownError;\n // Origin: trust one already stamped on the error (a thrown HwkError\n // carries the mapper's context knowledge), otherwise fall back to the\n // shared code→origin table — which returns undefined for the genuinely\n // ambiguous codes instead of guessing.\n const stampedOrigin = (error as { origin?: unknown })?.origin;\n const origin =\n stampedOrigin === 'device' || stampedOrigin === 'transport' || stampedOrigin === 'host'\n ? stampedOrigin\n : defaultOriginForCode(code);\n // Carry the thrower's params across the failure boundary. They are how a\n // caller tells apart two situations that share one code - \"you plugged in\n // a different Trezor\" vs \"the bound one is gone\" both read as\n // DeviceMismatch otherwise.\n const params =\n typed.params && typeof typed.params === 'object'\n ? (typed.params as Record<string, unknown>)\n : undefined;\n return failure(\n code,\n typed.message ?? String(error),\n params,\n origin,\n isHwkRecoveryHint(typed.recovery) ? typed.recovery : undefined\n );\n }\n\n /**\n * Emit `REQUEST_DEVICE_PERMISSION` and await the host's\n * `RECEIVE_DEVICE_PERMISSION` reply (60s budget covers OS prompt + user\n * tap). If the host doesn't wire a handler the wait times out and the\n * operation fails fast.\n *\n * Mirrors LedgerAdapter._ensureDevicePermission so hosts can register a\n * single handler that branches by `payload.transportType` (and optionally\n * the active brand) instead of teaching every adapter its own contract.\n *\n * - no `connectId` → environment-level check (scan / picker)\n * - with `connectId` → device-level check (per-call gating)\n */\n private async _ensureDevicePermission(\n connectId?: string,\n deviceId?: string,\n requestedTransport?: ConnectionType\n ): Promise<void> {\n // No handler? Skip silently so non-permission-aware hosts (and our own\n // unit tests) keep working — Ledger's adapter has a 60s timeout but\n // hardware-wallet flows on web/desktop don't always have a registered\n // listener, and they shouldn't stall for a minute waiting on one.\n if (!this._emitter.listenerCount(UI_REQUEST.REQUEST_DEVICE_PERMISSION)) {\n return;\n }\n const transportType: TransportType = requestedTransport ?? this.activeTransport ?? 'usb';\n\n const operationId = this._activeOperationId();\n const waitPromise = this._uiRegistry.wait<{ granted: boolean; reason?: string }>(\n UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n { timeoutMs: 60_000, operationId }\n );\n\n this._emitter.emit(UI_REQUEST.REQUEST_DEVICE_PERMISSION, {\n type: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n payload: { transportType, connectId, deviceId, operationId },\n });\n\n const { granted } = await waitPromise;\n if (!granted) {\n throw Object.assign(new Error('Device permission denied'), {\n code: HardwareErrorCode.DevicePermissionDenied,\n });\n }\n }\n}\n","import { sha3_256 as sha3Hash } from '@noble/hashes/sha3';\n\nimport { deviceAuthenticityConfig } from './config';\nimport { prepareDeviceAuthenticityData, verifyAuthenticityProof } from './verifyAuthenticityProof';\n\nimport type { DeviceAuthenticityConfig } from './types';\n\nexport { deviceAuthenticityConfig } from './config';\nexport { prepareDeviceAuthenticityData, verifyAuthenticityProof } from './verifyAuthenticityProof';\nexport * from './types';\n\n/** Raw fields taken from a Trezor `AuthenticityProof` message. */\nexport type AuthenticityProof = {\n optiga_certificates: string[];\n optiga_signature: string;\n tropic_certificates?: string[];\n tropic_signature?: string;\n mcu_certificates?: string[];\n mcu_signature?: string;\n};\n\nexport type AuthenticateDeviceResult = {\n /**\n * True only when every layer implemented by this verifier and required by\n * the explicit model policy verified up to a trusted Trezor root CA AND the\n * device signed our challenge:\n * - Optiga (all secure-element models), and\n * - Tropic (T3W1 / Safe 7).\n * This is the currently implemented client policy, not full parity with the\n * latest capability-based Trezor Connect policy. Raw MCU fields remain in the\n * returned proof but are not yet a client-side pass/fail condition.\n * The reward backend must independently verify the same raw proof under its\n * own versioned policy; this client result is only a UX preview.\n */\n verified: boolean;\n /**\n * SHA3-256 of the verified Optiga device-attestation public key. It survives\n * wipe/recovery and has one representation across supported models. Do NOT\n * trust it when `verified` is false — it is then attacker-controlled.\n */\n deviceId?: string;\n /** Raw device attestation public key (hex) from the Optiga device certificate. */\n deviceCertPubKey?: string;\n /** X.509 subject serial number (hex), only present on T3W1 and above. */\n serialNumber?: string;\n rootPubKey?: string;\n caPubKey?: string;\n /**\n * True when the chain matched a DEBUG/staging root key (simulator / dev\n * device). A production accounting flow must reject verified results that\n * have `usedDebugKey === true`.\n */\n usedDebugKey?: boolean;\n /** Failure reason when `verified` is false. */\n error?: string;\n};\n\n// Revocation hook: CA public keys (hex) that must be rejected even if otherwise\n// valid. Empty today; kept so a leaked intermediate CA can be blocked by config\n// rather than a code change. Mirrors @trezor/device-authenticity's blacklist.\nexport const caPubKeyBlacklist: string[] = [];\n\nconst modelConfigOf = (config: DeviceAuthenticityConfig, deviceModel: string) => {\n const modelConfig = config[deviceModel];\n return modelConfig && typeof modelConfig !== 'number' ? modelConfig : undefined;\n};\n\nexport const getRequiredDeviceAuthenticityLayers = (\n deviceModel: string\n): readonly ('optiga' | 'tropic')[] => (deviceModel === 'T3W1' ? ['optiga', 'tropic'] : ['optiga']);\n\nconst isTropicExpected = (deviceModel: string): boolean =>\n getRequiredDeviceAuthenticityLayers(deviceModel).includes('tropic');\n\nconst matchedDebugKey = (\n config: DeviceAuthenticityConfig,\n deviceModel: string,\n rootPubKey?: string\n): boolean => {\n if (!rootPubKey) return false;\n const m = modelConfigOf(config, deviceModel);\n if (!m?.debug) return false;\n return [...(m.debug.rootPubKeysOptiga ?? []), ...(m.debug.rootPubKeysTropic ?? [])].includes(\n rootPubKey\n );\n};\n\n/**\n * Verify a Trezor `AuthenticityProof` against a challenge and derive a stable\n * per-device id. `challenge` must be the exact random bytes sent in the\n * `AuthenticateDevice` request. Never throws — malformed input from a malicious\n * device is folded into `{ verified: false }`.\n */\nexport const authenticateDeviceFromProof = ({\n proof,\n challenge,\n deviceModel,\n config = deviceAuthenticityConfig,\n allowDebugKeys,\n}: {\n proof: AuthenticityProof;\n challenge: Buffer;\n deviceModel: string;\n config?: DeviceAuthenticityConfig;\n allowDebugKeys?: boolean;\n}): AuthenticateDeviceResult => {\n try {\n const signedData = prepareDeviceAuthenticityData({ payload: challenge });\n const common = { signedData, deviceModel, config, allowDebugKeys, caPubKeyBlacklist };\n\n // 1) Optiga is required on every attestation-capable model.\n const { optiga_certificates: optigaCertificates, optiga_signature: optigaSignature } = proof;\n if (!optigaSignature || !optigaCertificates?.length) {\n return { verified: false, error: 'RESPONSE_PAYLOAD_MISSING' };\n }\n const optiga = verifyAuthenticityProof({\n ...common,\n proofType: 'optiga',\n certificates: optigaCertificates,\n signature: optigaSignature,\n });\n if (!optiga.valid) {\n return {\n verified: false,\n deviceCertPubKey: optiga.deviceCertPubKey,\n caPubKey: optiga.caPubKey,\n rootPubKey: optiga.rootPubKey,\n error: optiga.error,\n };\n }\n\n // 2) Trezor Connect requires the independent Tropic proof on T3W1.\n let usedDebugKey = matchedDebugKey(config, deviceModel, optiga.rootPubKey);\n if (isTropicExpected(deviceModel)) {\n const { tropic_certificates: tropicCertificates, tropic_signature: tropicSignature } = proof;\n if (!tropicSignature || !tropicCertificates?.length) {\n return { verified: false, error: 'RESPONSE_PAYLOAD_MISSING' };\n }\n const tropic = verifyAuthenticityProof({\n ...common,\n proofType: 'tropic',\n certificates: tropicCertificates,\n signature: tropicSignature,\n });\n if (!tropic.valid) {\n return { verified: false, error: tropic.error };\n }\n usedDebugKey = usedDebugKey || matchedDebugKey(config, deviceModel, tropic.rootPubKey);\n }\n\n const deviceId = Buffer.from(\n sha3Hash(Uint8Array.from(Buffer.from(optiga.deviceCertPubKey, 'hex')))\n ).toString('hex');\n\n return {\n verified: true,\n deviceId,\n deviceCertPubKey: optiga.deviceCertPubKey,\n serialNumber: optiga.serialNumber,\n rootPubKey: optiga.rootPubKey,\n caPubKey: optiga.caPubKey,\n usedDebugKey,\n };\n } catch (error) {\n // A malicious device can return a malformed certificate that throws deep in\n // the parser; never let that escape as a rejected promise.\n return {\n verified: false,\n error: `RESPONSE_MALFORMED: ${(error as Error)?.message ?? 'parse error'}`,\n };\n }\n};\n","import type { DeviceAuthenticityConfig } from './types';\n\n/**\n * Trezor manufacturing root CA public keys, per internal model.\n * Authoritative upstream source (firmware):\n * https://github.com/trezor/trezor-firmware/blob/main/core/embed/projects/prodtest/cmd/hsm_keys.h\n * Mirrored from @trezor/device-authenticity `deviceAuthenticityConfig`.\n *\n * Devices without a secure element (T1B1, T2T1) do not support AuthenticateDevice\n * and are therefore absent from this config.\n */\nexport const deviceAuthenticityConfig: DeviceAuthenticityConfig = {\n version: 2,\n T2B1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '04ca97480ac0d7b1e6efafe518cd433cec2bf8ab9822d76eafd34363b55d63e60380bff20acc75cde03cffcb50ab6f8ce70c878e37ebc58ff7cca0a83b16b15fa5',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T3B1\n '047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a',\n ],\n },\n },\n T3B1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '045b5c3fdd01f3602092834209b86df0ca86a9faf25cac35c73bf6237d66eb21eafcec3706f1ccd5eb4cc7f2fa1751213eccb1c78389afba89a5788ff31ee46a5d',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T2B1\n '047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a',\n ],\n },\n },\n T3T1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '041854b27fb1d9f65abb66828e78c9dc0ca301e66081ab0c6a4d104f9df1cd0ad5a7c75f77a8c092f55cf825d2abaf734f934c9394d5e75f75a5a06a5ee9be93ae',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256\n '04e48b69cd7962068d3cca3bcc6b1747ef496c1e28b5529e34ad7295215ea161dbe8fb08ae0479568f9d2cb07630cb3e52f4af0692102da5873559e45e9fa72959',\n ],\n },\n },\n T3W1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '040dde0d3e0d4da593fac6fd02a461d0e7eef238aca55c7c50b4e9ec37f3873303b6429ef1c9b78b4411a7dcbbc5dde5225979c1c2da3b073e82b1ed3f5f9825bb',\n // upstream: DEV_AUTH_ROOT_PROD_BACKUP_P256\n '04c6a673af4ec44b10441b1d78676e15173ad0e36df9f7f2fa1cd819955f20fe32917b60da5fed3b3aa54a9ab8b3ed27d198b3768cad26eef5935cd87af0af065e',\n ],\n rootPubKeysTropic: [\n // upstream: DEV_AUTH_ROOT_PROD_ED25519\n '59237acd17134061d655b3f8d624573ca06ce8d862f38ba4e05140ce1d3d609d',\n // upstream: DEV_AUTH_ROOT_PROD_BACKUP_ED25519\n '5612606584ee7e0bc313b13f7ac94156bb4cb75bd77585ddbe579301306e85f1',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256\n '04521192e173a9da4e3023f747d836563725372681eba3079c56ff11b2fc137ab189eb4155f371127651b5594f8c332fc1e9c0f3b80d4212822668b63189706578',\n // upstream: DEV_AUTH_ROOT_STAGING_P256\n '0465e88f9b2cea67e8364f0cfcfacd500af24e9040b357beee629ccc4fce1704d1a7ef7284f387708f92ef14600e2caad6894016fee819d623b95d66210c3e7519',\n ],\n rootPubKeysTropic: [\n // upstream: DEV_AUTH_ROOT_STAGING_ED25519\n 'cd318dc8405ae4f4144e3284dcb7b0cb0f0c2195c2ca14a0f6fccd9104e32a4b',\n ],\n },\n },\n};\n","import type { Oid, ParsedCertificate } from './x509certificate';\n\nexport const findSubjectContentByOid = (\n deviceCert: ParsedCertificate,\n oid: Oid\n): Uint8Array | null => {\n const subjectItems = deviceCert.tbsCertificate.subject;\n const matchedItem = subjectItems.find(({ algorithmOid }) => algorithmOid === oid);\n if (!matchedItem || !matchedItem.parameters) return null;\n\n return matchedItem.parameters.asn1.contents;\n};\n","import { type parseCertificate } from './x509certificate';\n\n// Check that this certificate is a valid Trezor CA.\n// KeyUsage must be present and allow certificate signing.\n// BasicConstraints must be present, have the cA flag and a pathLenConstraint.\n// Any unrecognized non-critical extension is allowed. Any unrecognized critical extension is disallowed.\nexport const validateCaCertExtensions = (\n cert: ReturnType<typeof parseCertificate>,\n pathLen: number\n) => {\n let hasKeyUsage = false;\n let hasBasicConstraints = false;\n cert.tbsCertificate.extensions.forEach(ext => {\n if (ext.key === 'keyUsage') {\n if (ext.keyCertSign !== '1') {\n throw new Error(`CA keyCertSign not set`);\n }\n hasKeyUsage = true;\n } else if (ext.key === 'basicConstraints') {\n if (!ext.cA) {\n throw new Error(`CA basicConstraints.cA not set`);\n }\n if (typeof ext.pathLenConstraint !== 'number') {\n throw new Error('CA basicConstraints.pathLenConstraint not set');\n }\n if (ext.pathLenConstraint < pathLen) {\n throw new Error('Issuer was not permitted to issue certificate');\n }\n hasBasicConstraints = true;\n } else if (ext.critical) {\n throw new Error(`Unknown critical extension ${ext.key} in CA certificate`);\n }\n });\n\n if (!hasKeyUsage || !hasBasicConstraints) {\n throw new Error(\n `CA missing extensions keyUsage: ${hasKeyUsage}, basicConstraints: ${hasBasicConstraints}`\n );\n }\n};\n","import { ed25519 } from '@noble/curves/ed25519';\nimport { p256 } from '@noble/curves/p256';\nimport { sha256 } from '@noble/hashes/sha256';\n\nimport { type AlgorithmName, fixSignature } from './x509certificate';\n\nexport type VerifySignature = (\n rawKey: Uint8Array,\n data: Uint8Array,\n signature: Uint8Array\n) => boolean;\n\n// P-256 (secp256r1) ECDSA over SHA-256. Hardware attestation signatures are NOT\n// guaranteed to be low-S normalized, so lowS must be disabled or valid signatures\n// would be rejected. `fixSignature` repairs the 1-in-256 malformed Optiga DER encoding.\nexport const verifySignatureP256: VerifySignature = (rawKey, data, signature) => {\n try {\n const sig = p256.Signature.fromDER(Buffer.from(fixSignature(signature)).toString('hex'));\n\n return p256.verify(sig.toBytes('compact'), sha256(data), rawKey, { lowS: false });\n } catch {\n // invalid inputs (e.g. an Ed25519 signature with a P-256 key) are an\n // unsuccessful verification, not a runtime error\n return false;\n }\n};\n\nexport const verifySignatureEd25519: VerifySignature = (rawKey, data, signature) => {\n try {\n return ed25519.verify(signature, data, rawKey);\n } catch {\n return false;\n }\n};\n\nexport const getVerifyFn = (algorithmName: AlgorithmName): VerifySignature => {\n if (algorithmName === 'P-256') return verifySignatureP256;\n if (algorithmName === 'Ed25519') return verifySignatureEd25519;\n throw new Error(`Unsupported signature algorithm: ${algorithmName}`);\n};\n","/**\n * Parse an x509 certificate returned from Trezor (AuthenticityProof) from DER format.\n * Ported from @trezor/device-authenticity (self-contained, no external deps).\n * inspired by https://blog.engelke.com/2014/10/21/web-crypto-and-x-509-certificates/\n */\n\ninterface Asn1 {\n cls: number; // ASN.1 class of the object.\n tag: number; // ASN.1 object type.\n structured: boolean; // Structured objects are encoded ASN.1 objects. Other objects (primitive) values depends on the tag and class\n byteLength: number; // value size\n contents: Uint8Array; // byte array containing the object value.\n raw: Uint8Array; // original byte array\n}\n\ntype OneOrTwoNumbers = `${number}` | `${number}.${number}`;\n// type that allows between 4 to 8 numbers to specify an OID\nexport type Oid = `${OneOrTwoNumbers}.${OneOrTwoNumbers}.${OneOrTwoNumbers}.${OneOrTwoNumbers}`;\n\n// algorithms supported to verify certificates and signatures\nexport type AlgorithmName = 'P-256' | 'Ed25519' | 'MLDSA44' | 'unknown';\n\ntype Extension =\n | {\n key: 'keyUsage';\n critical?: boolean;\n keyCertSign: '0' | '1';\n }\n | {\n key: 'basicConstraints';\n critical?: boolean;\n cA: boolean;\n pathLenConstraint?: number;\n }\n | (Asn1 & {\n key: Oid;\n critical?: boolean;\n });\n\nconst parseOidToAlgorithmName = (oid: Oid): AlgorithmName => {\n if (oid === '1.2.840.10045.4.3.2') return 'P-256'; // https://oid-base.com/get/1.2.840.10045.4.3.2\n if (oid === '1.3.101.112') return 'Ed25519'; // https://oid-base.com/get/1.3.101.112\n if (oid === '2.16.840.1.101.3.4.3.17') return 'MLDSA44'; // https://oid-base.com/get/2.16.840.1.101.3.4.3.17\n\n return 'unknown';\n};\n\nconst derToAsn1 = (byteArray: Uint8Array): Asn1 => {\n let position = 0;\n\n function getTag() {\n let tag = byteArray[0] & 0x1f;\n position += 1;\n if (tag === 0x1f) {\n tag = 0;\n while (byteArray[position] >= 0x80) {\n tag = tag * 128 + byteArray[position] - 0x80;\n position += 1;\n }\n tag = tag * 128 + byteArray[position] - 0x80;\n position += 1;\n }\n\n return tag;\n }\n\n function getLength() {\n let length = 0;\n\n if (byteArray[position] < 0x80) {\n length = byteArray[position];\n position += 1;\n } else {\n const numberOfDigits = byteArray[position] & 0x7f;\n position += 1;\n length = 0;\n for (let i = 0; i < numberOfDigits; i++) {\n length = length * 256 + byteArray[position];\n position += 1;\n }\n }\n\n return length;\n }\n\n const cls = (byteArray[0] & 0xc0) / 64;\n const structured = (byteArray[0] & 0x20) === 0x20;\n const tag = getTag();\n\n if (byteArray[position] === 0x80) {\n // DER forbids indefinite length encoding. You must use the definite length encoding (that is, with the length specified at the beginning).\n // https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/\n throw new Error('Unsupported length encoding');\n }\n\n const length = getLength(); // As encoded, which may be special value 0\n const byteLength = position + length;\n const contents = byteArray.subarray(position, byteLength);\n\n const raw = byteArray.subarray(0, byteLength); // May not be the whole input array\n\n return {\n cls,\n tag,\n structured,\n byteLength,\n contents,\n raw,\n };\n};\n\nconst derToAsn1List = (byteArray: Uint8Array) => {\n const result = [];\n let nextPosition = 0;\n while (nextPosition < byteArray.length) {\n const nextPiece = derToAsn1(byteArray.subarray(nextPosition));\n result.push(nextPiece);\n nextPosition += nextPiece.byteLength;\n }\n\n return result;\n};\n\nconst derBitStringValue = (byteArray: Uint8Array) => ({\n unusedBits: byteArray[0],\n bytes: byteArray.subarray(1),\n});\n\nconst parseSignatureValue = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 3 || asn1.structured) {\n throw new Error('Bad signature value. Not a BIT STRING.');\n }\n\n return {\n asn1,\n bits: derBitStringValue(asn1.contents),\n };\n};\n\n// Optiga may produce a malformed signature with probability 1 in 256.\n// https://github.com/trezor/trezor-firmware/issues/3411\nexport const fixSignature = (byteArray: Uint8Array) => {\n const asn1 = derToAsn1(byteArray);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad signature. Not a SEQUENCE.');\n }\n\n const items = derToAsn1List(asn1.contents);\n let newLength = 0;\n const fixedItems = items.map(chunk => {\n // find first significant byte\n const index = chunk.contents.findIndex(value => value > 0x00);\n const data = chunk.contents.subarray(index);\n // According to the DER-encoding rules, the integers are supposed to be prefixed with a 0x00 byte\n // if **and only if** the most significant byte is >= 0x80\n const offset = data[0] >= 0x80 ? 1 : 0;\n // create replacement for chunk\n const chunkLength = data.length + offset;\n const newChunk = new Uint8Array(chunkLength + 2);\n // set first two bytes: original value and new length of the chunk\n newChunk.set([chunk.raw[0], chunkLength]);\n // optionally add 0\n if (offset > 0) {\n newChunk.set([0], 2);\n }\n // fill new chunk with data\n newChunk.set(data, 2 + offset);\n newLength += newChunk.length;\n\n return newChunk;\n });\n\n // create replacement for sequence object\n const signature = new Uint8Array(newLength + 2);\n // set two first bytes: original value and new length of all chunks\n signature.set([byteArray[0], newLength]);\n // fill new sequence with fixed items\n let signatureOffset = 2;\n fixedItems.forEach(item => {\n signature.set(item, signatureOffset);\n\n signatureOffset += item.length;\n });\n\n return signature;\n};\n\nconst derObjectIdentifierValue = (byteArray: Uint8Array) => {\n let oid = `${Math.floor(byteArray[0] / 40)}.${byteArray[0] % 40}`;\n let position = 1;\n while (position < byteArray.length) {\n let nextInteger = 0;\n while (byteArray[position] >= 0x80) {\n nextInteger = nextInteger * 0x80 + (byteArray[position] & 0x7f);\n position += 1;\n }\n nextInteger = nextInteger * 0x80 + byteArray[position];\n position += 1;\n oid += `.${nextInteger}`;\n }\n\n return oid as Oid;\n};\n\n/*\n * AlgorithmIdentifier ::= SEQUENCE {\n * algorithm OBJECT IDENTIFIER,\n * parameters ANY DEFINED BY algorithm OPTIONAL\n * }\n */\nconst parseAlgorithmIdentifier = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad algorithm identifier. Not a SEQUENCE.');\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length > 2) {\n throw new Error('Bad algorithm identifier. Contains too many child objects.');\n }\n const encodedAlgorithm = pieces[0];\n if (encodedAlgorithm.cls !== 0 || encodedAlgorithm.tag !== 6 || encodedAlgorithm.structured) {\n throw new Error('Bad algorithm identifier. Does not begin with an OBJECT IDENTIFIER.');\n }\n const algorithmOid = derObjectIdentifierValue(encodedAlgorithm.contents);\n const algorithmName = parseOidToAlgorithmName(algorithmOid);\n\n return {\n asn1,\n algorithmOid,\n algorithmName,\n parameters: pieces.length === 2 ? { asn1: pieces[1] } : null,\n };\n};\n\n/*\n * Name ::= SEQUENCE {\n * algorithm OBJECT IDENTIFIER,\n * parameters ANY DEFINED BY algorithm OPTIONAL\n * }\n */\nexport const parseName = (asn1: Asn1) =>\n // SEQUENCE > SET > SEQUENCE\n derToAsn1List(asn1.contents).map(item => {\n const attrSet = derToAsn1(item.contents);\n\n return parseAlgorithmIdentifier(attrSet);\n });\n\n/*\n * SubjectPublicKeyInfo ::= SEQUENCE {\n * algorithm AlgorithmIdentifier,\n * subjectPublicKey BIT STRING\n * }\n */\nconst parseSubjectPublicKeyInfo = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad SPKI. Not a SEQUENCE.');\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length !== 2) {\n throw new Error('Bad SubjectPublicKeyInfo. Wrong number of child objects.');\n }\n\n return {\n asn1,\n algorithm: parseAlgorithmIdentifier(pieces[0]),\n bits: derBitStringValue(pieces[1].contents),\n };\n};\n\n/*\n * Time ::= CHOICE {\n * utcTime UTCTime,\n * generalTime GeneralizedTime\n * }\n * NOTE: UTC and generalized times may both appear. (generalized > 2050)\n */\nconst parseUtcTime = (time: Asn1) => {\n // tag: 23 = UTCTime (YYMMDDhhmmZ);\n // tag: 24 = GeneralizedTime (YYYYMMDDhhmmZ)\n let offset = 4;\n let yearOffset = 0;\n if (time.tag === 23) {\n offset = 2;\n yearOffset = 2000;\n }\n const utc = Buffer.from(time.contents).toString();\n const year = yearOffset + Number(utc.substring(0, offset));\n const month = Number(utc.substring(offset, offset + 2)) - 1;\n const day = Number(utc.substring(offset + 2, offset + 4));\n const hour = Number(utc.substring(offset + 4, offset + 6));\n const minute = Number(utc.substring(offset + 6, offset + 8));\n\n const date = new Date();\n date.setUTCFullYear(year, month, day);\n date.setUTCHours(hour, minute, 0);\n\n return date;\n};\n\n/*\n * Validity ::= SEQUENCE {\n * from Time,\n * to Time\n * }\n */\nconst parseValidity = (asn1: Asn1) => {\n const [from, to] = derToAsn1List(asn1.contents);\n\n return {\n from: parseUtcTime(from),\n to: parseUtcTime(to),\n };\n};\n\n/*\n * https://www.alvestrand.no/objectid/2.5.29.html\n * Extensions ::= SEQUENCE {\n * extnID OBJECT IDENTIFIER,\n * critical BOOLEAN OPTIONAL,\n * extnValue OCTET STRING\n * }\n */\nconst parseExtensions = (data: Asn1) => {\n const asn1 = derToAsn1(data.contents);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be a Extension. Wrong data type.\");\n }\n\n const readBoolean = (value?: Asn1) => {\n if (!value) return false;\n if (value.cls !== 0 || value.tag !== 1 || value.contents.length !== 1 || value.structured) {\n throw new Error(\"This can't be a boolean. Wrong data type.\");\n }\n if (![0x00, 0xff].includes(value.contents[0])) {\n throw new Error('Invalid boolean value.');\n }\n\n return value.contents[0] === 0xff;\n };\n\n const readBitString = (uint8Array: Uint8Array) => {\n const buffer = Buffer.from(uint8Array);\n const tag = buffer.readUInt8(0);\n if (tag !== 3) {\n throw new Error(\"This can't be a bit string. Wrong data type.\");\n }\n const length = buffer.readUInt8(1);\n const unusedBits = buffer.readUInt8(2);\n const bitStringBytes = buffer.subarray(3, 3 + length - 1); // -1 because the length includes the unusedBits byte\n const bitString = bitStringBytes.reduce(\n (str, byte) => str + byte.toString(2).padStart(8, '0'),\n ''\n );\n\n return bitString.slice(0, bitString.length - unusedBits) as '01';\n };\n\n const readInteger = (value?: Asn1) => {\n if (!value) return undefined;\n if (value.cls !== 0 || value.tag !== 2 || value.contents.length !== 1 || value.structured) {\n throw new Error(\"This can't be a integer. Wrong data type.\");\n }\n\n return Buffer.from(value.contents).readInt8();\n };\n\n const extensions: Extension[] = [];\n derToAsn1List(asn1.contents).forEach(item => {\n const [id, ...pieces] = derToAsn1List(item.contents);\n if (id.cls !== 0 || id.tag !== 6 || id.structured) {\n throw new Error('Bad extension. Does not begin with an OBJECT IDENTIFIER.');\n }\n\n const algorithm = derObjectIdentifierValue(id.contents);\n const critical = pieces.length > 1 ? readBoolean(pieces[0]) : false;\n const extnValue = pieces.length > 1 ? pieces[1] : pieces[0];\n if (extnValue.cls !== 0 || extnValue.tag !== 4 || extnValue.structured) {\n throw new Error(\"This can't be a octet string. Wrong data type.\");\n }\n\n if (algorithm === '2.5.29.15') {\n // https://www.alvestrand.no/objectid/2.5.29.15.html\n extensions.push({\n key: 'keyUsage',\n critical,\n keyCertSign: readBitString(extnValue.contents)[5] as '0' | '1',\n });\n } else if (algorithm === '2.5.29.19') {\n // https://www.alvestrand.no/objectid/2.5.29.19.html\n const fields = derToAsn1List(derToAsn1(extnValue.contents).contents);\n const ca = fields.length > 0 && fields[0].tag === 1 ? fields[0] : undefined;\n const len = fields.length > 0 && fields[0].tag === 2 ? fields[0] : fields[1];\n\n extensions.push({\n key: 'basicConstraints',\n critical,\n cA: readBoolean(ca),\n pathLenConstraint: readInteger(len),\n });\n } else {\n extensions.push({\n key: algorithm,\n critical,\n ...item,\n });\n }\n });\n\n return extensions;\n};\n\n/*\n * TBSCertificate ::= SEQUENCE {\n * version [0] EXPLICIT Version DEFAULT v1,\n * serialNumber CertificateSerialNumber,\n * signature AlgorithmIdentifier,\n * issuer Name[],\n * validity Validity,\n * subject Name[],\n * subjectPublicKeyInfo SubjectPublicKeyInfo,\n * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,\n * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,\n * extensions [3] EXPLICIT Extensions OPTIONAL\n * }\n */\nconst parseTBSCertificate = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be a TBSCertificate. Wrong data type.\");\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length < 7) {\n throw new Error('Bad TBS Certificate. There are fewer than the seven required children.');\n }\n\n return {\n asn1,\n version: pieces[0],\n serialNumber: pieces[1],\n signature: parseAlgorithmIdentifier(pieces[2]),\n issuer: pieces[3],\n validity: parseValidity(pieces[4]),\n subject: parseName(pieces[5]),\n subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),\n extensions: parseExtensions(pieces[7]),\n };\n};\n\n/*\n * Certificate ::= SEQUENCE {\n * tbsCertificate TBSCertificate,\n * signatureAlgorithm AlgorithmIdentifier,\n * signatureValue BIT STRING\n * }\n */\nexport const parseCertificate = (byteArray: Uint8Array) => {\n const asn1 = derToAsn1(byteArray);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be an X.509 certificate. Wrong data type.\");\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length !== 3) {\n throw new Error('Certificate contains more than the three specified children.');\n }\n\n return {\n asn1,\n tbsCertificate: parseTBSCertificate(pieces[0]),\n signatureAlgorithm: parseAlgorithmIdentifier(pieces[1]),\n signatureValue: parseSignatureValue(pieces[2]),\n };\n};\n\nexport type ParsedCertificate = ReturnType<typeof parseCertificate>;\n","import { findSubjectContentByOid } from './findSubjectContentByOid';\nimport {\n type DeviceAuthenticityConfig,\n type VerifyAuthenticityProofParams,\n type VerifyAuthenticityProofResult,\n} from './types';\nimport { validateCaCertExtensions } from './validateCaCertExtensions';\nimport { getVerifyFn } from './verifySignatures';\nimport { type ParsedCertificate, parseCertificate } from './x509certificate';\n\nconst getChunkSize = (byteLength: number): Uint8Array => {\n if (byteLength < 0xfd) return Uint8Array.from([byteLength]);\n if (byteLength <= 0xffff) {\n const b = Buffer.alloc(3);\n b[0] = 0xfd;\n b.writeUInt16LE(byteLength, 1);\n\n return Uint8Array.from(b);\n }\n const b = Buffer.alloc(5);\n b[0] = 0xfe;\n b.writeUInt32LE(byteLength, 1);\n\n return Uint8Array.from(b);\n};\n\n// Compose the data against which the signatures are verified: each chunk is\n// prefixed with its compact-size length. Matches the firmware's signed payload.\nexport const prepareDeviceAuthenticityData = ({\n payload,\n prefix = 'AuthenticateDevice:',\n}: {\n payload: Buffer | Buffer[];\n prefix?: string;\n}): Uint8Array => {\n const chunks = [\n Uint8Array.from(Buffer.from(prefix)),\n ...(Array.isArray(payload) ? payload : [payload]).map(chunk => Uint8Array.from(chunk)),\n ];\n const framed = chunks.flatMap(chunk => [getChunkSize(chunk.byteLength), chunk]);\n const result = new Uint8Array(framed.reduce((total, chunk) => total + chunk.byteLength, 0));\n let offset = 0;\n for (const chunk of framed) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n};\n\nconst getRootPubKeys = ({\n config,\n deviceModel,\n proofType,\n allowDebugKeys,\n}: {\n config: DeviceAuthenticityConfig;\n deviceModel: string;\n proofType: 'optiga' | 'tropic';\n allowDebugKeys?: boolean;\n}): string[] => {\n const modelConfig = config[deviceModel];\n if (!modelConfig || typeof modelConfig === 'number') {\n throw new Error(`Pubkeys for ${deviceModel} not found in config`);\n }\n const prod =\n proofType === 'optiga'\n ? modelConfig.rootPubKeysOptiga ?? []\n : modelConfig.rootPubKeysTropic ?? [];\n if (!allowDebugKeys) return prod;\n\n return [\n ...prod,\n ...(proofType === 'optiga'\n ? modelConfig.debug?.rootPubKeysOptiga ?? []\n : modelConfig.debug?.rootPubKeysTropic ?? []),\n ];\n};\n\nconst matchRootPubKeyToCertificate = ({\n cert,\n allRootPubKeys,\n}: {\n cert: ParsedCertificate;\n allRootPubKeys: string[];\n}): string | undefined => {\n const verifySignatureFn = getVerifyFn(cert.signatureAlgorithm.algorithmName);\n\n return allRootPubKeys.find(rootPubKey =>\n verifySignatureFn(\n Uint8Array.from(Buffer.from(rootPubKey, 'hex')),\n cert.tbsCertificate.asn1.raw,\n cert.signatureValue.bits.bytes\n )\n );\n};\n\n// Get internal model name from the device cert Subject (OID 2.5.4.3), e.g. 'T2B1'.\nconst parseModelFromDeviceCertSubject = (deviceCert: ParsedCertificate) => {\n const modelDescriptionBytes = findSubjectContentByOid(deviceCert, '2.5.4.3');\n if (modelDescriptionBytes === null) return null;\n\n // the whole string is e.g. 'T3W1 Trezor Safe 7', only the first 4 chars are the model\n return Buffer.from(modelDescriptionBytes.subarray(0, 4)).toString();\n};\n\n// Get serial number from the device cert Subject (OID 2.5.4.5). Only present on T3W1 and above.\nconst parseSerialNumberFromDeviceCert = (deviceCert: ParsedCertificate) => {\n const serialNumber = findSubjectContentByOid(deviceCert, '2.5.4.5');\n if (serialNumber === null) return undefined;\n\n return Buffer.from(serialNumber).toString('hex');\n};\n\n/**\n * Verifies the signing scheme: rootPubKey → CA pub key → device key → signature of prefixed challenge.\n * Returns the per-device attestation public key (`deviceCertPubKey`) on success.\n */\nexport const verifyAuthenticityProof = ({\n proofType,\n certificates,\n signature,\n signedData,\n deviceModel,\n config,\n allowDebugKeys,\n caPubKeyBlacklist = [],\n}: VerifyAuthenticityProofParams): VerifyAuthenticityProofResult => {\n const allRootPubKeys = getRootPubKeys({\n config,\n deviceModel,\n proofType,\n allowDebugKeys,\n });\n\n const parsedCertificates = certificates.map(c =>\n parseCertificate(new Uint8Array(Buffer.from(c, 'hex')))\n );\n\n const firstCertAlgName = parsedCertificates[0]?.signatureAlgorithm.algorithmName;\n // This mirrors Trezor Connect's production policy: Optiga uses P-256 and\n // Safe 7's additional Tropic proof uses Ed25519. MCU/ML-DSA is not a separate\n // client-side pass/fail condition.\n const expectedAlgorithmName = proofType === 'optiga' ? 'P-256' : 'Ed25519';\n if (firstCertAlgName !== expectedAlgorithmName) {\n return { valid: false, error: 'RESPONSE_MALFORMED' };\n }\n if (parsedCertificates.length !== 2) {\n return { valid: false, error: 'RESPONSE_MALFORMED' };\n }\n\n const [deviceCert, caCert] = parsedCertificates;\n const deviceCertPubKey = Buffer.from(\n deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes\n ).toString('hex');\n\n const deviceCertAlgName = deviceCert.signatureAlgorithm.algorithmName;\n const caCertAlgName = caCert.signatureAlgorithm.algorithmName;\n if (deviceCertAlgName !== caCertAlgName) {\n return { valid: false, deviceCertPubKey, error: 'RESPONSE_MALFORMED' };\n }\n\n validateCaCertExtensions(caCert, 0); // pathLenConstraint is always 0 (single CA cert, no chain)\n const verifySignatureFn = getVerifyFn(deviceCertAlgName);\n\n // 1) CA certificate must be signed by one of the trusted root pub keys.\n const caPubKeyBytes = caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes;\n const caPubKey = Buffer.from(caPubKeyBytes).toString('hex');\n const rootPubKeyMatch = matchRootPubKeyToCertificate({ allRootPubKeys, cert: caCert });\n if (rootPubKeyMatch === undefined) {\n return { valid: false, caPubKey, deviceCertPubKey, error: 'ROOT_PUBKEY_NOT_FOUND' };\n }\n // Revocation: reject a specific (e.g. leaked) intermediate CA even if it chains\n // to a trusted root.\n if (caPubKeyBlacklist.includes(caPubKey)) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'CA_PUBKEY_BLACKLISTED',\n };\n }\n // Both the CA and the device leaf must be currently valid: neither cert's\n // notBefore may be in the future, and neither may already be past notAfter.\n // An expired link in the chain must not still verify as trusted.\n const now = Date.now();\n const isWithinValidity = (validity: { from: Date; to: Date }) =>\n validity.from.getTime() <= now && now <= validity.to.getTime();\n if (\n !isWithinValidity(caCert.tbsCertificate.validity) ||\n !isWithinValidity(deviceCert.tbsCertificate.validity)\n ) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'CERTIFICATE_EXPIRED',\n };\n }\n\n // 2) Device model in the certificate must match the connected device.\n const modelFromSubject = parseModelFromDeviceCertSubject(deviceCert);\n if (modelFromSubject !== deviceModel) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_MODEL',\n };\n }\n\n // 3) Device certificate must be signed by the CA pub key.\n const isDeviceCertValid = verifySignatureFn(\n Uint8Array.from(caPubKeyBytes),\n deviceCert.tbsCertificate.asn1.raw,\n deviceCert.signatureValue.bits.bytes\n );\n if (!isDeviceCertValid) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_CERTIFICATE',\n };\n }\n\n // 4) The challenge signature must be produced by the device key.\n const isSignatureValid = verifySignatureFn(\n Uint8Array.from(deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes),\n signedData,\n Uint8Array.from(Buffer.from(signature, 'hex'))\n );\n if (!isSignatureValid) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_SIGNATURE',\n };\n }\n\n return {\n valid: true,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n serialNumber: parseSerialNumberFromDeviceCert(deviceCert),\n };\n};\n","/**\n * SDK-global event bus. Per-runtime singleton; hosts forward events over their\n * own IPC when the adapter runs in an offscreen/background split.\n */\n\nexport type SdkLogEvent = {\n type: 'log';\n level: 'debug' | 'info' | 'warn' | 'error';\n /** Pre-stringified payload. */\n message: string;\n};\n\nexport type SdkEvent = SdkLogEvent;\n\nexport type SdkEventListener = (event: SdkEvent) => void;\n\nconst listeners = new Set<SdkEventListener>();\n\nexport function onSdkEvent(listener: SdkEventListener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function offSdkEvent(listener: SdkEventListener): void {\n listeners.delete(listener);\n}\n\nexport function emitSdkEvent(event: SdkEvent): void {\n if (listeners.size === 0) return;\n for (const listener of listeners) {\n try {\n listener(event);\n } catch {\n // Logging subscribers must not affect SDK execution.\n }\n }\n}\n\nexport function emitLog(level: SdkLogEvent['level'], ...args: unknown[]): void {\n if (listeners.size === 0) return;\n const message = args.map(a => (typeof a === 'string' ? a : safeStringify(a))).join(' ');\n emitSdkEvent({ type: 'log', level, message });\n}\n\nfunction safeStringify(value: unknown): string {\n if (value instanceof Error) {\n return value.stack ? `${value.message}\\n${value.stack}` : value.message;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n","import { emitLog } from './sdkEventBus';\n\nexport function debugLog(...args: unknown[]): void {\n emitLog('debug', ...args);\n}\n\nexport function debugError(...args: unknown[]): void {\n emitLog('error', ...args);\n}\n","/**\n * The one place a Trezor device-queue key is derived.\n *\n * Three call sites have to agree on it or a cancel misses its target: the job\n * `enqueue` in `_callMethod` / `getPassphraseState`, the bundle-wide cancel\n * scope in `allNetworkGetAddress`, and `cancel()`. An operation id wins when\n * there is one, because a call pinned to an operation is queued under it.\n */\nexport function trezorQueueKey({\n operationId,\n connectId,\n}: {\n operationId?: string;\n connectId?: string;\n}): string {\n return operationId || connectId || '';\n}\n","import type { EvmEthereumDefinitions } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Opt-in helpers for fetching Trezor Ethereum \"definitions\" — the SatoshiLabs-\n * signed network/token metadata a Trezor device uses to render friendly names\n * for chains and tokens that are NOT built into firmware.\n *\n * IMPORTANT — the SDK signing methods (evmSignTransaction / evmGetAddress / …)\n * NEVER call these. A local hardware operation must not silently become a\n * third-party network request (see PR #824 review). The caller decides whether,\n * when, and where to fetch, then passes the result into the sign params as\n * `ethereumDefinitions`. When omitted, the device falls back to a generic\n * confirmation screen and signing still completes.\n *\n * Cross-process note: `fetchImpl` is a FUNCTION and cannot be serialized across\n * an IPC / postMessage boundary. Call these helpers in a network-capable\n * process and send only the resulting hex strings to the process that talks\n * to the device. Use `baseUrl` (a string) to route through your own\n * controlled proxy instead of hitting data.trezor.io directly.\n */\n\n/** Default upstream (Trezor). Override with `baseUrl` to use your own proxy. */\nexport const DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL =\n 'https://data.trezor.io/firmware/eth-definitions';\n\n/** Timeout so a hung host can't stall the signing flow. */\nexport const DEFINITIONS_FETCH_TIMEOUT_MS = 20_000;\n\n/** Race a thunk against a deadline. Generic so it works with any FetchLike on\n * RN/Hermes; a timeout stops awaiting but does not cancel the socket. */\nexport async function runWithTimeout<T>(\n run: () => Promise<T>,\n timeoutMs: number = DEFINITIONS_FETCH_TIMEOUT_MS\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`definitions fetch timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n });\n try {\n return await Promise.race([run(), deadline]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nexport type FetchLike = (url: string) => Promise<{\n status: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n}>;\n\nexport type FetchEthereumDefinitionsParams = {\n chainId?: number;\n slip44?: number;\n contractAddress?: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport type BuildEthereumDefinitionsForPathParams = {\n path: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport type BuildEthereumDefinitionsForSignTxParams = {\n path: string;\n chainId: number;\n to?: string;\n data?: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\n/** Derive the SLIP-44 coin type (unhardened) from a BIP44-style path. */\nexport function getSlip44FromPath(path: string): number {\n const segments = path.trim().replace(/^m\\//i, '').split('/');\n const coinType = segments[1];\n const parsed = coinType === undefined ? NaN : Number(coinType.replace(/['hH]$/, ''));\n if (!Number.isFinite(parsed)) {\n throw new Error(`Cannot derive SLIP-44 coin type from path: ${path}`);\n }\n return parsed >= 0x80000000 ? parsed - 0x80000000 : parsed;\n}\n\nexport async function fetchEthereumDefinitions({\n chainId,\n slip44,\n contractAddress,\n baseUrl = DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL,\n fetchImpl = globalThis.fetch,\n}: FetchEthereumDefinitionsParams): Promise<EvmEthereumDefinitions> {\n if (!chainId && !slip44) {\n throw new Error('fetchEthereumDefinitions requires chainId or slip44');\n }\n if (!fetchImpl) {\n return {};\n }\n\n const mode = chainId ? 'chain-id' : 'slip44';\n const id = chainId ?? slip44;\n const definitions: EvmEthereumDefinitions = {};\n\n const network = await fetchDefinitionHex(`${baseUrl}/${mode}/${id}/network.dat`, fetchImpl);\n if (network) {\n definitions.encodedNetwork = network;\n }\n\n if (contractAddress) {\n const token = await fetchDefinitionHex(\n `${baseUrl}/${mode}/${id}/token-${stripHexPrefix(contractAddress).toLowerCase()}.dat`,\n fetchImpl\n );\n if (token) {\n definitions.encodedToken = token;\n }\n }\n\n return definitions;\n}\n\nexport async function buildEthereumDefinitionsForPath({\n path,\n baseUrl,\n fetchImpl,\n}: BuildEthereumDefinitionsForPathParams): Promise<EvmEthereumDefinitions> {\n return fetchEthereumDefinitions({\n slip44: getSlip44FromPath(path),\n baseUrl,\n fetchImpl,\n });\n}\n\nexport async function buildEthereumDefinitionsForSignTx({\n path,\n chainId,\n to,\n data,\n baseUrl,\n fetchImpl,\n}: BuildEthereumDefinitionsForSignTxParams): Promise<EvmEthereumDefinitions | undefined> {\n const dataHex = stripHexPrefix(data ?? '');\n if (chainId === 1 && !dataHex) {\n return undefined;\n }\n return fetchEthereumDefinitions({\n chainId,\n slip44: getSlip44FromPath(path),\n contractAddress: dataHex && to ? to : undefined,\n baseUrl,\n fetchImpl,\n });\n}\n\nasync function fetchDefinitionHex(url: string, fetchImpl: FetchLike): Promise<string | undefined> {\n try {\n return await runWithTimeout(async () => {\n const response = await fetchImpl(url);\n if (response.status !== 200) {\n return undefined;\n }\n return arrayBufferToHex(await response.arrayBuffer());\n });\n } catch {\n return undefined;\n }\n}\n\nfunction arrayBufferToHex(value: ArrayBuffer): string {\n return Buffer.from(value).toString('hex');\n}\n\nfunction stripHexPrefix(value: string): string {\n return value.startsWith('0x') || value.startsWith('0X') ? value.slice(2) : value;\n}\n","import { runWithTimeout } from './ethereumDefinitions';\n\nimport type { FetchLike } from './ethereumDefinitions';\n\n/**\n * Opt-in helper for fetching a Trezor Solana token definition. Same contract as\n * the Ethereum helpers (see ./ethereumDefinitions): the SDK signing path NEVER\n * calls this — the caller fetches (through its own `baseUrl` proxy if desired)\n * and passes the bytes into `solSignTransaction` params as\n * `additionalInfo.encodedToken`. When omitted the device shows a generic token\n * confirmation screen and signing still completes.\n *\n * `fetchImpl` is a function and must not cross an IPC boundary — fetch in a\n * network-capable process and pass only the resulting hex string.\n */\n\n/** Default upstream (Trezor). Override with `baseUrl` to use your own proxy. */\nexport const DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL =\n 'https://data.trezor.io/firmware/definitions/solana/token';\n\nexport type FetchSolanaTokenDefinitionParams = {\n tokenMint: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport async function fetchSolanaTokenDefinition({\n tokenMint,\n baseUrl = DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL,\n fetchImpl = globalThis.fetch,\n}: FetchSolanaTokenDefinitionParams): Promise<string | undefined> {\n if (!fetchImpl) {\n return undefined;\n }\n try {\n return await runWithTimeout(async () => {\n const response = await fetchImpl(`${baseUrl}/${tokenMint}.dat`);\n if (response.status !== 200) {\n return undefined;\n }\n return Buffer.from(await response.arrayBuffer()).toString('hex');\n });\n } catch {\n return undefined;\n }\n}\n","export const TREZOR_SAFE_7_MODEL = 'T3W1';\n\nexport const TREZOR_BLE_SUPPORTED_MODELS = [TREZOR_SAFE_7_MODEL] as const;\n\nexport const TREZOR_BLE_PACKET_SIZE = 244;\n\nexport const TREZOR_BLE_UUIDS = {\n service: '8c000001-a59b-4d58-a9ad-073df69fa1b1',\n write: '8c000002-a59b-4d58-a9ad-073df69fa1b1',\n notify: '8c000003-a59b-4d58-a9ad-073df69fa1b1',\n push: '8c000004-a59b-4d58-a9ad-073df69fa1b1',\n batteryService: '0000180f-0000-1000-8000-00805f9b34fb',\n} as const;\n","import { TREZOR_BLE_SUPPORTED_MODELS, TREZOR_BLE_UUIDS } from '../constants';\n\nimport type { TrezorBleDescriptor } from '../types';\n\nexport function isTrezorSafe7BleName(name?: string): boolean {\n if (!name) return false;\n return /\\bTrezor\\b/i.test(name) && (/\\bSafe\\s*7\\b/i.test(name) || /\\bT3W1\\b/i.test(name));\n}\n\nexport function isTrezorBleSupportedModel(model?: string): boolean {\n if (!model) return false;\n const normalizedModel = model.trim().replace(/\\s+/g, ' ').toLowerCase();\n return (\n TREZOR_BLE_SUPPORTED_MODELS.some(\n supportedModel => supportedModel.toLowerCase() === normalizedModel\n ) ||\n normalizedModel === 'safe 7' ||\n normalizedModel === 'trezor safe 7'\n );\n}\n\nexport function isTrezorSafe7BleDescriptor(descriptor: TrezorBleDescriptor): boolean {\n return isTrezorBleDescriptor(descriptor);\n}\n\nexport function normalizeTrezorBleUuid(uuid: string): string {\n return uuid.replace(/-/g, '').toLowerCase();\n}\n\nexport function isTrezorBleServiceUuid(uuid: string): boolean {\n return normalizeTrezorBleUuid(uuid) === normalizeTrezorBleUuid(TREZOR_BLE_UUIDS.service);\n}\n\nexport function isTrezorBleDescriptor(descriptor: TrezorBleDescriptor): boolean {\n const serviceUuids = [\n ...(descriptor.serviceUUIDs ?? []),\n ...(descriptor.advertisedServiceUuids ?? []),\n ...(descriptor.serviceUuids ?? []),\n ];\n return serviceUuids.some(isTrezorBleServiceUuid);\n}\n\nexport function resolveTrezorBleConnectId(descriptor: TrezorBleDescriptor): string {\n return descriptor.id ?? descriptor.path ?? descriptor.deviceId ?? descriptor.name ?? '';\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-trezor-adapter/dist/index.js","../src/adapter/TrezorAdapter.ts","../src/deviceAuthenticity/index.ts","../src/deviceAuthenticity/config.ts","../src/deviceAuthenticity/findSubjectContentByOid.ts","../src/deviceAuthenticity/validateCaCertExtensions.ts","../src/deviceAuthenticity/verifySignatures.ts","../src/deviceAuthenticity/x509certificate.ts","../src/deviceAuthenticity/verifyAuthenticityProof.ts","../src/utils/sdkEventBus.ts","../src/utils/debugLog.ts","../src/utils/ethereumDefinitions.ts","../src/utils/solanaTokenDefinition.ts","../src/constants.ts","../src/utils/bleIdentity.ts"],"names":[],"mappings":"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","file":"/home/runner/work/hardware-js-sdk/hardware-js-sdk/packages/hwk-trezor-adapter/dist/index.js","sourcesContent":[null,"import {\n DEVICE,\n DeviceJobQueue,\n HardwareErrorCode,\n TypedEventEmitter,\n UI_REQUEST,\n UI_RESPONSE,\n UiRequestRegistry,\n failure,\n rehydrateConnectorError,\n runAllNetworkGetAddress,\n success,\n} from '@onekeyfe/hwk-adapter-core';\nimport { randomBytes } from '@noble/hashes/utils';\n\nimport { authenticateDeviceFromProof } from '../deviceAuthenticity';\nimport { debugLog } from '../utils/debugLog';\n\nimport type { AuthenticityProof } from '../deviceAuthenticity';\nimport type {\n AllNetworkAddressParams,\n AllNetworkAddressResponse,\n AllNetworkGetAddressParams,\n AllNetworkMethodName,\n BtcAddress,\n BtcGetAddressParams,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignMsgParams,\n BtcSignPsbtParams,\n BtcSignTxParams,\n BtcSignature,\n BtcSignedPsbt,\n BtcSignedTx,\n ChainCapability,\n ChainForFingerprint,\n ConnectorCallResult,\n ConnectorDevice,\n ConnectorUiEvent,\n DeviceAuthenticityParams,\n DeviceAuthenticityResult,\n DeviceEventListener,\n DeviceInfo,\n EvmAddress,\n EvmGetAddressParams,\n EvmSignMsgParams,\n EvmSignTxTrezorParams,\n EvmSignTypedDataParams,\n EvmSignature,\n EvmSignedTx,\n HardwareEvent,\n HardwareEventMap,\n IBtcMethods,\n ICommonCallParams,\n IConnector,\n IDeviceManagerMethods,\n IEvmMethods,\n IHardwareWallet,\n ISolMethods,\n ITronMethods,\n Response,\n SolAddress,\n SolGetAddressParams,\n SolSignMsgParams,\n SolSignTxParams,\n SolSignature,\n SolSignedTx,\n TransportType,\n TrezorBrightnessParams,\n TrezorChangePinParams,\n TrezorDeviceSettingsParams,\n TronAddress,\n TronGetAddressParams,\n TronSignMsgParams,\n TronSignTxParams,\n TronSignature,\n TronSignedTx,\n UiResponseEvent,\n} from '@onekeyfe/hwk-adapter-core';\n\n// Valid HardwareErrorCode numbers. Used to reject foreign numeric `code`s (e.g.\n// a DOMException's `code: 20` on a WebUSB AbortError) that must NOT be trusted\n// as HardwareErrorCodes — otherwise they leak through as Unknown.\nconst KNOWN_HARDWARE_ERROR_CODES = new Set<number>(\n Object.values(HardwareErrorCode).filter((value): value is number => typeof value === 'number')\n);\n\ntype NullableCallArg<T> = T | null | undefined;\n\ntype TrezorPassphraseCallParams = {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n};\n\ntype TrezorPassphraseRequestContext = {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n};\n\ntype TrezorVerifiedPassphraseSession = {\n sessionId: string;\n protocol: 'thp' | 'v1';\n thpSessionId?: string;\n};\n\ntype TrezorCallParams<T> = (T & ICommonCallParams & TrezorPassphraseCallParams) | null | undefined;\n\ntype TrezorCommonParams = (ICommonCallParams & TrezorPassphraseCallParams) | null | undefined;\n\ntype AsyncMethodName<T> = Extract<\n {\n [K in keyof T]-?: NonNullable<T[K]> extends (\n ...args: infer _Args\n ) => Promise<Response<infer _Payload>>\n ? K\n : never;\n }[keyof T],\n string\n>;\n\ntype TrezorWalletMethods = IEvmMethods & IBtcMethods & ISolMethods & ITronMethods;\n\ntype TrezorWalletMethodName = AsyncMethodName<TrezorWalletMethods>;\n\ntype TrezorDeviceManagerMethodName = AsyncMethodName<IDeviceManagerMethods>;\n\ntype TrezorMethodName = TrezorWalletMethodName | TrezorDeviceManagerMethodName;\n\nconst TREZOR_BTC_NETWORK_COIN_MAP: Partial<Record<string, string>> = {\n btc: 'Bitcoin',\n bitcoin: 'Bitcoin',\n tbtc: 'Testnet',\n testnet: 'Testnet',\n sbtc: 'Signet',\n signet: 'Signet',\n ltc: 'Litecoin',\n litecoin: 'Litecoin',\n doge: 'Dogecoin',\n dogecoin: 'Dogecoin',\n bch: 'Bcash',\n bcash: 'Bcash',\n dash: 'Dash',\n};\n\nexport class TrezorAdapter implements IHardwareWallet {\n readonly vendor = 'trezor' as const;\n\n private readonly _connector: IConnector;\n\n private readonly _emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private readonly _devices = new Map<string, DeviceInfo>();\n\n private readonly _sessions = new Map<string, string>();\n\n private readonly _connectingPromises = new Map<string, Promise<string>>();\n\n // connectIds disconnected mid-connect; the session they produce is torn down, not cached.\n private readonly _disconnectRequested = new Set<string>();\n\n private readonly _uiRegistry = new UiRequestRegistry();\n\n private readonly _passphraseRequestContextByConnectId = new Map<\n string,\n TrezorPassphraseRequestContext\n >();\n\n private readonly _verifiedPassphraseSessionsByConnectId = new Map<\n string,\n Map<string, TrezorVerifiedPassphraseSession>\n >();\n\n // Per-device queue with preemption + AbortSignal. Same-device chain calls\n // serialize (Trezor's protocol is single-request-response — interleaving\n // desyncs THP nonce). 'safe' read methods auto-cancel each other; 'confirm'\n // sign methods emit REQUEST_PREEMPTION so the consumer can decide.\n private readonly _jobQueue: DeviceJobQueue;\n\n constructor(connector: IConnector) {\n this._connector = connector;\n // Upstream DeviceJobQueue is now a global FIFO with no built-in\n // preemption — interruptibility lives at the application layer.\n this._jobQueue = new DeviceJobQueue();\n this._registerConnectorEvents();\n }\n\n private static _createDeviceBusyError(method: string): Error {\n // Our own queued request blocks this one → DeviceBusyInternal, not \"another app\".\n return Object.assign(new Error(`Trezor is busy with another request (${method})`), {\n code: HardwareErrorCode.DeviceBusyInternal,\n });\n }\n\n /**\n * Split a Trezor-only `passphraseState` routing hint off the chain params so\n * it never reaches the protobuf layer. The connector/firmware only sees the\n * real op fields; the adapter uses `passphraseState` to align the session.\n */\n private static _normalizeCallArgs(\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>\n ): {\n connectId: string;\n params: unknown;\n } {\n return {\n connectId: connectId || deviceId || '',\n params: params ?? {},\n };\n }\n\n private static _splitCommonParams(params: unknown): {\n passphraseState?: string;\n useEmptyPassphrase?: boolean;\n rest: unknown;\n } {\n if (params && typeof params === 'object') {\n const {\n passphraseState,\n autoInstallApp: _autoInstallApp,\n useEmptyPassphrase,\n ...rest\n } = params as Record<string, unknown>;\n return {\n passphraseState: typeof passphraseState === 'string' ? passphraseState : undefined,\n useEmptyPassphrase:\n typeof useEmptyPassphrase === 'boolean' ? useEmptyPassphrase : undefined,\n rest,\n };\n }\n return { rest: params ?? {} };\n }\n\n private static _withAllNetworkRequestCommonParams(\n item: AllNetworkAddressParams,\n commonParams: TrezorCommonParams\n ): AllNetworkAddressParams {\n const autoInstallApp = commonParams?.autoInstallApp;\n const passphraseState = commonParams?.passphraseState;\n const useEmptyPassphrase = commonParams?.useEmptyPassphrase;\n if (\n autoInstallApp === undefined &&\n passphraseState === undefined &&\n useEmptyPassphrase === undefined\n ) {\n return item;\n }\n return {\n ...item,\n ...(autoInstallApp !== undefined ? { autoInstallApp } : {}),\n ...(passphraseState !== undefined ? { passphraseState } : {}),\n ...(useEmptyPassphrase !== undefined ? { useEmptyPassphrase } : {}),\n };\n }\n\n // Keys are matched after normalizeLogKey, so snake_case/camelCase both hit.\n private static readonly _sensitiveLogKeys = new Set([\n 'credential',\n 'credentials',\n 'entropy',\n 'hoststatickey',\n 'mnemonic',\n 'mnemonics',\n 'passphrase',\n 'passphrasestate',\n 'password',\n 'pin',\n 'privatekey',\n 'seed',\n 'session',\n 'sessionid',\n 'trezorstaticpublickey',\n 'word',\n 'words',\n 'xprv',\n ]);\n\n private static _normalizeLogKey(key: string): string {\n return key.replace(/[_-]/g, '').toLowerCase();\n }\n\n // Mirrors hd-core's logBlockEvent: a signing method's body is the user's\n // transaction, so it is dropped wholesale; other methods redact by key.\n private static _sanitizeForLog(value: unknown, methodName?: string): unknown {\n if (methodName && /sign/i.test(methodName)) return '[redacted]';\n return TrezorAdapter._redactForLog(value, new WeakSet());\n }\n\n private static _redactForLog(value: unknown, seen: WeakSet<object>): unknown {\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n return `[BINARY:${value.byteLength}]`;\n }\n if (!value || typeof value !== 'object') return value;\n if (seen.has(value)) return '[CIRCULAR]';\n seen.add(value);\n const out = Array.isArray(value)\n ? value.map(item => TrezorAdapter._redactForLog(item, seen))\n : Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n TrezorAdapter._sensitiveLogKeys.has(TrezorAdapter._normalizeLogKey(key)) &&\n item !== null &&\n item !== undefined\n ? '[redacted]'\n : TrezorAdapter._redactForLog(item, seen),\n ])\n );\n seen.delete(value);\n return out;\n }\n\n private static _errorForLog(error: unknown): unknown {\n if (!error || typeof error !== 'object') return error;\n const typed = error as {\n code?: unknown;\n errorCode?: unknown;\n message?: unknown;\n name?: unknown;\n response?: unknown;\n statusCode?: unknown;\n };\n return TrezorAdapter._sanitizeForLog({\n name: typed.name,\n message: typed.message,\n code: typed.code,\n errorCode: typed.errorCode,\n statusCode: typed.statusCode,\n response: typed.response,\n });\n }\n\n private _setPassphraseRequestContext(\n connectId: string,\n context: TrezorPassphraseRequestContext\n ): () => void {\n const previous = this._passphraseRequestContextByConnectId.get(connectId);\n if (context.passphraseState !== undefined || context.useEmptyPassphrase !== undefined) {\n this._passphraseRequestContextByConnectId.set(connectId, context);\n } else {\n this._passphraseRequestContextByConnectId.delete(connectId);\n }\n return () => {\n if (previous) {\n this._passphraseRequestContextByConnectId.set(connectId, previous);\n } else {\n this._passphraseRequestContextByConnectId.delete(connectId);\n }\n };\n }\n\n private static _trezorFailureMessage(error: unknown): {\n code?: unknown;\n message?: unknown;\n } {\n const response = (error as { response?: unknown } | null | undefined)?.response;\n const message = (response as { message?: unknown } | null | undefined)?.message;\n if (!message || typeof message !== 'object') return {};\n const failureMessage = message as { code?: unknown; message?: unknown };\n return {\n code: failureMessage.code,\n message: failureMessage.message,\n };\n }\n\n private static _mapTrezorFailureCode(error: unknown): HardwareErrorCode | undefined {\n const directCode = (error as { code?: unknown } | null | undefined)?.code;\n if (directCode === 'Device_InitializeFailed') {\n return HardwareErrorCode.PinCancelled;\n }\n if (directCode === 'Failure_ActionCancelled') {\n return HardwareErrorCode.UserRejected;\n }\n if (directCode === 'ThpPairingRequired') {\n return HardwareErrorCode.ThpPairingRequired;\n }\n if (directCode === 'Failure_UnexpectedMessage') {\n return HardwareErrorCode.MethodNotSupported;\n }\n const message = (error as { message?: unknown } | null | undefined)?.message;\n if (\n typeof message === 'string' &&\n message.includes(\"Failed to execute 'transfer\") &&\n message.includes(\"on 'USBDevice'\")\n ) {\n return HardwareErrorCode.TransportError;\n }\n const failure = TrezorAdapter._trezorFailureMessage(error);\n if (failure.code === 'Failure_PinCancelled') {\n return HardwareErrorCode.PinCancelled;\n }\n if (failure.code === 'Failure_PinInvalid') {\n return HardwareErrorCode.PinInvalid;\n }\n if (failure.code === 'Failure_PinMismatch') {\n return HardwareErrorCode.PinMismatch;\n }\n if (failure.code === 'Failure_ActionCancelled') {\n return HardwareErrorCode.UserRejected;\n }\n if (failure.code === 'Failure_ProcessError' && failure.message === 'Unsupported script type') {\n return HardwareErrorCode.MethodNotSupported;\n }\n // Device rejected the derivation path (e.g. an index outside its allowed\n // range) — distinct path-specific surface, not a generic \"method\" error.\n if (failure.code === 'Failure_DataError' && failure.message === 'Forbidden key path') {\n return HardwareErrorCode.DevicePathForbidden;\n }\n // Match the stable setting name instead of the full firmware message.\n if (\n failure.code === 'Failure_DataError' &&\n typeof failure.message === 'string' &&\n failure.message.includes('PASSPHRASE_ALWAYS_ON_DEVICE')\n ) {\n return HardwareErrorCode.PassphraseAlwaysOnDevice;\n }\n // Firmware can't process this request (e.g. EIP-712 typed data the device\n // firmware doesn't support) → surface as \"method not supported\".\n if (failure.code === 'Failure_FirmwareError') {\n return HardwareErrorCode.MethodNotSupported;\n }\n // Device firmware doesn't recognize the message (e.g. an older device asked\n // for a coin/app it lacks) → \"method not supported\", not a generic unknown.\n if (failure.code === 'Failure_UnexpectedMessage') {\n return HardwareErrorCode.MethodNotSupported;\n }\n if (failure.code === 'Failure_NotInitialized') {\n return HardwareErrorCode.DeviceNotInitialized;\n }\n // Device busy with its own op, not another app → DeviceBusyInternal.\n if (failure.code === 'Failure_Busy' || failure.code === 'Failure_InProgress') {\n return HardwareErrorCode.DeviceBusyInternal;\n }\n return undefined;\n }\n\n /**\n * Whether a device-side error code means the THP application session we\n * selected is gone (the device evicted it from its limited slot pool). The\n * caller drops the stale cache entry and recreates from scratch.\n *\n * NOTE: the exact eviction code still needs real-device confirmation — match\n * conservatively so a genuine error isn't mistaken for an evicted session\n * (which would silently re-prompt the passphrase).\n */\n private static _isStaleSessionError(code: unknown): boolean {\n if (typeof code !== 'string') return false;\n return (\n code === 'ThpUnallocatedChannel' ||\n /invalid.?session|unallocated.?session|session.?not.?found/i.test(code)\n );\n }\n\n private static _errorCode(error: unknown): unknown {\n return (error as { code?: unknown }).code ?? TrezorAdapter._trezorFailureMessage(error).code;\n }\n\n private static _isConnectionUnavailableError(error: unknown): boolean {\n const { code } = error as { code?: unknown };\n return (\n code === HardwareErrorCode.DeviceNotFound || code === HardwareErrorCode.DeviceDisconnected\n );\n }\n\n private static _isRecoverableProtocolResidueError(error: unknown): boolean {\n const protocolError = error as {\n name?: unknown;\n code?: unknown;\n message?: unknown;\n };\n return (\n protocolError.name === 'TrezorProtocolError' &&\n protocolError.code === 'Malformed protocol format' &&\n protocolError.message === 'Malformed protocol format'\n );\n }\n\n /**\n * Race a promise against an abort signal. Copied from LedgerAdapter:\n * IConnector.call() can't actually be cancelled at the protocol level, but\n * the caller gets the abort immediately and the underlying work completes\n * uselessly in the background.\n */\n private static _abortable<T>(signal: AbortSignal, promise: Promise<T>): Promise<T> {\n if (signal.aborted) {\n return Promise.reject(\n (signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted')\n );\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n reject((signal as AbortSignal & { reason?: unknown }).reason ?? new Error('Aborted'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n err => {\n signal.removeEventListener('abort', onAbort);\n reject(err);\n }\n );\n });\n }\n\n private async _connectSession(connectId: string, signal?: AbortSignal): Promise<string> {\n const connectOnce = async () => {\n const connectPromise = this._connector.connect(connectId);\n if (!signal) return connectPromise;\n try {\n return await TrezorAdapter._abortable(signal, connectPromise);\n } catch (error) {\n // _abortable rejected (abort/failure) but the underlying connect keeps\n // running — tear down any session it still resolves so it isn't orphaned.\n void connectPromise.then(\n orphan => this._connector.disconnect(orphan.sessionId).catch(() => undefined),\n () => undefined\n );\n throw error;\n }\n };\n let session;\n try {\n session = await connectOnce();\n } catch (error) {\n if (signal?.aborted || !TrezorAdapter._isRecoverableProtocolResidueError(error)) {\n throw error;\n }\n // An interrupted THP handshake may leave exactly one v2 frame queued on\n // the shared USB pipe. The connector intentionally drains it as a loud\n // v1 malformed-frame failure; retry once now that the residue is gone.\n debugLog('[TrezorAdapter] retrying connect after draining a stale THP frame', {\n connectId,\n });\n session = await connectOnce();\n }\n // disconnectDevice() ran mid-connect: tear down the now-unwanted session\n // instead of caching it (else it leaks a limited THP slot).\n if (this._disconnectRequested.delete(connectId)) {\n await this._connector.disconnect(session.sessionId).catch(() => undefined);\n throw Object.assign(new Error('Trezor connection aborted'), {\n code: HardwareErrorCode.UserAborted,\n });\n }\n this._sessions.set(connectId, session.sessionId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n this._devices.set(connectId, session.deviceInfo);\n return session.sessionId;\n }\n\n get activeTransport(): TransportType | null {\n return this._connector.connectionType;\n }\n\n async init(_config?: unknown): Promise<void> {}\n\n async dispose(): Promise<void> {\n this._unregisterConnectorEvents();\n this._uiRegistry.reset();\n this._jobQueue.clear();\n this._connector.reset();\n this._devices.clear();\n this._sessions.clear();\n this._verifiedPassphraseSessionsByConnectId.clear();\n this._connectingPromises.clear();\n this._emitter.removeAllListeners();\n }\n\n /**\n * Clear cached state without tearing down the adapter or unregistering\n * listeners. Mirrors LedgerAdapter.resetState() — useful for retry-after-\n * error flows. Aborts active jobs and releases UI waits.\n */\n resetState(): void {\n this._uiRegistry.reset();\n this._jobQueue.clear();\n this._devices.clear();\n this._sessions.clear();\n this._verifiedPassphraseSessionsByConnectId.clear();\n this._connectingPromises.clear();\n }\n\n getAvailableTransports(): TransportType[] {\n return this.activeTransport ? [this.activeTransport] : [];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {}\n\n async searchDevices(options?: { waitForAllTransports?: boolean }): Promise<DeviceInfo[]> {\n await this._ensureDevicePermission();\n const scanned = await this._connector.searchDevices(\n options?.waitForAllTransports ? { waitForAll: true } : undefined\n );\n const scannedIds = new Set(scanned.map(d => d.connectId));\n // A rescan that misses a currently-connected device shouldn't evict it —\n // otherwise getDeviceInfo would return DeviceNotFound for an active session.\n for (const connectId of [...this._devices.keys()]) {\n if (!scannedIds.has(connectId) && !this._sessions.has(connectId)) {\n this._devices.delete(connectId);\n }\n }\n for (const device of scanned) {\n const info = this._connectorDeviceToDeviceInfo(device);\n this._devices.set(info.connectId, info);\n }\n return Array.from(this._devices.values());\n }\n\n async connectDevice(connectId: string): Promise<Response<string>> {\n try {\n await this._ensureDevicePermission(connectId);\n await this._ensureSession(connectId);\n return success(connectId);\n } catch (error) {\n return this._errorToFailure(error);\n }\n }\n\n async disconnectDevice(connectId: string): Promise<void> {\n const connecting = this._connectingPromises.has(connectId);\n this._connectingPromises.delete(connectId);\n const sessionId = this._sessions.get(connectId);\n if (!sessionId) {\n // Connect may be in flight (session not recorded yet) — mark it so\n // _connectSession tears down the session it produces instead of caching it.\n if (connecting) this._disconnectRequested.add(connectId);\n return;\n }\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n await this._connector.disconnect(sessionId);\n }\n\n async getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>> {\n const device =\n this._devices.get(connectId) ??\n Array.from(this._devices.values()).find(item => item.deviceId === deviceId);\n if (!device) return failure(HardwareErrorCode.DeviceNotFound, 'Trezor device not found');\n return success(device);\n }\n\n getSupportedChains(): ChainCapability[] {\n // Keep in sync with TrezorConnectorBase.call()'s switch.\n // Chain inclusion means \"at least one method wired\" — per-method gaps:\n // sol: signMessage is explicitly NotSupported (firmware doesn't ship it).\n // tron: signMessage same. signTransaction uses the multi-step\n // TronContractRequest flow.\n return ['btc', 'evm', 'sol', 'tron'];\n }\n\n async allNetworkGetAddress(\n connectId: string,\n deviceId: string,\n params: AllNetworkGetAddressParams\n ): Promise<Response<AllNetworkAddressResponse[]>> {\n let liveDeviceId = '';\n const topLevelFailureIndexes = new Set<number>();\n const isSingleNetworkBundle = params.bundle.every(\n item => item.network === params.bundle[0]?.network\n );\n const getLiveDeviceId = async (): Promise<Response<string>> => {\n if (liveDeviceId) return success(liveDeviceId);\n const deviceIdResponse = await this._getTrezorDeviceId(connectId);\n if (deviceIdResponse.success) {\n liveDeviceId = deviceIdResponse.payload;\n }\n return deviceIdResponse;\n };\n\n return runAllNetworkGetAddress({\n connectId,\n deviceId,\n params,\n normalizeItem: TrezorAdapter._normalizeAllNetworkItem,\n callItem: async ({ method, item, index }) => {\n const expectedDeviceId = TrezorAdapter._getItemDeviceId(item) ?? deviceId;\n if (expectedDeviceId) {\n const fingerprint = await getLiveDeviceId();\n if (!fingerprint.success) {\n topLevelFailureIndexes.add(index);\n return fingerprint;\n }\n if (expectedDeviceId !== fingerprint.payload) {\n topLevelFailureIndexes.add(index);\n return failure(\n HardwareErrorCode.DeviceMismatch,\n `Wrong device: expected ${expectedDeviceId}, got ${fingerprint.payload}`,\n { expected: expectedDeviceId, actual: fingerprint.payload }\n );\n }\n }\n const callItem = TrezorAdapter._withAllNetworkRequestCommonParams(item, params);\n return this._callAllNetworkMethod(connectId, method, callItem);\n },\n attachIdentity: async ({ item, chain, payload }) => {\n if (!liveDeviceId) {\n const fingerprint = await getLiveDeviceId();\n if (!fingerprint.success) {\n return { ...item, success: false, payload: fingerprint.payload };\n }\n }\n return {\n ...item,\n success: true,\n payload: {\n ...payload,\n deviceIdentity: {\n vendor: 'trezor',\n type: 'deviceId',\n value: liveDeviceId,\n },\n chainFingerprint: liveDeviceId,\n chainFingerprintChain: chain,\n },\n };\n },\n // One named boolean per abort reason.\n shouldAbortBundle: (response, { index }) => {\n const isSessionLevelFailure = topLevelFailureIndexes.has(index);\n // Mixed bundles must not abort — other chains can still derive.\n const isWholeChainForbidden =\n isSingleNetworkBundle && response.payload?.code === HardwareErrorCode.DevicePathForbidden;\n const isPassphrasePolicyFailure =\n response.payload?.code === HardwareErrorCode.PassphraseAlwaysOnDevice;\n return isSessionLevelFailure || isWholeChainForbidden || isPassphrasePolicyFailure;\n },\n });\n }\n\n getFeatures(connectId: string): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>('getFeatures', connectId, {});\n }\n\n /**\n * Device authenticity attestation. Sends a host-generated challenge, has the\n * device sign it with its secure-element key, then verifies the returned\n * certificate chain up to a trusted Trezor root CA. On success returns a\n * `deviceId` that uniquely identifies the physical device, survives wipe, and\n * cannot be forged from a seed. Only trust the result when `verified` is true\n * (and `usedDebugKey` is false in production).\n *\n * Requires a secure-element model (Safe 3 = T2B1/T3B1, Safe 5 = T3T1, T3W1)\n * and an on-device confirmation. Older models (T1B1, T2T1) will fail.\n *\n * `dangerouslyAllowDebugKeys` accepts simulator / development root keys — NEVER\n * enable it in a production accounting flow, it lets an emulator mint any id.\n */\n async verifyDeviceAuthenticity(\n connectId: string,\n params: DeviceAuthenticityParams = {}\n ): Promise<Response<DeviceAuthenticityResult>> {\n if (params.challenge && params.dangerouslyAllowDebugKeys) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Debug attestation roots cannot be used with a server challenge'\n );\n }\n if (params.challenge && !/^[0-9a-fA-F]{64}$/.test(params.challenge)) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Device authenticity challenge must be exactly 32 bytes encoded as hex'\n );\n }\n\n const featuresRes = await this.getFeatures(connectId);\n if (!featuresRes.success) return featuresRes;\n\n const internalModel = (featuresRes.payload as { internal_model?: string }).internal_model;\n if (!internalModel) {\n return failure(HardwareErrorCode.UnknownError, 'Device internal_model unavailable');\n }\n\n const challengeHex =\n params.challenge?.toLowerCase() ?? Buffer.from(randomBytes(32)).toString('hex');\n const challenge = Buffer.from(challengeHex, 'hex');\n const proofRes = await this._callDeviceManagerMethod<Record<string, unknown>>(\n 'authenticateDevice',\n connectId,\n { challenge: challengeHex }\n );\n if (!proofRes.success) return proofRes;\n\n const proof = proofRes.payload as unknown as AuthenticityProof;\n const verification = authenticateDeviceFromProof({\n proof,\n challenge,\n deviceModel: internalModel,\n allowDebugKeys: params.dangerouslyAllowDebugKeys,\n });\n\n return success({\n ...verification,\n vendor: 'trezor' as const,\n trezorProof: {\n challenge: challengeHex,\n deviceModel: internalModel,\n proof,\n },\n });\n }\n\n deviceSettings(\n connectId: string,\n params: TrezorDeviceSettingsParams\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'deviceSettings',\n connectId,\n params\n );\n }\n\n setBrightness(\n connectId: string,\n params: TrezorBrightnessParams = {}\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>(\n 'setBrightness',\n connectId,\n params\n );\n }\n\n changePin(\n connectId: string,\n params: TrezorChangePinParams = {}\n ): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>('changePin', connectId, params);\n }\n\n wipeDevice(connectId: string): Promise<Response<Record<string, unknown>>> {\n return this._callDeviceManagerMethod<Record<string, unknown>>('wipeDevice', connectId, {});\n }\n\n private async _getTrezorDeviceId(connectId: string): Promise<Response<string>> {\n const features = await this.getFeatures(connectId);\n if (!features.success) return features;\n const liveDeviceId = features.payload.device_id;\n if (typeof liveDeviceId !== 'string' || liveDeviceId.length === 0) {\n return failure(HardwareErrorCode.UnknownError, 'Trezor features did not include a device_id');\n }\n return success(liveDeviceId);\n }\n\n cancel(connectId?: string): void {\n const userAbortReason = Object.assign(new Error('User aborted operation'), {\n code: HardwareErrorCode.UserAborted,\n });\n // Release adapter-level UI waits (preemption) and connector-level ones\n // (THP pairing / PIN matrix) — a single CANCEL clears whichever is open.\n this._uiRegistry.cancel();\n this._connector.uiResponse({ type: UI_RESPONSE.CANCEL });\n if (connectId) {\n this._jobQueue.forceCancelActive(connectId, userAbortReason);\n void this._connector.cancel(this._sessions.get(connectId) ?? connectId);\n return;\n }\n for (const cid of this._sessions.keys()) {\n this._jobQueue.forceCancelActive(cid, userAbortReason);\n }\n for (const sessionId of this._sessions.values()) {\n void this._connector.cancel(sessionId);\n }\n }\n\n /**\n * Routes to BOTH the adapter's local UI registry (preemption decisions,\n * future SELECT_DEVICE / DEVICE_PERMISSION) AND the connector's registry\n * (THP pairing tag, PIN matrix). Each side ignores types it isn't waiting\n * for, so double-routing is harmless.\n */\n uiResponse(response: UiResponseEvent): void {\n this._uiRegistry.resolve(response.type, response.payload);\n this._connector.uiResponse(response);\n }\n\n /**\n * Returns the Trezor `device_id` from Features — a random 12-byte value the\n * device stores and regenerates on `wipe_device`. It identifies the PHYSICAL\n * DEVICE, not a seed/wallet: it is shared across passphrase wallets and\n * changes after wipe/restore, so it suits device-match checks but must NOT be\n * used as a wallet fingerprint (use `passphraseState` for wallet identity).\n * Unlike Ledger (which hashes a per-chain address), it is chain-global, so\n * `chain` is accepted for API parity but ignored.\n */\n async getChainFingerprint(\n connectId: string,\n _deviceId: string,\n _chain: ChainForFingerprint\n ): Promise<Response<string>> {\n return this._getTrezorDeviceId(connectId);\n }\n\n /**\n * Resolve the active passphrase wallet identity (`passphraseState`).\n * See {@link IHardwareWallet.getPassphraseState} for the discover/verify\n * semantics. Returns `null` for a standard wallet (no passphrase protection) —\n * there's nothing to pin. Serialized through the per-device job queue so it\n * can't interleave with a chain call on the same device (which would desync\n * the THP session selection).\n */\n getPassphraseState(\n connectId: string,\n passphraseState?: string\n ): Promise<Response<string | null>> {\n return this._jobQueue\n .enqueue(\n connectId,\n async signal => {\n const restorePassphraseRequestContext = this._setPassphraseRequestContext(connectId, {\n passphraseState,\n });\n try {\n return await this._resolvePassphraseState(connectId, passphraseState, signal);\n } finally {\n restorePassphraseRequestContext();\n }\n },\n {\n label: 'getPassphraseState',\n rejectIfBusy: true,\n busyError: TrezorAdapter._createDeviceBusyError('getPassphraseState'),\n }\n )\n .catch(error => this._errorToFailure(error));\n }\n\n evmGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmGetAddressParams>\n ) {\n return this._callWalletMethod<EvmAddress>('evmGetAddress', connectId, deviceId, params);\n }\n\n evmSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignTxTrezorParams>\n ) {\n return this._callWalletMethod<EvmSignedTx>('evmSignTransaction', connectId, deviceId, params);\n }\n\n evmSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignMsgParams>\n ) {\n return this._callWalletMethod<EvmSignature>('evmSignMessage', connectId, deviceId, params);\n }\n\n evmSignTypedData(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<EvmSignTypedDataParams>\n ) {\n return this._callWalletMethod<EvmSignature>('evmSignTypedData', connectId, deviceId, params);\n }\n\n btcGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcGetAddressParams>\n ) {\n return this._callWalletMethod<BtcAddress>('btcGetAddress', connectId, deviceId, params);\n }\n\n btcGetPublicKey(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcGetPublicKeyParams>\n ) {\n return this._callWalletMethod<BtcPublicKey>('btcGetPublicKey', connectId, deviceId, params);\n }\n\n btcSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignTxParams>\n ) {\n return this._callWalletMethod<BtcSignedTx>('btcSignTransaction', connectId, deviceId, params);\n }\n\n btcSignPsbt(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignPsbtParams>\n ) {\n return this._callWalletMethod<BtcSignedPsbt>('btcSignPsbt', connectId, deviceId, params);\n }\n\n btcSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<BtcSignMsgParams>\n ) {\n return this._callWalletMethod<BtcSignature>('btcSignMessage', connectId, deviceId, params);\n }\n\n btcGetMasterFingerprint(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCommonParams\n ) {\n return this._callWalletMethod<{ masterFingerprint: string }>(\n 'btcGetMasterFingerprint',\n connectId,\n deviceId,\n params\n );\n }\n\n solGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolGetAddressParams>\n ) {\n return this._callWalletMethod<SolAddress>('solGetAddress', connectId, deviceId, params);\n }\n\n solSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolSignTxParams>\n ) {\n return this._callWalletMethod<SolSignedTx>('solSignTransaction', connectId, deviceId, params);\n }\n\n solSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<SolSignMsgParams>\n ) {\n return this._callWalletMethod<SolSignature>('solSignMessage', connectId, deviceId, params);\n }\n\n tronGetAddress(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronGetAddressParams>\n ) {\n return this._callWalletMethod<TronAddress>('tronGetAddress', connectId, deviceId, params);\n }\n\n tronSignTransaction(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronSignTxParams>\n ) {\n return this._callWalletMethod<TronSignedTx>('tronSignTransaction', connectId, deviceId, params);\n }\n\n tronSignMessage(\n connectId?: string | null,\n deviceId?: string | null,\n params?: TrezorCallParams<TronSignMsgParams>\n ) {\n return this._callWalletMethod<TronSignature>('tronSignMessage', connectId, deviceId, params);\n }\n\n private static _unwrapConnectorResult(result: unknown): unknown {\n if (\n result &&\n typeof result === 'object' &&\n 'success' in result &&\n (((result as ConnectorCallResult).success === true && 'payload' in result) ||\n ((result as ConnectorCallResult).success === false && 'error' in result))\n ) {\n const connectorResult = result as ConnectorCallResult;\n if (connectorResult.success) return connectorResult.payload;\n throw rehydrateConnectorError(connectorResult.error);\n }\n return result;\n }\n\n private static async _callConnector(\n connector: IConnector,\n sessionId: string,\n method: string,\n params: unknown,\n signal?: AbortSignal\n ): Promise<unknown> {\n const promise = connector.call(sessionId, method, params);\n const result = signal ? await TrezorAdapter._abortable(signal, promise) : await promise;\n return TrezorAdapter._unwrapConnectorResult(result);\n }\n\n private static _normalizeAllNetworkItem(\n method: AllNetworkMethodName,\n item: AllNetworkAddressParams\n ): AllNetworkAddressParams {\n if (method !== 'btcGetAddress' && method !== 'btcGetPublicKey') {\n return item;\n }\n\n const itemWithCoin = item as AllNetworkAddressParams & { coin?: unknown };\n if (itemWithCoin.coin) {\n return item;\n }\n\n const network = item.network.toLowerCase();\n return {\n ...item,\n coin: TREZOR_BTC_NETWORK_COIN_MAP[network] ?? item.network,\n };\n }\n\n private static _getItemDeviceId(item: AllNetworkAddressParams): string | undefined {\n const { deviceId } = item as { deviceId?: unknown };\n return typeof deviceId === 'string' && deviceId.length > 0 ? deviceId : undefined;\n }\n\n private _callAllNetworkMethod(\n connectId: string,\n method: AllNetworkMethodName,\n item: AllNetworkAddressParams\n ): Promise<Response<unknown>> {\n switch (method) {\n case 'evmGetAddress':\n return this.evmGetAddress(connectId, '', item);\n case 'btcGetAddress':\n return this.btcGetAddress(connectId, '', item);\n case 'btcGetPublicKey':\n return this.btcGetPublicKey(connectId, '', item);\n case 'solGetAddress':\n return this.solGetAddress(connectId, '', item);\n case 'tronGetAddress':\n return this.tronGetAddress(connectId, '', item);\n default:\n return Promise.resolve(\n failure(\n HardwareErrorCode.InvalidParams,\n `Unsupported allNetwork method: ${String(method)}`\n )\n );\n }\n }\n\n on<K extends keyof HardwareEventMap>(\n event: K,\n listener: (event: HardwareEventMap[K]) => void\n ): void;\n\n on(event: string, listener: DeviceEventListener): void;\n\n on(event: string, listener: (event: HardwareEvent) => void): void {\n this._emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(\n event: K,\n listener: (event: HardwareEventMap[K]) => void\n ): void;\n\n off(event: string, listener: DeviceEventListener): void;\n\n off(event: string, listener: (event: HardwareEvent) => void): void {\n this._emitter.off(event, listener);\n }\n\n private _callWalletMethod<T>(\n methodName: TrezorWalletMethodName,\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>\n ): Promise<Response<T>> {\n return this._callMethod<T>(methodName, connectId, deviceId, params, true);\n }\n\n private _callDeviceManagerMethod<T>(\n methodName: TrezorDeviceManagerMethodName,\n connectId: NullableCallArg<string>,\n params: NullableCallArg<unknown>\n ): Promise<Response<T>> {\n return this._callMethod<T>(methodName, connectId, undefined, params, false);\n }\n\n private async _callMethod<T>(\n methodName: TrezorMethodName,\n connectId: NullableCallArg<string>,\n deviceId: NullableCallArg<string>,\n params: NullableCallArg<unknown>,\n requiresWalletIntent: boolean\n ): Promise<Response<T>> {\n const call = TrezorAdapter._normalizeCallArgs(connectId, deviceId, params);\n debugLog('[TrezorAdapter][REQ]', {\n method: methodName,\n connectId: call.connectId || '(empty)',\n deviceId: deviceId || undefined,\n params: TrezorAdapter._sanitizeForLog(call.params, methodName),\n });\n try {\n const response = await this._jobQueue.enqueue(\n call.connectId,\n signal =>\n this._callWithRetry<T>(\n call.connectId,\n methodName,\n call.params,\n requiresWalletIntent,\n true,\n signal\n ),\n {\n label: methodName,\n rejectIfBusy: true,\n busyError: TrezorAdapter._createDeviceBusyError(methodName),\n }\n );\n debugLog('[TrezorAdapter][RES]', {\n method: methodName,\n success: response.success,\n payload: TrezorAdapter._sanitizeForLog(response.payload, methodName),\n });\n return response;\n } catch (error) {\n // The only way a Promise rejects out of `enqueue` is the busy-reject —\n // _callWithRetry never throws, it returns Response.failure. Convert to\n // the Response shape so chain method callers stay uniform.\n const response = this._errorToFailure(error);\n debugLog('[TrezorAdapter][RES]', {\n method: methodName,\n success: false,\n payload: TrezorAdapter._sanitizeForLog(response.payload, methodName),\n });\n return response;\n }\n }\n\n private async _callWithRetry<T>(\n connectId: string,\n methodName: TrezorMethodName,\n params: unknown,\n requiresWalletIntent: boolean,\n allowRetry: boolean,\n signal: AbortSignal\n ): Promise<Response<T>> {\n const { passphraseState, useEmptyPassphrase, rest } = TrezorAdapter._splitCommonParams(params);\n const restorePassphraseRequestContext = this._setPassphraseRequestContext(connectId, {\n passphraseState,\n useEmptyPassphrase,\n });\n try {\n const sessionId = await this._ensureSession(connectId, signal);\n if (requiresWalletIntent && !passphraseState && useEmptyPassphrase !== true) {\n return failure(\n HardwareErrorCode.InvalidParams,\n `Trezor ${methodName} requires an explicit wallet intent: passphraseState or useEmptyPassphrase`\n );\n }\n // Pin the call to the requested passphrase wallet. For THP this creates\n // a new application session; for v1 it re-initializes the device session.\n // Runs inside this queued job so the session alignment and the call can't\n // be interleaved by another request.\n if (passphraseState) {\n await TrezorAdapter._abortable(\n signal,\n this._alignAppSession(connectId, sessionId, passphraseState, signal)\n );\n } else if (useEmptyPassphrase === true) {\n await TrezorAdapter._abortable(signal, this._createFreshAppSession(sessionId, signal));\n }\n const result = await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, methodName, rest)\n );\n return success(result as T);\n } catch (error) {\n // If we were aborted, surface as-is — don't take the retry/recovery path.\n if (signal.aborted) {\n return this._errorToFailure(error);\n }\n const code = TrezorAdapter._errorCode(error);\n // On a transient disconnect (BLE drop, \"device not connected\" race after\n // the device-disconnect event hasn't propagated yet), drop the stale\n // session and reconnect once. Matches Ledger's _retryWithFreshConnection.\n if (allowRetry && code === HardwareErrorCode.DeviceDisconnected) {\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n return await this._callWithRetry<T>(\n connectId,\n methodName,\n params,\n requiresWalletIntent,\n false,\n signal\n );\n }\n // The device evicted the passphrase session created for this call. Retry\n // once and recreate the requested wallet context.\n if (\n allowRetry &&\n (passphraseState || useEmptyPassphrase === true) &&\n TrezorAdapter._isStaleSessionError(code)\n ) {\n if (passphraseState) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n }\n return await this._callWithRetry<T>(\n connectId,\n methodName,\n params,\n requiresWalletIntent,\n false,\n signal\n );\n }\n debugLog('[TrezorAdapter][ERROR]', {\n method: methodName,\n connectId,\n error: TrezorAdapter._errorForLog(error),\n });\n return this._errorToFailure(error);\n } finally {\n restorePassphraseRequestContext();\n }\n }\n\n private async _ensureSession(connectId: string, signal?: AbortSignal): Promise<string> {\n const existing = this._sessions.get(connectId);\n if (existing) return existing;\n\n const pending = this._connectingPromises.get(connectId);\n if (pending) return pending;\n\n const promise = (async () => {\n try {\n if (signal?.aborted) {\n throw Object.assign(new Error('Trezor connection aborted'), {\n code: HardwareErrorCode.UserAborted,\n });\n }\n // Fail fast: a single connect attempt. On an \"unavailable device\" error we\n // drop the cached session/passphrase state and rethrow (no retry loop).\n try {\n return await this._connectSession(connectId, signal);\n } catch (error) {\n if (TrezorAdapter._isConnectionUnavailableError(error)) {\n this._sessions.delete(connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n }\n throw error;\n }\n } finally {\n this._connectingPromises.delete(connectId);\n this._disconnectRequested.delete(connectId);\n }\n })();\n\n this._connectingPromises.set(connectId, promise);\n return promise;\n }\n\n /**\n * Pin the device's active wallet session to `passphraseState` (the target\n * wallet identity) before a wallet-bound op. THP has an app-session id; v1\n * does not, but it still binds passphrase to the device session, so the\n * connector re-initializes v1 before we derive and verify.\n *\n * SECURITY: a verified THP app session may be selected again, but the adapter\n * still derives and verifies the passphrase state before any chain method can\n * run. If the cache is stale, fall back to creating a fresh wallet context.\n */\n private async _alignAppSession(\n connectId: string,\n sessionId: string,\n passphraseState: string,\n signal: AbortSignal\n ): Promise<void> {\n const reused = await this._reuseVerifiedPassphraseSession(\n connectId,\n sessionId,\n passphraseState,\n signal\n );\n if (reused) return;\n\n const created = (await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, '__thpCreateSession', {\n passphraseMode: 'prompt',\n })\n )) as { protocol?: string; thpSessionId?: string | null };\n // v1 has no host-managed app-session id, but the connector has just\n // re-initialized a fresh device session; continue with reactive\n // passphrase-state verification.\n if (created?.protocol === 'thp' && !created.thpSessionId) return;\n if (created?.protocol !== 'thp' && created?.protocol !== 'v1') return;\n const state = await this._deriveState(sessionId, signal);\n if (state !== passphraseState) {\n throw Object.assign(\n new Error(\n `Passphrase produced wallet ${state}, expected ${passphraseState} (passphraseState mismatch)`\n ),\n { code: HardwareErrorCode.PassphraseStateMismatch }\n );\n }\n this._rememberVerifiedPassphraseSession(connectId, passphraseState, sessionId, created);\n }\n\n private _rememberVerifiedPassphraseSession(\n connectId: string,\n passphraseState: string,\n sessionId: string,\n created: { protocol?: string; thpSessionId?: string | null } | undefined\n ): void {\n let session: TrezorVerifiedPassphraseSession | undefined;\n if (created?.protocol === 'thp' && typeof created.thpSessionId === 'string') {\n session = {\n sessionId,\n protocol: 'thp',\n thpSessionId: created.thpSessionId,\n };\n } else if (created?.protocol === 'v1') {\n session = {\n sessionId,\n protocol: 'v1',\n };\n }\n if (!session) return;\n\n const sessions =\n this._verifiedPassphraseSessionsByConnectId.get(connectId) ??\n new Map<string, TrezorVerifiedPassphraseSession>();\n sessions.set(passphraseState, session);\n this._verifiedPassphraseSessionsByConnectId.set(connectId, sessions);\n }\n\n private _forgetVerifiedPassphraseSession(connectId: string, passphraseState: string): void {\n const sessions = this._verifiedPassphraseSessionsByConnectId.get(connectId);\n if (!sessions) return;\n sessions.delete(passphraseState);\n if (!sessions.size) {\n this._verifiedPassphraseSessionsByConnectId.delete(connectId);\n }\n }\n\n private async _reuseVerifiedPassphraseSession(\n connectId: string,\n sessionId: string,\n passphraseState: string,\n signal: AbortSignal\n ): Promise<boolean> {\n const cached = this._verifiedPassphraseSessionsByConnectId.get(connectId)?.get(passphraseState);\n if (!cached || cached.sessionId !== sessionId) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n return false;\n }\n\n try {\n if (cached.protocol === 'thp') {\n if (!cached.thpSessionId) return false;\n await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, '__thpSelectSession', {\n thpSessionId: cached.thpSessionId,\n })\n );\n }\n const state = await this._deriveState(sessionId, signal);\n if (state !== passphraseState) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n return false;\n }\n return true;\n } catch (error) {\n this._forgetVerifiedPassphraseSession(connectId, passphraseState);\n if (signal.aborted) throw error;\n return false;\n }\n }\n\n private async _createFreshAppSession(sessionId: string, signal: AbortSignal): Promise<void> {\n // Create a fresh standard-wallet context for this call. Empty passphrase is\n // enforced inside connector/core, not delegated to host UI handlers.\n await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, '__thpCreateSession', {\n passphraseMode: 'empty',\n })\n );\n }\n\n /**\n * Derive the active session's passphrase state — the wallet identity used to\n * verify the right wallet is active: the compressed PUBLIC KEY at a fixed\n * account path (m/44'/0'/0'). It comes from the SAME GetPublicKey that also\n * carries the 4-byte fingerprint, but we use the FULL pubkey (not the truncated\n * fingerprint) so it's collision-resistant — the address we return can never\n * come from the wrong wallet — while avoiding OneKey's extra Testnet GetAddress.\n * Non-interactive (also unlocks via PIN as a protected derivation).\n */\n private async _deriveState(sessionId: string, signal: AbortSignal): Promise<string> {\n const derived = (await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, 'btcGetPublicKey', {\n path: \"m/44'/0'/0'\",\n showOnDevice: false,\n })\n )) as { publicKey?: string };\n const state = derived?.publicKey;\n if (!state) {\n throw Object.assign(new Error('Failed to derive passphrase state (wallet public key)'), {\n code: HardwareErrorCode.UnknownError,\n });\n }\n return state;\n }\n\n private async _resolvePassphraseState(\n connectId: string,\n passphraseState: string | undefined,\n signal: AbortSignal\n ): Promise<Response<string | null>> {\n try {\n const sessionId = await this._ensureSession(connectId, signal);\n if (passphraseState) {\n // Verify mode: align (which always re-derives + confirms the state) so the\n // host can gate signing on the correct wallet being active.\n await this._alignAppSession(connectId, sessionId, passphraseState, signal);\n return success(passphraseState);\n }\n // Discover mode (OneKey-aligned). DON'T trust pre-read features — a LOCKED\n // device reports an unreliable `passphrase_protection`, and the connector's\n // plain getFeatures returns a CACHED blob, so checking `unlocked` up front\n // is meaningless. Instead derive first (which unlocks), then re-read fresh:\n // 1. Create a session + derive the state. This UNLOCKS the device (PIN) and,\n // for a passphrase wallet, prompts the passphrase (THP: proactively in\n // ThpCreateNewSession; v1: reactively).\n // 2. Re-read features FRESH from the device (now unlocked → trustworthy).\n // 3. passphrase_protection === true → return the current passphrase\n // state, even if the entered passphrase was empty. Otherwise →\n // standard wallet → return null (OneKey-aligned).\n const created = (await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, '__thpCreateSession', {\n passphraseMode: 'prompt',\n })\n )) as { protocol?: string; thpSessionId?: string | null };\n const state = await this._deriveState(sessionId, signal);\n const features = (await TrezorAdapter._abortable(\n signal,\n TrezorAdapter._callConnector(this._connector, sessionId, 'getFeatures', { refresh: true })\n )) as Record<string, unknown> | undefined;\n if (features?.passphrase_protection !== true) {\n // Standard wallet — discard the derived state, return null (OneKey convention).\n return success(null);\n }\n this._rememberVerifiedPassphraseSession(connectId, state, sessionId, created);\n return success(state);\n } catch (error) {\n return this._errorToFailure(error);\n }\n }\n\n private _onDeviceConnect = (data: { device: ConnectorDevice }): void => {\n const device = this._connectorDeviceToDeviceInfo(data.device);\n this._devices.set(device.connectId, device);\n this._emitter.emit(DEVICE.CONNECT, { type: DEVICE.CONNECT, payload: device });\n };\n\n private _onDeviceDisconnect = (data: { connectId: string }): void => {\n this._sessions.delete(data.connectId);\n this._verifiedPassphraseSessionsByConnectId.delete(data.connectId);\n this._devices.delete(data.connectId);\n this._emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private _onSupportFeatures = (data: {\n device: ConnectorDevice & { features: Record<string, unknown> };\n }): void => {\n const device = {\n ...this._connectorDeviceToDeviceInfo(data.device),\n features: data.device.features,\n };\n this._emitter.emit(DEVICE.FEATURES, {\n type: DEVICE.FEATURES,\n device,\n payload: { device },\n });\n };\n\n private _onUiRequest = (data: { type: string; payload?: unknown }): void => {\n if (data.type === UI_REQUEST.REQUEST_PASSPHRASE) {\n const payload =\n data.payload && typeof data.payload === 'object'\n ? (data.payload as Record<string, unknown>)\n : {};\n const connectId = typeof payload.connectId === 'string' ? payload.connectId : undefined;\n const context = connectId\n ? this._passphraseRequestContextByConnectId.get(connectId)\n : undefined;\n this._emitter.emit(\n data.type as keyof HardwareEventMap,\n {\n ...data,\n payload: {\n ...payload,\n ...(context?.passphraseState !== undefined\n ? { passphraseState: context.passphraseState }\n : {}),\n ...(context?.useEmptyPassphrase !== undefined\n ? { useEmptyPassphrase: context.useEmptyPassphrase }\n : {}),\n },\n } as never\n );\n return;\n }\n this._emitter.emit(data.type as keyof HardwareEventMap, data as never);\n };\n\n private _onUiEvent = (data: ConnectorUiEvent): void => {\n this._emitter.emit('ui-event', data);\n };\n\n private _onThpCredentialsChanged = (data: {\n connectId: string;\n deviceId?: string;\n credentials: Record<string, unknown>[];\n }): void => {\n this._emitter.emit(DEVICE.TREZOR_THP_CREDENTIALS_CHANGED, {\n type: DEVICE.TREZOR_THP_CREDENTIALS_CHANGED,\n payload: data,\n });\n };\n\n private _registerConnectorEvents(): void {\n this._connector.on('device-connect', this._onDeviceConnect);\n this._connector.on('device-disconnect', this._onDeviceDisconnect);\n this._connector.on(DEVICE.FEATURES, this._onSupportFeatures);\n this._connector.on('device-trezor-thp-credentials-changed', this._onThpCredentialsChanged);\n this._connector.on('ui-request', this._onUiRequest);\n this._connector.on('ui-event', this._onUiEvent);\n }\n\n private _unregisterConnectorEvents(): void {\n this._connector.off('device-connect', this._onDeviceConnect);\n this._connector.off('device-disconnect', this._onDeviceDisconnect);\n this._connector.off(DEVICE.FEATURES, this._onSupportFeatures);\n this._connector.off('device-trezor-thp-credentials-changed', this._onThpCredentialsChanged);\n this._connector.off('ui-request', this._onUiRequest);\n this._connector.off('ui-event', this._onUiEvent);\n }\n\n private _connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'trezor',\n model: device.model ?? 'unknown',\n firmwareVersion: 'unknown',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n // The per-device transport is authoritative (a combined USB+BLE\n // connector tags each discovered device); the connector's own\n // connectionType is only a nominal value, so fall back to it for\n // single-transport connectors that don't tag each device.\n connectionType: device.connectionType ?? this._connector.connectionType,\n capabilities: device.capabilities,\n };\n }\n\n private _errorToFailure(error: unknown) {\n const typed = error as { code?: unknown; message?: string };\n // Map hwk-trezor-core's string markers to standard HardwareErrorCodes.\n // The core tags pairing-handshake rejections (e.g. mistyped CodeEntry code)\n // with `code: 'ThpPairingFailed'`; surface it as a proper code, not Unknown.\n if (typed.code === 'ThpPairingFailed') {\n return failure(HardwareErrorCode.ThpPairingFailed, typed.message ?? 'THP pairing failed');\n }\n // Only trust a numeric `code` if it is an actual HardwareErrorCode. A raw\n // WebUSB AbortError carries a DOMException `code: 20`, which is NOT one of\n // ours — fall through to message-based mapping (transferOut/USBDevice abort\n // → TransportError) so it surfaces as a recognizable, retryable transport\n // error instead of Unknown.\n const trustedNumericCode =\n typeof typed.code === 'number' && KNOWN_HARDWARE_ERROR_CODES.has(typed.code)\n ? typed.code\n : undefined;\n const code =\n trustedNumericCode ??\n TrezorAdapter._mapTrezorFailureCode(error) ??\n HardwareErrorCode.UnknownError;\n return failure(code, typed.message ?? String(error));\n }\n\n /**\n * Emit `REQUEST_DEVICE_PERMISSION` and await the host's\n * `RECEIVE_DEVICE_PERMISSION` reply (60s budget covers OS prompt + user\n * tap). If the host doesn't wire a handler the wait times out and the\n * operation fails fast.\n *\n * Mirrors LedgerAdapter._ensureDevicePermission so hosts can register a\n * single handler that branches by `payload.transportType` (and optionally\n * the active brand) instead of teaching every adapter its own contract.\n *\n * - no `connectId` → environment-level check (scan / picker)\n * - with `connectId` → device-level check (per-call gating)\n */\n private async _ensureDevicePermission(connectId?: string, deviceId?: string): Promise<void> {\n // No handler? Skip silently so non-permission-aware hosts (and our own\n // unit tests) keep working — Ledger's adapter has a 60s timeout but\n // hardware-wallet flows on web/desktop don't always have a registered\n // listener, and they shouldn't stall for a minute waiting on one.\n if (!this._emitter.listenerCount(UI_REQUEST.REQUEST_DEVICE_PERMISSION)) {\n return;\n }\n const transportType: TransportType = this.activeTransport ?? 'usb';\n\n const waitPromise = this._uiRegistry.wait<{ granted: boolean; reason?: string }>(\n UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n { timeoutMs: 60_000 }\n );\n\n this._emitter.emit(UI_REQUEST.REQUEST_DEVICE_PERMISSION, {\n type: UI_REQUEST.REQUEST_DEVICE_PERMISSION,\n payload: { transportType, connectId, deviceId },\n });\n\n const { granted } = await waitPromise;\n if (!granted) {\n throw Object.assign(new Error('Device permission denied'), {\n code: HardwareErrorCode.DevicePermissionDenied,\n });\n }\n }\n}\n","import { sha3_256 as sha3Hash } from '@noble/hashes/sha3';\n\nimport { deviceAuthenticityConfig } from './config';\nimport { prepareDeviceAuthenticityData, verifyAuthenticityProof } from './verifyAuthenticityProof';\n\nimport type { DeviceAuthenticityConfig } from './types';\n\nexport { deviceAuthenticityConfig } from './config';\nexport { prepareDeviceAuthenticityData, verifyAuthenticityProof } from './verifyAuthenticityProof';\nexport * from './types';\n\n/** Raw fields taken from a Trezor `AuthenticityProof` message. */\nexport type AuthenticityProof = {\n optiga_certificates: string[];\n optiga_signature: string;\n tropic_certificates?: string[];\n tropic_signature?: string;\n mcu_certificates?: string[];\n mcu_signature?: string;\n};\n\nexport type AuthenticateDeviceResult = {\n /**\n * True only when every layer implemented by this verifier and required by\n * the explicit model policy verified up to a trusted Trezor root CA AND the\n * device signed our challenge:\n * - Optiga (all secure-element models), and\n * - Tropic (T3W1 / Safe 7).\n * This is the currently implemented client policy, not full parity with the\n * latest capability-based Trezor Connect policy. Raw MCU fields remain in the\n * returned proof but are not yet a client-side pass/fail condition.\n * The reward backend must independently verify the same raw proof under its\n * own versioned policy; this client result is only a UX preview.\n */\n verified: boolean;\n /**\n * SHA3-256 of the verified Optiga device-attestation public key. It survives\n * wipe/recovery and has one representation across supported models. Do NOT\n * trust it when `verified` is false — it is then attacker-controlled.\n */\n deviceId?: string;\n /** Raw device attestation public key (hex) from the Optiga device certificate. */\n deviceCertPubKey?: string;\n /** X.509 subject serial number (hex), only present on T3W1 and above. */\n serialNumber?: string;\n rootPubKey?: string;\n caPubKey?: string;\n /**\n * True when the chain matched a DEBUG/staging root key (simulator / dev\n * device). A production accounting flow must reject verified results that\n * have `usedDebugKey === true`.\n */\n usedDebugKey?: boolean;\n /** Failure reason when `verified` is false. */\n error?: string;\n};\n\n// Revocation hook: CA public keys (hex) that must be rejected even if otherwise\n// valid. Empty today; kept so a leaked intermediate CA can be blocked by config\n// rather than a code change. Mirrors @trezor/device-authenticity's blacklist.\nexport const caPubKeyBlacklist: string[] = [];\n\nconst modelConfigOf = (config: DeviceAuthenticityConfig, deviceModel: string) => {\n const modelConfig = config[deviceModel];\n return modelConfig && typeof modelConfig !== 'number' ? modelConfig : undefined;\n};\n\nexport const getRequiredDeviceAuthenticityLayers = (\n deviceModel: string\n): readonly ('optiga' | 'tropic')[] => (deviceModel === 'T3W1' ? ['optiga', 'tropic'] : ['optiga']);\n\nconst isTropicExpected = (deviceModel: string): boolean =>\n getRequiredDeviceAuthenticityLayers(deviceModel).includes('tropic');\n\nconst matchedDebugKey = (\n config: DeviceAuthenticityConfig,\n deviceModel: string,\n rootPubKey?: string\n): boolean => {\n if (!rootPubKey) return false;\n const m = modelConfigOf(config, deviceModel);\n if (!m?.debug) return false;\n return [...(m.debug.rootPubKeysOptiga ?? []), ...(m.debug.rootPubKeysTropic ?? [])].includes(\n rootPubKey\n );\n};\n\n/**\n * Verify a Trezor `AuthenticityProof` against a challenge and derive a stable\n * per-device id. `challenge` must be the exact random bytes sent in the\n * `AuthenticateDevice` request. Never throws — malformed input from a malicious\n * device is folded into `{ verified: false }`.\n */\nexport const authenticateDeviceFromProof = ({\n proof,\n challenge,\n deviceModel,\n config = deviceAuthenticityConfig,\n allowDebugKeys,\n}: {\n proof: AuthenticityProof;\n challenge: Buffer;\n deviceModel: string;\n config?: DeviceAuthenticityConfig;\n allowDebugKeys?: boolean;\n}): AuthenticateDeviceResult => {\n try {\n const signedData = prepareDeviceAuthenticityData({ payload: challenge });\n const common = { signedData, deviceModel, config, allowDebugKeys, caPubKeyBlacklist };\n\n // 1) Optiga is required on every attestation-capable model.\n const { optiga_certificates: optigaCertificates, optiga_signature: optigaSignature } = proof;\n if (!optigaSignature || !optigaCertificates?.length) {\n return { verified: false, error: 'RESPONSE_PAYLOAD_MISSING' };\n }\n const optiga = verifyAuthenticityProof({\n ...common,\n proofType: 'optiga',\n certificates: optigaCertificates,\n signature: optigaSignature,\n });\n if (!optiga.valid) {\n return {\n verified: false,\n deviceCertPubKey: optiga.deviceCertPubKey,\n caPubKey: optiga.caPubKey,\n rootPubKey: optiga.rootPubKey,\n error: optiga.error,\n };\n }\n\n // 2) Trezor Connect requires the independent Tropic proof on T3W1.\n let usedDebugKey = matchedDebugKey(config, deviceModel, optiga.rootPubKey);\n if (isTropicExpected(deviceModel)) {\n const { tropic_certificates: tropicCertificates, tropic_signature: tropicSignature } = proof;\n if (!tropicSignature || !tropicCertificates?.length) {\n return { verified: false, error: 'RESPONSE_PAYLOAD_MISSING' };\n }\n const tropic = verifyAuthenticityProof({\n ...common,\n proofType: 'tropic',\n certificates: tropicCertificates,\n signature: tropicSignature,\n });\n if (!tropic.valid) {\n return { verified: false, error: tropic.error };\n }\n usedDebugKey = usedDebugKey || matchedDebugKey(config, deviceModel, tropic.rootPubKey);\n }\n\n const deviceId = Buffer.from(\n sha3Hash(Uint8Array.from(Buffer.from(optiga.deviceCertPubKey, 'hex')))\n ).toString('hex');\n\n return {\n verified: true,\n deviceId,\n deviceCertPubKey: optiga.deviceCertPubKey,\n serialNumber: optiga.serialNumber,\n rootPubKey: optiga.rootPubKey,\n caPubKey: optiga.caPubKey,\n usedDebugKey,\n };\n } catch (error) {\n // A malicious device can return a malformed certificate that throws deep in\n // the parser; never let that escape as a rejected promise.\n return {\n verified: false,\n error: `RESPONSE_MALFORMED: ${(error as Error)?.message ?? 'parse error'}`,\n };\n }\n};\n","import type { DeviceAuthenticityConfig } from './types';\n\n/**\n * Trezor manufacturing root CA public keys, per internal model.\n * Authoritative upstream source (firmware):\n * https://github.com/trezor/trezor-firmware/blob/main/core/embed/projects/prodtest/cmd/hsm_keys.h\n * Mirrored from @trezor/device-authenticity `deviceAuthenticityConfig`.\n *\n * Devices without a secure element (T1B1, T2T1) do not support AuthenticateDevice\n * and are therefore absent from this config.\n */\nexport const deviceAuthenticityConfig: DeviceAuthenticityConfig = {\n version: 2,\n T2B1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '04ca97480ac0d7b1e6efafe518cd433cec2bf8ab9822d76eafd34363b55d63e60380bff20acc75cde03cffcb50ab6f8ce70c878e37ebc58ff7cca0a83b16b15fa5',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T3B1\n '047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a',\n ],\n },\n },\n T3B1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '045b5c3fdd01f3602092834209b86df0ca86a9faf25cac35c73bf6237d66eb21eafcec3706f1ccd5eb4cc7f2fa1751213eccb1c78389afba89a5788ff31ee46a5d',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256 shared with T2B1\n '047f77368dea2d4d61e989f474a56723c3212dacf8a808d8795595ef38441427c4389bc454f02089d7f08b873005e4c28d432468997871c0bf286fd3861e21e96a',\n ],\n },\n },\n T3T1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '041854b27fb1d9f65abb66828e78c9dc0ca301e66081ab0c6a4d104f9df1cd0ad5a7c75f77a8c092f55cf825d2abaf734f934c9394d5e75f75a5a06a5ee9be93ae',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256\n '04e48b69cd7962068d3cca3bcc6b1747ef496c1e28b5529e34ad7295215ea161dbe8fb08ae0479568f9d2cb07630cb3e52f4af0692102da5873559e45e9fa72959',\n ],\n },\n },\n T3W1: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_PROD_P256\n '040dde0d3e0d4da593fac6fd02a461d0e7eef238aca55c7c50b4e9ec37f3873303b6429ef1c9b78b4411a7dcbbc5dde5225979c1c2da3b073e82b1ed3f5f9825bb',\n // upstream: DEV_AUTH_ROOT_PROD_BACKUP_P256\n '04c6a673af4ec44b10441b1d78676e15173ad0e36df9f7f2fa1cd819955f20fe32917b60da5fed3b3aa54a9ab8b3ed27d198b3768cad26eef5935cd87af0af065e',\n ],\n rootPubKeysTropic: [\n // upstream: DEV_AUTH_ROOT_PROD_ED25519\n '59237acd17134061d655b3f8d624573ca06ce8d862f38ba4e05140ce1d3d609d',\n // upstream: DEV_AUTH_ROOT_PROD_BACKUP_ED25519\n '5612606584ee7e0bc313b13f7ac94156bb4cb75bd77585ddbe579301306e85f1',\n ],\n debug: {\n rootPubKeysOptiga: [\n // upstream: DEV_AUTH_ROOT_DEBUG_P256\n '04521192e173a9da4e3023f747d836563725372681eba3079c56ff11b2fc137ab189eb4155f371127651b5594f8c332fc1e9c0f3b80d4212822668b63189706578',\n // upstream: DEV_AUTH_ROOT_STAGING_P256\n '0465e88f9b2cea67e8364f0cfcfacd500af24e9040b357beee629ccc4fce1704d1a7ef7284f387708f92ef14600e2caad6894016fee819d623b95d66210c3e7519',\n ],\n rootPubKeysTropic: [\n // upstream: DEV_AUTH_ROOT_STAGING_ED25519\n 'cd318dc8405ae4f4144e3284dcb7b0cb0f0c2195c2ca14a0f6fccd9104e32a4b',\n ],\n },\n },\n};\n","import type { Oid, ParsedCertificate } from './x509certificate';\n\nexport const findSubjectContentByOid = (\n deviceCert: ParsedCertificate,\n oid: Oid\n): Uint8Array | null => {\n const subjectItems = deviceCert.tbsCertificate.subject;\n const matchedItem = subjectItems.find(({ algorithmOid }) => algorithmOid === oid);\n if (!matchedItem || !matchedItem.parameters) return null;\n\n return matchedItem.parameters.asn1.contents;\n};\n","import { type parseCertificate } from './x509certificate';\n\n// Check that this certificate is a valid Trezor CA.\n// KeyUsage must be present and allow certificate signing.\n// BasicConstraints must be present, have the cA flag and a pathLenConstraint.\n// Any unrecognized non-critical extension is allowed. Any unrecognized critical extension is disallowed.\nexport const validateCaCertExtensions = (\n cert: ReturnType<typeof parseCertificate>,\n pathLen: number\n) => {\n let hasKeyUsage = false;\n let hasBasicConstraints = false;\n cert.tbsCertificate.extensions.forEach(ext => {\n if (ext.key === 'keyUsage') {\n if (ext.keyCertSign !== '1') {\n throw new Error(`CA keyCertSign not set`);\n }\n hasKeyUsage = true;\n } else if (ext.key === 'basicConstraints') {\n if (!ext.cA) {\n throw new Error(`CA basicConstraints.cA not set`);\n }\n if (typeof ext.pathLenConstraint !== 'number') {\n throw new Error('CA basicConstraints.pathLenConstraint not set');\n }\n if (ext.pathLenConstraint < pathLen) {\n throw new Error('Issuer was not permitted to issue certificate');\n }\n hasBasicConstraints = true;\n } else if (ext.critical) {\n throw new Error(`Unknown critical extension ${ext.key} in CA certificate`);\n }\n });\n\n if (!hasKeyUsage || !hasBasicConstraints) {\n throw new Error(\n `CA missing extensions keyUsage: ${hasKeyUsage}, basicConstraints: ${hasBasicConstraints}`\n );\n }\n};\n","import { ed25519 } from '@noble/curves/ed25519';\nimport { p256 } from '@noble/curves/p256';\nimport { sha256 } from '@noble/hashes/sha256';\n\nimport { type AlgorithmName, fixSignature } from './x509certificate';\n\nexport type VerifySignature = (\n rawKey: Uint8Array,\n data: Uint8Array,\n signature: Uint8Array\n) => boolean;\n\n// P-256 (secp256r1) ECDSA over SHA-256. Hardware attestation signatures are NOT\n// guaranteed to be low-S normalized, so lowS must be disabled or valid signatures\n// would be rejected. `fixSignature` repairs the 1-in-256 malformed Optiga DER encoding.\nexport const verifySignatureP256: VerifySignature = (rawKey, data, signature) => {\n try {\n const sig = p256.Signature.fromDER(Buffer.from(fixSignature(signature)).toString('hex'));\n\n return p256.verify(sig.toBytes('compact'), sha256(data), rawKey, { lowS: false });\n } catch {\n // invalid inputs (e.g. an Ed25519 signature with a P-256 key) are an\n // unsuccessful verification, not a runtime error\n return false;\n }\n};\n\nexport const verifySignatureEd25519: VerifySignature = (rawKey, data, signature) => {\n try {\n return ed25519.verify(signature, data, rawKey);\n } catch {\n return false;\n }\n};\n\nexport const getVerifyFn = (algorithmName: AlgorithmName): VerifySignature => {\n if (algorithmName === 'P-256') return verifySignatureP256;\n if (algorithmName === 'Ed25519') return verifySignatureEd25519;\n throw new Error(`Unsupported signature algorithm: ${algorithmName}`);\n};\n","/**\n * Parse an x509 certificate returned from Trezor (AuthenticityProof) from DER format.\n * Ported from @trezor/device-authenticity (self-contained, no external deps).\n * inspired by https://blog.engelke.com/2014/10/21/web-crypto-and-x-509-certificates/\n */\n\ninterface Asn1 {\n cls: number; // ASN.1 class of the object.\n tag: number; // ASN.1 object type.\n structured: boolean; // Structured objects are encoded ASN.1 objects. Other objects (primitive) values depends on the tag and class\n byteLength: number; // value size\n contents: Uint8Array; // byte array containing the object value.\n raw: Uint8Array; // original byte array\n}\n\ntype OneOrTwoNumbers = `${number}` | `${number}.${number}`;\n// type that allows between 4 to 8 numbers to specify an OID\nexport type Oid = `${OneOrTwoNumbers}.${OneOrTwoNumbers}.${OneOrTwoNumbers}.${OneOrTwoNumbers}`;\n\n// algorithms supported to verify certificates and signatures\nexport type AlgorithmName = 'P-256' | 'Ed25519' | 'MLDSA44' | 'unknown';\n\ntype Extension =\n | {\n key: 'keyUsage';\n critical?: boolean;\n keyCertSign: '0' | '1';\n }\n | {\n key: 'basicConstraints';\n critical?: boolean;\n cA: boolean;\n pathLenConstraint?: number;\n }\n | (Asn1 & {\n key: Oid;\n critical?: boolean;\n });\n\nconst parseOidToAlgorithmName = (oid: Oid): AlgorithmName => {\n if (oid === '1.2.840.10045.4.3.2') return 'P-256'; // https://oid-base.com/get/1.2.840.10045.4.3.2\n if (oid === '1.3.101.112') return 'Ed25519'; // https://oid-base.com/get/1.3.101.112\n if (oid === '2.16.840.1.101.3.4.3.17') return 'MLDSA44'; // https://oid-base.com/get/2.16.840.1.101.3.4.3.17\n\n return 'unknown';\n};\n\nconst derToAsn1 = (byteArray: Uint8Array): Asn1 => {\n let position = 0;\n\n function getTag() {\n let tag = byteArray[0] & 0x1f;\n position += 1;\n if (tag === 0x1f) {\n tag = 0;\n while (byteArray[position] >= 0x80) {\n tag = tag * 128 + byteArray[position] - 0x80;\n position += 1;\n }\n tag = tag * 128 + byteArray[position] - 0x80;\n position += 1;\n }\n\n return tag;\n }\n\n function getLength() {\n let length = 0;\n\n if (byteArray[position] < 0x80) {\n length = byteArray[position];\n position += 1;\n } else {\n const numberOfDigits = byteArray[position] & 0x7f;\n position += 1;\n length = 0;\n for (let i = 0; i < numberOfDigits; i++) {\n length = length * 256 + byteArray[position];\n position += 1;\n }\n }\n\n return length;\n }\n\n const cls = (byteArray[0] & 0xc0) / 64;\n const structured = (byteArray[0] & 0x20) === 0x20;\n const tag = getTag();\n\n if (byteArray[position] === 0x80) {\n // DER forbids indefinite length encoding. You must use the definite length encoding (that is, with the length specified at the beginning).\n // https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/\n throw new Error('Unsupported length encoding');\n }\n\n const length = getLength(); // As encoded, which may be special value 0\n const byteLength = position + length;\n const contents = byteArray.subarray(position, byteLength);\n\n const raw = byteArray.subarray(0, byteLength); // May not be the whole input array\n\n return {\n cls,\n tag,\n structured,\n byteLength,\n contents,\n raw,\n };\n};\n\nconst derToAsn1List = (byteArray: Uint8Array) => {\n const result = [];\n let nextPosition = 0;\n while (nextPosition < byteArray.length) {\n const nextPiece = derToAsn1(byteArray.subarray(nextPosition));\n result.push(nextPiece);\n nextPosition += nextPiece.byteLength;\n }\n\n return result;\n};\n\nconst derBitStringValue = (byteArray: Uint8Array) => ({\n unusedBits: byteArray[0],\n bytes: byteArray.subarray(1),\n});\n\nconst parseSignatureValue = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 3 || asn1.structured) {\n throw new Error('Bad signature value. Not a BIT STRING.');\n }\n\n return {\n asn1,\n bits: derBitStringValue(asn1.contents),\n };\n};\n\n// Optiga may produce a malformed signature with probability 1 in 256.\n// https://github.com/trezor/trezor-firmware/issues/3411\nexport const fixSignature = (byteArray: Uint8Array) => {\n const asn1 = derToAsn1(byteArray);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad signature. Not a SEQUENCE.');\n }\n\n const items = derToAsn1List(asn1.contents);\n let newLength = 0;\n const fixedItems = items.map(chunk => {\n // find first significant byte\n const index = chunk.contents.findIndex(value => value > 0x00);\n const data = chunk.contents.subarray(index);\n // According to the DER-encoding rules, the integers are supposed to be prefixed with a 0x00 byte\n // if **and only if** the most significant byte is >= 0x80\n const offset = data[0] >= 0x80 ? 1 : 0;\n // create replacement for chunk\n const chunkLength = data.length + offset;\n const newChunk = new Uint8Array(chunkLength + 2);\n // set first two bytes: original value and new length of the chunk\n newChunk.set([chunk.raw[0], chunkLength]);\n // optionally add 0\n if (offset > 0) {\n newChunk.set([0], 2);\n }\n // fill new chunk with data\n newChunk.set(data, 2 + offset);\n newLength += newChunk.length;\n\n return newChunk;\n });\n\n // create replacement for sequence object\n const signature = new Uint8Array(newLength + 2);\n // set two first bytes: original value and new length of all chunks\n signature.set([byteArray[0], newLength]);\n // fill new sequence with fixed items\n let signatureOffset = 2;\n fixedItems.forEach(item => {\n signature.set(item, signatureOffset);\n\n signatureOffset += item.length;\n });\n\n return signature;\n};\n\nconst derObjectIdentifierValue = (byteArray: Uint8Array) => {\n let oid = `${Math.floor(byteArray[0] / 40)}.${byteArray[0] % 40}`;\n let position = 1;\n while (position < byteArray.length) {\n let nextInteger = 0;\n while (byteArray[position] >= 0x80) {\n nextInteger = nextInteger * 0x80 + (byteArray[position] & 0x7f);\n position += 1;\n }\n nextInteger = nextInteger * 0x80 + byteArray[position];\n position += 1;\n oid += `.${nextInteger}`;\n }\n\n return oid as Oid;\n};\n\n/*\n * AlgorithmIdentifier ::= SEQUENCE {\n * algorithm OBJECT IDENTIFIER,\n * parameters ANY DEFINED BY algorithm OPTIONAL\n * }\n */\nconst parseAlgorithmIdentifier = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad algorithm identifier. Not a SEQUENCE.');\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length > 2) {\n throw new Error('Bad algorithm identifier. Contains too many child objects.');\n }\n const encodedAlgorithm = pieces[0];\n if (encodedAlgorithm.cls !== 0 || encodedAlgorithm.tag !== 6 || encodedAlgorithm.structured) {\n throw new Error('Bad algorithm identifier. Does not begin with an OBJECT IDENTIFIER.');\n }\n const algorithmOid = derObjectIdentifierValue(encodedAlgorithm.contents);\n const algorithmName = parseOidToAlgorithmName(algorithmOid);\n\n return {\n asn1,\n algorithmOid,\n algorithmName,\n parameters: pieces.length === 2 ? { asn1: pieces[1] } : null,\n };\n};\n\n/*\n * Name ::= SEQUENCE {\n * algorithm OBJECT IDENTIFIER,\n * parameters ANY DEFINED BY algorithm OPTIONAL\n * }\n */\nexport const parseName = (asn1: Asn1) =>\n // SEQUENCE > SET > SEQUENCE\n derToAsn1List(asn1.contents).map(item => {\n const attrSet = derToAsn1(item.contents);\n\n return parseAlgorithmIdentifier(attrSet);\n });\n\n/*\n * SubjectPublicKeyInfo ::= SEQUENCE {\n * algorithm AlgorithmIdentifier,\n * subjectPublicKey BIT STRING\n * }\n */\nconst parseSubjectPublicKeyInfo = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error('Bad SPKI. Not a SEQUENCE.');\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length !== 2) {\n throw new Error('Bad SubjectPublicKeyInfo. Wrong number of child objects.');\n }\n\n return {\n asn1,\n algorithm: parseAlgorithmIdentifier(pieces[0]),\n bits: derBitStringValue(pieces[1].contents),\n };\n};\n\n/*\n * Time ::= CHOICE {\n * utcTime UTCTime,\n * generalTime GeneralizedTime\n * }\n * NOTE: UTC and generalized times may both appear. (generalized > 2050)\n */\nconst parseUtcTime = (time: Asn1) => {\n // tag: 23 = UTCTime (YYMMDDhhmmZ);\n // tag: 24 = GeneralizedTime (YYYYMMDDhhmmZ)\n let offset = 4;\n let yearOffset = 0;\n if (time.tag === 23) {\n offset = 2;\n yearOffset = 2000;\n }\n const utc = Buffer.from(time.contents).toString();\n const year = yearOffset + Number(utc.substring(0, offset));\n const month = Number(utc.substring(offset, offset + 2)) - 1;\n const day = Number(utc.substring(offset + 2, offset + 4));\n const hour = Number(utc.substring(offset + 4, offset + 6));\n const minute = Number(utc.substring(offset + 6, offset + 8));\n\n const date = new Date();\n date.setUTCFullYear(year, month, day);\n date.setUTCHours(hour, minute, 0);\n\n return date;\n};\n\n/*\n * Validity ::= SEQUENCE {\n * from Time,\n * to Time\n * }\n */\nconst parseValidity = (asn1: Asn1) => {\n const [from, to] = derToAsn1List(asn1.contents);\n\n return {\n from: parseUtcTime(from),\n to: parseUtcTime(to),\n };\n};\n\n/*\n * https://www.alvestrand.no/objectid/2.5.29.html\n * Extensions ::= SEQUENCE {\n * extnID OBJECT IDENTIFIER,\n * critical BOOLEAN OPTIONAL,\n * extnValue OCTET STRING\n * }\n */\nconst parseExtensions = (data: Asn1) => {\n const asn1 = derToAsn1(data.contents);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be a Extension. Wrong data type.\");\n }\n\n const readBoolean = (value?: Asn1) => {\n if (!value) return false;\n if (value.cls !== 0 || value.tag !== 1 || value.contents.length !== 1 || value.structured) {\n throw new Error(\"This can't be a boolean. Wrong data type.\");\n }\n if (![0x00, 0xff].includes(value.contents[0])) {\n throw new Error('Invalid boolean value.');\n }\n\n return value.contents[0] === 0xff;\n };\n\n const readBitString = (uint8Array: Uint8Array) => {\n const buffer = Buffer.from(uint8Array);\n const tag = buffer.readUInt8(0);\n if (tag !== 3) {\n throw new Error(\"This can't be a bit string. Wrong data type.\");\n }\n const length = buffer.readUInt8(1);\n const unusedBits = buffer.readUInt8(2);\n const bitStringBytes = buffer.subarray(3, 3 + length - 1); // -1 because the length includes the unusedBits byte\n const bitString = bitStringBytes.reduce(\n (str, byte) => str + byte.toString(2).padStart(8, '0'),\n ''\n );\n\n return bitString.slice(0, bitString.length - unusedBits) as '01';\n };\n\n const readInteger = (value?: Asn1) => {\n if (!value) return undefined;\n if (value.cls !== 0 || value.tag !== 2 || value.contents.length !== 1 || value.structured) {\n throw new Error(\"This can't be a integer. Wrong data type.\");\n }\n\n return Buffer.from(value.contents).readInt8();\n };\n\n const extensions: Extension[] = [];\n derToAsn1List(asn1.contents).forEach(item => {\n const [id, ...pieces] = derToAsn1List(item.contents);\n if (id.cls !== 0 || id.tag !== 6 || id.structured) {\n throw new Error('Bad extension. Does not begin with an OBJECT IDENTIFIER.');\n }\n\n const algorithm = derObjectIdentifierValue(id.contents);\n const critical = pieces.length > 1 ? readBoolean(pieces[0]) : false;\n const extnValue = pieces.length > 1 ? pieces[1] : pieces[0];\n if (extnValue.cls !== 0 || extnValue.tag !== 4 || extnValue.structured) {\n throw new Error(\"This can't be a octet string. Wrong data type.\");\n }\n\n if (algorithm === '2.5.29.15') {\n // https://www.alvestrand.no/objectid/2.5.29.15.html\n extensions.push({\n key: 'keyUsage',\n critical,\n keyCertSign: readBitString(extnValue.contents)[5] as '0' | '1',\n });\n } else if (algorithm === '2.5.29.19') {\n // https://www.alvestrand.no/objectid/2.5.29.19.html\n const fields = derToAsn1List(derToAsn1(extnValue.contents).contents);\n const ca = fields.length > 0 && fields[0].tag === 1 ? fields[0] : undefined;\n const len = fields.length > 0 && fields[0].tag === 2 ? fields[0] : fields[1];\n\n extensions.push({\n key: 'basicConstraints',\n critical,\n cA: readBoolean(ca),\n pathLenConstraint: readInteger(len),\n });\n } else {\n extensions.push({\n key: algorithm,\n critical,\n ...item,\n });\n }\n });\n\n return extensions;\n};\n\n/*\n * TBSCertificate ::= SEQUENCE {\n * version [0] EXPLICIT Version DEFAULT v1,\n * serialNumber CertificateSerialNumber,\n * signature AlgorithmIdentifier,\n * issuer Name[],\n * validity Validity,\n * subject Name[],\n * subjectPublicKeyInfo SubjectPublicKeyInfo,\n * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,\n * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,\n * extensions [3] EXPLICIT Extensions OPTIONAL\n * }\n */\nconst parseTBSCertificate = (asn1: Asn1) => {\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be a TBSCertificate. Wrong data type.\");\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length < 7) {\n throw new Error('Bad TBS Certificate. There are fewer than the seven required children.');\n }\n\n return {\n asn1,\n version: pieces[0],\n serialNumber: pieces[1],\n signature: parseAlgorithmIdentifier(pieces[2]),\n issuer: pieces[3],\n validity: parseValidity(pieces[4]),\n subject: parseName(pieces[5]),\n subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]),\n extensions: parseExtensions(pieces[7]),\n };\n};\n\n/*\n * Certificate ::= SEQUENCE {\n * tbsCertificate TBSCertificate,\n * signatureAlgorithm AlgorithmIdentifier,\n * signatureValue BIT STRING\n * }\n */\nexport const parseCertificate = (byteArray: Uint8Array) => {\n const asn1 = derToAsn1(byteArray);\n if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) {\n throw new Error(\"This can't be an X.509 certificate. Wrong data type.\");\n }\n const pieces = derToAsn1List(asn1.contents);\n if (pieces.length !== 3) {\n throw new Error('Certificate contains more than the three specified children.');\n }\n\n return {\n asn1,\n tbsCertificate: parseTBSCertificate(pieces[0]),\n signatureAlgorithm: parseAlgorithmIdentifier(pieces[1]),\n signatureValue: parseSignatureValue(pieces[2]),\n };\n};\n\nexport type ParsedCertificate = ReturnType<typeof parseCertificate>;\n","import { findSubjectContentByOid } from './findSubjectContentByOid';\nimport {\n type DeviceAuthenticityConfig,\n type VerifyAuthenticityProofParams,\n type VerifyAuthenticityProofResult,\n} from './types';\nimport { validateCaCertExtensions } from './validateCaCertExtensions';\nimport { getVerifyFn } from './verifySignatures';\nimport { type ParsedCertificate, parseCertificate } from './x509certificate';\n\nconst getChunkSize = (byteLength: number): Uint8Array => {\n if (byteLength < 0xfd) return Uint8Array.from([byteLength]);\n if (byteLength <= 0xffff) {\n const b = Buffer.alloc(3);\n b[0] = 0xfd;\n b.writeUInt16LE(byteLength, 1);\n\n return Uint8Array.from(b);\n }\n const b = Buffer.alloc(5);\n b[0] = 0xfe;\n b.writeUInt32LE(byteLength, 1);\n\n return Uint8Array.from(b);\n};\n\n// Compose the data against which the signatures are verified: each chunk is\n// prefixed with its compact-size length. Matches the firmware's signed payload.\nexport const prepareDeviceAuthenticityData = ({\n payload,\n prefix = 'AuthenticateDevice:',\n}: {\n payload: Buffer | Buffer[];\n prefix?: string;\n}): Uint8Array => {\n const chunks = [\n Uint8Array.from(Buffer.from(prefix)),\n ...(Array.isArray(payload) ? payload : [payload]).map(chunk => Uint8Array.from(chunk)),\n ];\n const framed = chunks.flatMap(chunk => [getChunkSize(chunk.byteLength), chunk]);\n const result = new Uint8Array(framed.reduce((total, chunk) => total + chunk.byteLength, 0));\n let offset = 0;\n for (const chunk of framed) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n};\n\nconst getRootPubKeys = ({\n config,\n deviceModel,\n proofType,\n allowDebugKeys,\n}: {\n config: DeviceAuthenticityConfig;\n deviceModel: string;\n proofType: 'optiga' | 'tropic';\n allowDebugKeys?: boolean;\n}): string[] => {\n const modelConfig = config[deviceModel];\n if (!modelConfig || typeof modelConfig === 'number') {\n throw new Error(`Pubkeys for ${deviceModel} not found in config`);\n }\n const prod =\n proofType === 'optiga'\n ? modelConfig.rootPubKeysOptiga ?? []\n : modelConfig.rootPubKeysTropic ?? [];\n if (!allowDebugKeys) return prod;\n\n return [\n ...prod,\n ...(proofType === 'optiga'\n ? modelConfig.debug?.rootPubKeysOptiga ?? []\n : modelConfig.debug?.rootPubKeysTropic ?? []),\n ];\n};\n\nconst matchRootPubKeyToCertificate = ({\n cert,\n allRootPubKeys,\n}: {\n cert: ParsedCertificate;\n allRootPubKeys: string[];\n}): string | undefined => {\n const verifySignatureFn = getVerifyFn(cert.signatureAlgorithm.algorithmName);\n\n return allRootPubKeys.find(rootPubKey =>\n verifySignatureFn(\n Uint8Array.from(Buffer.from(rootPubKey, 'hex')),\n cert.tbsCertificate.asn1.raw,\n cert.signatureValue.bits.bytes\n )\n );\n};\n\n// Get internal model name from the device cert Subject (OID 2.5.4.3), e.g. 'T2B1'.\nconst parseModelFromDeviceCertSubject = (deviceCert: ParsedCertificate) => {\n const modelDescriptionBytes = findSubjectContentByOid(deviceCert, '2.5.4.3');\n if (modelDescriptionBytes === null) return null;\n\n // the whole string is e.g. 'T3W1 Trezor Safe 7', only the first 4 chars are the model\n return Buffer.from(modelDescriptionBytes.subarray(0, 4)).toString();\n};\n\n// Get serial number from the device cert Subject (OID 2.5.4.5). Only present on T3W1 and above.\nconst parseSerialNumberFromDeviceCert = (deviceCert: ParsedCertificate) => {\n const serialNumber = findSubjectContentByOid(deviceCert, '2.5.4.5');\n if (serialNumber === null) return undefined;\n\n return Buffer.from(serialNumber).toString('hex');\n};\n\n/**\n * Verifies the signing scheme: rootPubKey → CA pub key → device key → signature of prefixed challenge.\n * Returns the per-device attestation public key (`deviceCertPubKey`) on success.\n */\nexport const verifyAuthenticityProof = ({\n proofType,\n certificates,\n signature,\n signedData,\n deviceModel,\n config,\n allowDebugKeys,\n caPubKeyBlacklist = [],\n}: VerifyAuthenticityProofParams): VerifyAuthenticityProofResult => {\n const allRootPubKeys = getRootPubKeys({\n config,\n deviceModel,\n proofType,\n allowDebugKeys,\n });\n\n const parsedCertificates = certificates.map(c =>\n parseCertificate(new Uint8Array(Buffer.from(c, 'hex')))\n );\n\n const firstCertAlgName = parsedCertificates[0]?.signatureAlgorithm.algorithmName;\n // This mirrors Trezor Connect's production policy: Optiga uses P-256 and\n // Safe 7's additional Tropic proof uses Ed25519. MCU/ML-DSA is not a separate\n // client-side pass/fail condition.\n const expectedAlgorithmName = proofType === 'optiga' ? 'P-256' : 'Ed25519';\n if (firstCertAlgName !== expectedAlgorithmName) {\n return { valid: false, error: 'RESPONSE_MALFORMED' };\n }\n if (parsedCertificates.length !== 2) {\n return { valid: false, error: 'RESPONSE_MALFORMED' };\n }\n\n const [deviceCert, caCert] = parsedCertificates;\n const deviceCertPubKey = Buffer.from(\n deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes\n ).toString('hex');\n\n const deviceCertAlgName = deviceCert.signatureAlgorithm.algorithmName;\n const caCertAlgName = caCert.signatureAlgorithm.algorithmName;\n if (deviceCertAlgName !== caCertAlgName) {\n return { valid: false, deviceCertPubKey, error: 'RESPONSE_MALFORMED' };\n }\n\n validateCaCertExtensions(caCert, 0); // pathLenConstraint is always 0 (single CA cert, no chain)\n const verifySignatureFn = getVerifyFn(deviceCertAlgName);\n\n // 1) CA certificate must be signed by one of the trusted root pub keys.\n const caPubKeyBytes = caCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes;\n const caPubKey = Buffer.from(caPubKeyBytes).toString('hex');\n const rootPubKeyMatch = matchRootPubKeyToCertificate({ allRootPubKeys, cert: caCert });\n if (rootPubKeyMatch === undefined) {\n return { valid: false, caPubKey, deviceCertPubKey, error: 'ROOT_PUBKEY_NOT_FOUND' };\n }\n // Revocation: reject a specific (e.g. leaked) intermediate CA even if it chains\n // to a trusted root.\n if (caPubKeyBlacklist.includes(caPubKey)) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'CA_PUBKEY_BLACKLISTED',\n };\n }\n // Both the CA and the device leaf must be currently valid: neither cert's\n // notBefore may be in the future, and neither may already be past notAfter.\n // An expired link in the chain must not still verify as trusted.\n const now = Date.now();\n const isWithinValidity = (validity: { from: Date; to: Date }) =>\n validity.from.getTime() <= now && now <= validity.to.getTime();\n if (\n !isWithinValidity(caCert.tbsCertificate.validity) ||\n !isWithinValidity(deviceCert.tbsCertificate.validity)\n ) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'CERTIFICATE_EXPIRED',\n };\n }\n\n // 2) Device model in the certificate must match the connected device.\n const modelFromSubject = parseModelFromDeviceCertSubject(deviceCert);\n if (modelFromSubject !== deviceModel) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_MODEL',\n };\n }\n\n // 3) Device certificate must be signed by the CA pub key.\n const isDeviceCertValid = verifySignatureFn(\n Uint8Array.from(caPubKeyBytes),\n deviceCert.tbsCertificate.asn1.raw,\n deviceCert.signatureValue.bits.bytes\n );\n if (!isDeviceCertValid) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_CERTIFICATE',\n };\n }\n\n // 4) The challenge signature must be produced by the device key.\n const isSignatureValid = verifySignatureFn(\n Uint8Array.from(deviceCert.tbsCertificate.subjectPublicKeyInfo.bits.bytes),\n signedData,\n Uint8Array.from(Buffer.from(signature, 'hex'))\n );\n if (!isSignatureValid) {\n return {\n valid: false,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n error: 'INVALID_DEVICE_SIGNATURE',\n };\n }\n\n return {\n valid: true,\n caPubKey,\n rootPubKey: rootPubKeyMatch,\n deviceCertPubKey,\n serialNumber: parseSerialNumberFromDeviceCert(deviceCert),\n };\n};\n","/**\n * SDK-global event bus. Per-runtime singleton; hosts forward events over their\n * own IPC when the adapter runs in an offscreen/background split.\n */\n\nexport type SdkLogEvent = {\n type: 'log';\n level: 'debug' | 'info' | 'warn' | 'error';\n /** Pre-stringified payload. */\n message: string;\n};\n\nexport type SdkEvent = SdkLogEvent;\n\nexport type SdkEventListener = (event: SdkEvent) => void;\n\nconst listeners = new Set<SdkEventListener>();\n\nexport function onSdkEvent(listener: SdkEventListener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function offSdkEvent(listener: SdkEventListener): void {\n listeners.delete(listener);\n}\n\nexport function emitSdkEvent(event: SdkEvent): void {\n if (listeners.size === 0) return;\n for (const listener of listeners) {\n try {\n listener(event);\n } catch {\n // Logging subscribers must not affect SDK execution.\n }\n }\n}\n\nexport function emitLog(level: SdkLogEvent['level'], ...args: unknown[]): void {\n if (listeners.size === 0) return;\n const message = args.map(a => (typeof a === 'string' ? a : safeStringify(a))).join(' ');\n emitSdkEvent({ type: 'log', level, message });\n}\n\nfunction safeStringify(value: unknown): string {\n if (value instanceof Error) {\n return value.stack ? `${value.message}\\n${value.stack}` : value.message;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n","import { emitLog } from './sdkEventBus';\n\nexport function debugLog(...args: unknown[]): void {\n emitLog('debug', ...args);\n}\n\nexport function debugError(...args: unknown[]): void {\n emitLog('error', ...args);\n}\n","import type { EvmEthereumDefinitions } from '@onekeyfe/hwk-adapter-core';\n\n/**\n * Opt-in helpers for fetching Trezor Ethereum \"definitions\" — the SatoshiLabs-\n * signed network/token metadata a Trezor device uses to render friendly names\n * for chains and tokens that are NOT built into firmware.\n *\n * IMPORTANT — the SDK signing methods (evmSignTransaction / evmGetAddress / …)\n * NEVER call these. A local hardware operation must not silently become a\n * third-party network request (see PR #824 review). The caller decides whether,\n * when, and where to fetch, then passes the result into the sign params as\n * `ethereumDefinitions`. When omitted, the device falls back to a generic\n * confirmation screen and signing still completes.\n *\n * Cross-process note: `fetchImpl` is a FUNCTION and cannot be serialized across\n * an IPC / postMessage boundary. Call these helpers in a network-capable\n * process and send only the resulting hex strings to the process that talks\n * to the device. Use `baseUrl` (a string) to route through your own\n * controlled proxy instead of hitting data.trezor.io directly.\n */\n\n/** Default upstream (Trezor). Override with `baseUrl` to use your own proxy. */\nexport const DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL =\n 'https://data.trezor.io/firmware/eth-definitions';\n\n/** Timeout so a hung host can't stall the signing flow. */\nexport const DEFINITIONS_FETCH_TIMEOUT_MS = 20_000;\n\n/** Race a thunk against a deadline. Generic so it works with any FetchLike on\n * RN/Hermes; a timeout stops awaiting but does not cancel the socket. */\nexport async function runWithTimeout<T>(\n run: () => Promise<T>,\n timeoutMs: number = DEFINITIONS_FETCH_TIMEOUT_MS\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`definitions fetch timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n });\n try {\n return await Promise.race([run(), deadline]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\nexport type FetchLike = (url: string) => Promise<{\n status: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n}>;\n\nexport type FetchEthereumDefinitionsParams = {\n chainId?: number;\n slip44?: number;\n contractAddress?: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport type BuildEthereumDefinitionsForPathParams = {\n path: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport type BuildEthereumDefinitionsForSignTxParams = {\n path: string;\n chainId: number;\n to?: string;\n data?: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\n/** Derive the SLIP-44 coin type (unhardened) from a BIP44-style path. */\nexport function getSlip44FromPath(path: string): number {\n const segments = path.trim().replace(/^m\\//i, '').split('/');\n const coinType = segments[1];\n const parsed = coinType === undefined ? NaN : Number(coinType.replace(/['hH]$/, ''));\n if (!Number.isFinite(parsed)) {\n throw new Error(`Cannot derive SLIP-44 coin type from path: ${path}`);\n }\n return parsed >= 0x80000000 ? parsed - 0x80000000 : parsed;\n}\n\nexport async function fetchEthereumDefinitions({\n chainId,\n slip44,\n contractAddress,\n baseUrl = DEFAULT_ETHEREUM_DEFINITIONS_BASE_URL,\n fetchImpl = globalThis.fetch,\n}: FetchEthereumDefinitionsParams): Promise<EvmEthereumDefinitions> {\n if (!chainId && !slip44) {\n throw new Error('fetchEthereumDefinitions requires chainId or slip44');\n }\n if (!fetchImpl) {\n return {};\n }\n\n const mode = chainId ? 'chain-id' : 'slip44';\n const id = chainId ?? slip44;\n const definitions: EvmEthereumDefinitions = {};\n\n const network = await fetchDefinitionHex(`${baseUrl}/${mode}/${id}/network.dat`, fetchImpl);\n if (network) {\n definitions.encodedNetwork = network;\n }\n\n if (contractAddress) {\n const token = await fetchDefinitionHex(\n `${baseUrl}/${mode}/${id}/token-${stripHexPrefix(contractAddress).toLowerCase()}.dat`,\n fetchImpl\n );\n if (token) {\n definitions.encodedToken = token;\n }\n }\n\n return definitions;\n}\n\nexport async function buildEthereumDefinitionsForPath({\n path,\n baseUrl,\n fetchImpl,\n}: BuildEthereumDefinitionsForPathParams): Promise<EvmEthereumDefinitions> {\n return fetchEthereumDefinitions({\n slip44: getSlip44FromPath(path),\n baseUrl,\n fetchImpl,\n });\n}\n\nexport async function buildEthereumDefinitionsForSignTx({\n path,\n chainId,\n to,\n data,\n baseUrl,\n fetchImpl,\n}: BuildEthereumDefinitionsForSignTxParams): Promise<EvmEthereumDefinitions | undefined> {\n const dataHex = stripHexPrefix(data ?? '');\n if (chainId === 1 && !dataHex) {\n return undefined;\n }\n return fetchEthereumDefinitions({\n chainId,\n slip44: getSlip44FromPath(path),\n contractAddress: dataHex && to ? to : undefined,\n baseUrl,\n fetchImpl,\n });\n}\n\nasync function fetchDefinitionHex(url: string, fetchImpl: FetchLike): Promise<string | undefined> {\n try {\n return await runWithTimeout(async () => {\n const response = await fetchImpl(url);\n if (response.status !== 200) {\n return undefined;\n }\n return arrayBufferToHex(await response.arrayBuffer());\n });\n } catch {\n return undefined;\n }\n}\n\nfunction arrayBufferToHex(value: ArrayBuffer): string {\n return Buffer.from(value).toString('hex');\n}\n\nfunction stripHexPrefix(value: string): string {\n return value.startsWith('0x') || value.startsWith('0X') ? value.slice(2) : value;\n}\n","import { runWithTimeout } from './ethereumDefinitions';\n\nimport type { FetchLike } from './ethereumDefinitions';\n\n/**\n * Opt-in helper for fetching a Trezor Solana token definition. Same contract as\n * the Ethereum helpers (see ./ethereumDefinitions): the SDK signing path NEVER\n * calls this — the caller fetches (through its own `baseUrl` proxy if desired)\n * and passes the bytes into `solSignTransaction` params as\n * `additionalInfo.encodedToken`. When omitted the device shows a generic token\n * confirmation screen and signing still completes.\n *\n * `fetchImpl` is a function and must not cross an IPC boundary — fetch in a\n * network-capable process and pass only the resulting hex string.\n */\n\n/** Default upstream (Trezor). Override with `baseUrl` to use your own proxy. */\nexport const DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL =\n 'https://data.trezor.io/firmware/definitions/solana/token';\n\nexport type FetchSolanaTokenDefinitionParams = {\n tokenMint: string;\n baseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\nexport async function fetchSolanaTokenDefinition({\n tokenMint,\n baseUrl = DEFAULT_SOLANA_TOKEN_DEFINITION_BASE_URL,\n fetchImpl = globalThis.fetch,\n}: FetchSolanaTokenDefinitionParams): Promise<string | undefined> {\n if (!fetchImpl) {\n return undefined;\n }\n try {\n return await runWithTimeout(async () => {\n const response = await fetchImpl(`${baseUrl}/${tokenMint}.dat`);\n if (response.status !== 200) {\n return undefined;\n }\n return Buffer.from(await response.arrayBuffer()).toString('hex');\n });\n } catch {\n return undefined;\n }\n}\n","export const TREZOR_SAFE_7_MODEL = 'T3W1';\n\nexport const TREZOR_BLE_SUPPORTED_MODELS = [TREZOR_SAFE_7_MODEL] as const;\n\nexport const TREZOR_BLE_PACKET_SIZE = 244;\n\nexport const TREZOR_BLE_UUIDS = {\n service: '8c000001-a59b-4d58-a9ad-073df69fa1b1',\n write: '8c000002-a59b-4d58-a9ad-073df69fa1b1',\n notify: '8c000003-a59b-4d58-a9ad-073df69fa1b1',\n push: '8c000004-a59b-4d58-a9ad-073df69fa1b1',\n batteryService: '0000180f-0000-1000-8000-00805f9b34fb',\n} as const;\n","import { TREZOR_BLE_SUPPORTED_MODELS, TREZOR_BLE_UUIDS } from '../constants';\n\nimport type { TrezorBleDescriptor } from '../types';\n\nexport function isTrezorSafe7BleName(name?: string): boolean {\n if (!name) return false;\n return /\\bTrezor\\b/i.test(name) && (/\\bSafe\\s*7\\b/i.test(name) || /\\bT3W1\\b/i.test(name));\n}\n\nexport function isTrezorBleSupportedModel(model?: string): boolean {\n if (!model) return false;\n const normalizedModel = model.trim().replace(/\\s+/g, ' ').toLowerCase();\n return (\n TREZOR_BLE_SUPPORTED_MODELS.some(\n supportedModel => supportedModel.toLowerCase() === normalizedModel\n ) ||\n normalizedModel === 'safe 7' ||\n normalizedModel === 'trezor safe 7'\n );\n}\n\nexport function isTrezorSafe7BleDescriptor(descriptor: TrezorBleDescriptor): boolean {\n return isTrezorBleDescriptor(descriptor);\n}\n\nexport function normalizeTrezorBleUuid(uuid: string): string {\n return uuid.replace(/-/g, '').toLowerCase();\n}\n\nexport function isTrezorBleServiceUuid(uuid: string): boolean {\n return normalizeTrezorBleUuid(uuid) === normalizeTrezorBleUuid(TREZOR_BLE_UUIDS.service);\n}\n\nexport function isTrezorBleDescriptor(descriptor: TrezorBleDescriptor): boolean {\n const serviceUuids = [\n ...(descriptor.serviceUUIDs ?? []),\n ...(descriptor.advertisedServiceUuids ?? []),\n ...(descriptor.serviceUuids ?? []),\n ];\n return serviceUuids.some(isTrezorBleServiceUuid);\n}\n\nexport function resolveTrezorBleConnectId(descriptor: TrezorBleDescriptor): string {\n return descriptor.id ?? descriptor.path ?? descriptor.deviceId ?? descriptor.name ?? '';\n}\n"]}