From 3981a25fcbc6d7ba695f5c87f093bd6a01f696d8 Mon Sep 17 00:00:00 2001 From: iGroza Date: Wed, 14 Feb 2024 07:42:05 +0700 Subject: [PATCH 1/2] feat: rxjs support --- src/device-access.ts | 374 +++++++++++++++++++++++++++++++++++ src/provider.ts | 456 +++++++++++++++++++++---------------------- 2 files changed, 602 insertions(+), 228 deletions(-) create mode 100644 src/device-access.ts diff --git a/src/device-access.ts b/src/device-access.ts new file mode 100644 index 0000000..04ab960 --- /dev/null +++ b/src/device-access.ts @@ -0,0 +1,374 @@ +import { + BluetoothRequired, + CantOpenDevice, + DeviceHalted, + EthAppPleaseEnableContractData, + FirmwareOrAppUpdateRequired, + PairingFailed, + PeerRemovedPairing, + TransportInterfaceNotAvailable, + TransportStatusError, + TransportWebUSBGestureRequired, + UpdateYourApp, + WrongAppForCurrency, + WrongDeviceForAccount, +} from '@ledgerhq/errors'; +import {trace, LocalTracer, TraceContext} from '@ledgerhq/logs'; +import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'; +import {throwError, timer, Observable, Subscription} from 'rxjs'; +import {catchError, mergeMap, retryWhen} from 'rxjs/operators'; + +const LOG_TYPE = 'haqq-ledger'; + +// delay when polling device +const WITH_DEVICE_POLLING_DELAY = 500; + +const initialErrorRemapping = (error: unknown, context?: TraceContext) => { + let mappedError = error; + + if (error && error instanceof TransportStatusError) { + if (error.statusCode === 0x6faa) { + mappedError = new DeviceHalted(error.message); + } else if (error.statusCode === 0x6b00) { + mappedError = new FirmwareOrAppUpdateRequired(error.message); + } + } + + trace({ + type: LOG_TYPE, + message: `Initial error remapping: ${error}`, + data: {error, mappedError}, + context, + }); + return throwError(() => mappedError); +}; + +let errorRemapping = (e: any) => throwError(() => e); + +export const setErrorRemapping = ( + f: (arg0: Error) => Observable, +): void => { + errorRemapping = f; +}; +/* tslint:disable:no-empty */ +const never = new Promise(() => {}); + +/** + * Wrapper to pipe a "cleanup" function at then end of an Observable flow. + * + * The `finalize` is only called once if there is an error and a complete + * (but normally an error event completes automatically the Observable pipes. Is it needed ?) + */ +function transportFinally(cleanup: () => Promise) { + return (observable: Observable): Observable => { + return new Observable(o => { + let done = false; + + const finalize = () => { + if (done) return never; + done = true; + return cleanup(); + }; + + const sub = observable.subscribe({ + next: e => o.next(e), + complete: () => { + finalize().then(() => o.complete()); + }, + error: e => { + finalize().then(() => o.error(e)); + }, + }); + + return () => { + sub.unsubscribe(); + finalize(); + }; + }); + }; +} + +const identifyTransport = (t: any) => (typeof t.id === 'string' ? t.id : ''); + +const needsCleanup: Record = {}; +// When a series of APDUs are interrupted, this is called +// so we don't forget to cleanup on the next withDevice +export const cancelDeviceAction = (transport: TransportBLE): void => { + const transportId = identifyTransport(transport); + trace({ + type: LOG_TYPE, + message: 'Cancelling device action', + data: {transportId}, + }); + + needsCleanup[transportId] = true; +}; + +export type QueuedJob = {job: Promise; id: number}; + +/** + * Manages queued jobs for each device (id) + * + * Careful: a USB-connected device has no unique id, and its `deviceId` will be an empty string. + * + * The queue object `queuedJobsByDevice` only stores, for each device, the latest void promise that will resolve + * when the device is ready to be opened again. + * They are scheduled to resolve whenever the job associated to the device is finished. + * When calling withDevice several times, the new promise will be chained to the "then" of the previous promise: + * open(device) -> execute job -> clean connection -> resolve promise -> next promise can start: open(device) -> etc. + * So a queue is indeed created for each device, by creating a chain of promises, but only the end of the queue is stored for each device. + */ +export class DeviceQueuedJobsManager { + // For each device, queue of linked Promises that wait after each other, blocking any future job for a given device + private queuedJobsByDevice: {[deviceId: string]: QueuedJob}; + + private static instance: DeviceQueuedJobsManager | null = null; + + // To be able to differentiate withDevice calls in our logs + private static jobIdCounter: number = -1; + + private constructor() { + this.queuedJobsByDevice = {}; + } + + /** + * Get the singleton instance + */ + static getInstance(): DeviceQueuedJobsManager { + if (!this.instance) { + this.instance = new DeviceQueuedJobsManager(); + } + + return this.instance; + } + + /** + * Returns the latest queued job for a given device id + * + * @param deviceId + * @returns the latest QueuedJob. If none, return a queued job that can be resolved directly. + */ + getLastQueuedJob(deviceId: string): QueuedJob { + return ( + this.queuedJobsByDevice[deviceId] || {job: Promise.resolve(), id: -1} + ); + } + + /** + * Sets the latest queue job for a given device id + * + * Also increments the job id counter and set the newly queued job id to this new incremented value. + * + * Note: we should be fine on race conditions when updating the jobId in our use cases. + * + * @param deviceId + * @param jobToQueue a Promise that resolve to void, representing an async job + * @returns the id of the queued job + */ + setLastQueuedJob(deviceId: string, jobToQueue: Promise): number { + const id = ++DeviceQueuedJobsManager.jobIdCounter; + this.queuedJobsByDevice[deviceId] = {job: jobToQueue, id}; + return id; + } +} + +/** + * Provides a Transport instance to a given job + * + * @param deviceId + * @param options contains optional configuration + * - openTimeoutMs: optional timeout that limits in time the open attempt of the matching registered transport. + */ +export const withDevice = + (deviceId: string, options?: {openTimeoutMs?: number}) => + (job: (t: TransportBLE) => Observable): Observable => + new Observable(o => { + const queuedJobManager = DeviceQueuedJobsManager.getInstance(); + const previousQueuedJob = queuedJobManager.getLastQueuedJob(deviceId); + + // When the new job is finished, this will unlock the associated device queue of jobs + let resolveQueuedJob: (value: PromiseLike | void) => void; + + const jobId = queuedJobManager.setLastQueuedJob( + deviceId, + new Promise(resolve => { + resolveQueuedJob = resolve; + }), + ); + + const tracer = new LocalTracer(LOG_TYPE, { + jobId, + deviceId, + origin: 'haqq-hw:withDevice', + }); + tracer.trace(`New job for device: ${deviceId || 'unknown BLE device'}`); + + // To call to cleanup the current transport + const finalize = async ( + transport: TransportBLE, + cleanups: (() => void)[], + ) => { + tracer.trace('Closing and cleaning transport', {function: 'finalize'}); + + try { + await transport.close(); + } catch (error) { + tracer.trace( + `An error occurred when closing transport (ignoring it): ${error}`, + { + error, + function: 'finalize', + }, + ); + } + cleanups.forEach(c => c()); + }; + + let unsubscribed = false; + let sub: Subscription | undefined; + + tracer.trace('Waiting for the previous job in the queue to complete', { + previousJobId: previousQueuedJob.id, + }); + // For any new job, we'll now wait the exec queue to be available + previousQueuedJob.job + .then(() => { + tracer.trace( + 'Previous queued job resolved, now trying to get a Transport instance', + { + previousJobId: previousQueuedJob.id, + currentJobId: jobId, + }, + ); + // @ts-ignore + return TransportBLE.open( + deviceId, + options?.openTimeoutMs, + tracer.getContext(), + ); + }) // open the transport + .then(async transport => { + tracer.trace('Got a Transport instance from open'); + + if (unsubscribed) { + tracer.trace('Unsubscribed (1) while processing job'); + // It was unsubscribed prematurely + return finalize(transport, [resolveQueuedJob]); + } + + if (needsCleanup[identifyTransport(transport)]) { + delete needsCleanup[identifyTransport(transport)]; + /* tslint:disable:no-empty */ + await transport.send(0, 0, 0, 0).catch(() => {}); + } + + return transport; + }) + // This catch is here only for errors that might happen at open or at clean up of the transport before doing the job + .catch(e => { + tracer.trace(`Error while opening Transport: ${e}`, {error: e}); + resolveQueuedJob(); + if (e instanceof BluetoothRequired) throw e; + if (e instanceof TransportWebUSBGestureRequired) throw e; + if (e instanceof TransportInterfaceNotAvailable) throw e; + if (e instanceof PeerRemovedPairing) throw e; + if (e instanceof PairingFailed) throw e; + throw new CantOpenDevice(e.message); + }) + // Executes the job + .then(transport => { + tracer.trace('Executing job', { + hasTransport: !!transport, + unsubscribed, + }); + if (!transport) return; + + // It was unsubscribed prematurely + if (unsubscribed) { + tracer.trace('Unsubscribed (2) while processing job'); + return finalize(transport, [resolveQueuedJob]); + } + + sub = job(transport) + .pipe( + catchError(error => + initialErrorRemapping(error, tracer.getContext()), + ), + catchError(errorRemapping), + transportFinally(() => { + // Closes the transport and cleans up everything + return finalize(transport, [resolveQueuedJob]); + }), + ) + .subscribe({ + next: event => { + // This kind of log should be a "debug" level for ex + // tracer.trace("Job next", { event }); + o.next(event); + }, + error: error => { + tracer.trace('Job error', {error}); + if (error.statusCode) { + o.error(new TransportStatusError(error.statusCode)); + } else { + o.error(error); + } + }, + complete: () => { + o.complete(); + }, + }); + }) + .catch(error => { + tracer.trace(`Caught error on job execution step: ${error}`, {error}); + o.error(error); + }); + + // Returns function to unsubscribe from the job if we don't need it anymore. + // This will prevent us from executing the job unnecessarily later on + return () => { + tracer.trace( + `Unsubscribing withDevice flow. Ongoing job to unsubscribe from ? ${!!sub}`, + ); + unsubscribed = true; + if (sub) sub.unsubscribe(); + }; + }); + +export const genericCanRetryOnError = (err: unknown): boolean => { + if (err instanceof WrongAppForCurrency) return false; + if (err instanceof WrongDeviceForAccount) return false; + if (err instanceof CantOpenDevice) return false; + if (err instanceof BluetoothRequired) return false; + if (err instanceof UpdateYourApp) return false; + if (err instanceof FirmwareOrAppUpdateRequired) return false; + if (err instanceof DeviceHalted) return false; + if (err instanceof TransportWebUSBGestureRequired) return false; + if (err instanceof TransportInterfaceNotAvailable) return false; + if (err instanceof EthAppPleaseEnableContractData) return false; + // tx denied by the user + if (err instanceof TransportStatusError) return err.statusCode !== 0x6985; + return true; +}; + +export const retryWhileErrors = (acceptError: (arg0: Error) => boolean) => { + return (attempts: Observable): Observable => { + return attempts.pipe( + mergeMap(error => { + if (!acceptError(error)) { + return throwError(() => error); + } + + return timer(WITH_DEVICE_POLLING_DELAY); + }), + ); + }; +}; + +export const withDevicePolling = + (deviceId: string) => + ( + job: (arg0: TransportBLE) => Observable, + acceptError: (arg0: Error) => boolean = genericCanRetryOnError, + ): Observable => + withDevice(deviceId)(job).pipe(retryWhen(retryWhileErrors(acceptError))); diff --git a/src/provider.ts b/src/provider.ts index c627103..9ef9948 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -11,263 +11,263 @@ import { import AppEth, {ledgerService} from '@ledgerhq/hw-app-eth'; import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'; import {utils, UnsignedTransaction} from 'ethers'; +import {firstValueFrom, Observable} from 'rxjs'; import {suggestApp} from './commands'; -import {getDeviceConnection} from './get-device-connection'; -import {sleep} from './sleep'; +import {withDevicePolling} from './device-access'; import {ProviderLedgerReactNativeOptions} from './types'; export class ProviderLedgerReactNative extends Provider implements ProviderInterface { - public stop: boolean = false; - private _transport: TransportBLE | null = null; - getIdentifier(): string { return this._options.deviceId; } - async getAccountInfo(hdPath: string) { - let resp = {publicKey: '', address: ''}; - try { - this.stop = false; - - let transport = await this.awaitForTransport(this._options.deviceId); - if (!transport) { - throw new Error('can_not_connected'); - } - - if (this._options.appName) { - await suggestApp(transport, this._options.appName); - this.onDisconnectTransport(); - transport = await this.awaitForTransport(this._options.deviceId); - } - - const eth = new AppEth(transport!); - - const response = await eth.getAddress(hdPath); + withDevice = () => { + return (job: (arg0: TransportBLE) => Observable): Observable => { + return withDevicePolling(this._options.deviceId)( + transport => + new Observable(o => { + this.on('abortCall', () => { + o.error(new Error('aborted')); + o.complete(); + }); + return job(transport).subscribe(o); + }), + ); + }; + }; + + async confirmAddress(hdPath: string) { + return (await this.getAccountInfo(hdPath, true)).address; + } - resp = { - publicKey: compressPublicKey(response.publicKey), - address: response.address, - }; - this.emit('getPublicKeyForHDPath', true); - } catch (e) { - if (e instanceof Error) { - this.catchError(e, 'getPublicKeyForHDPath'); - } - } - return resp; + async getAccountInfo(hdPath: string, showDisplay = false) { + await this.suggestApp(); + return firstValueFrom<{publicKey: string; address: string}>( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + const eth = new AppEth(transport); + const response = await eth.getAddress(hdPath, showDisplay); + + return { + publicKey: compressPublicKey(response.publicKey), + address: response.address, + }; + }; + + run() + .then(result => { + o.next(result); + o.complete(); + }) + .catch(e => { + try { + o.error(e); // resolve in genericCanRetryOnError + } catch (_) { + o.next({publicKey: '', address: ''}); + o.complete(); + this.catchError(e, 'getPublicKeyForHDPath'); + } + }); + }), + ), + ); } async signTransaction(hdPath: string, transaction: TransactionRequest) { - let resp = ''; - try { - this.stop = false; - const unsignedTx = utils - .serializeTransaction(transaction as UnsignedTransaction) - .substring(2); - const resolution = await ledgerService.resolveTransaction( - unsignedTx, - {}, - {}, - ); - - let transport = await this.awaitForTransport(this._options.deviceId); - - if (!transport) { - throw new Error('can_not_connected'); - } - - if (this._options.appName) { - await suggestApp(transport, this._options.appName); - this.onDisconnectTransport(); - transport = await this.awaitForTransport(this._options.deviceId); - } - - const eth = new AppEth(transport!); - - const signature = await eth.signTransaction( - hdPath, - unsignedTx, - resolution, - ); - - resp = utils.serializeTransaction(transaction as UnsignedTransaction, { - ...signature, - r: '0x' + signature.r, - s: '0x' + signature.s, - v: parseInt(signature.v, 10), - }); - - this.emit('signTransaction', true); - } catch (e) { - if (e instanceof Error) { - this.catchError(e, 'signTransaction'); - } - } - - return resp; + await this.suggestApp(); + return firstValueFrom( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + const eth = new AppEth(transport); + const unsignedTx = utils + .serializeTransaction(transaction as UnsignedTransaction) + .substring(2); + const resolution = await ledgerService.resolveTransaction( + unsignedTx, + {}, + {}, + ); + const signature = await eth.signTransaction( + hdPath, + unsignedTx, + resolution, + ); + + return utils.serializeTransaction( + transaction as UnsignedTransaction, + { + ...signature, + r: '0x' + signature.r, + s: '0x' + signature.s, + v: parseInt(signature.v, 10), + }, + ); + }; + + run() + .then(result => { + o.next(result); + o.complete(); + }) + .catch(e => { + try { + o.error(e); // resolve in genericCanRetryOnError + } catch (_) { + o.next(''); + o.complete(); + this.catchError(e, 'signTransaction'); + } + }); + }), + ), + ); } async signPersonalMessage( hdPath: string, message: string | BytesLike, ): Promise { - let resp = ''; - try { - this.stop = false; - const transport = await this.awaitForTransport(this._options.deviceId); - - if (!transport) { - throw new Error('can_not_connected'); - } - - if (this._options.appName) { - await suggestApp(transport, this._options.appName); - } - - const eth = new AppEth(transport); - - const m = Array.from( - typeof message === 'string' ? stringToUtf8Bytes(message) : message, - ); - const signature = await eth.signPersonalMessage( - hdPath, - Buffer.from(m).toString('hex'), - ); - - const v = (signature.v - 27).toString(16).padStart(2, '0'); - resp = '0x' + signature.r + signature.s + v; - - this.emit('signPersonalMessage', true); - } catch (e) { - if (e instanceof Error) { - this.catchError(e, 'signPersonalMessage'); - } - } - - return resp; + await this.suggestApp(); + return firstValueFrom( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + const eth = new AppEth(transport); + const m = Array.from( + typeof message === 'string' + ? stringToUtf8Bytes(message) + : message, + ); + const signature = await eth.signPersonalMessage( + hdPath, + Buffer.from(m).toString('hex'), + ); + + const v = (signature.v - 27).toString(16).padStart(2, '0'); + return '0x' + signature.r + signature.s + v; + }; + + run() + .then(result => { + o.next(result); + o.complete(); + }) + .catch(e => { + try { + o.error(e); // resolve in genericCanRetryOnError + } catch (_) { + o.next(''); + o.complete(); + this.catchError(e, 'signPersonalMessage'); + } + }); + }), + ), + ); } async signTypedData(hdPath: string, typedData: TypedData) { - let resp = ''; - try { - this.stop = false; - - const transport = await this.awaitForTransport(this._options.deviceId); - - if (!transport) { - throw new Error('can_not_connected'); - } - - if (this._options.appName) { - await suggestApp(transport, this._options.appName); - } - - const eth = new AppEth(transport); - - const {domainSeparatorHex, hashStructMessageHex} = - prepareHashedEip712Data(typedData); - const signature = await eth.signEIP712HashedMessage( - hdPath, - domainSeparatorHex, - hashStructMessageHex, - ); - - const v = (signature.v - 27).toString(16).padStart(2, '0'); - resp = '0x' + signature.r + signature.s + v; - - this.emit('signTypedData', true); - } catch (e) { - if (e instanceof Error) { - this.catchError(e, 'signTypedData'); - } - return ''; - } - - return resp; - } - - abort() { - this.emit('abortCall'); - this.stop = true; - } - - async confirmAddress(hdPath: string) { - let resp = ''; - try { - this.stop = false; - - const transport = await this.awaitForTransport(this._options.deviceId); - if (!transport) { - throw new Error('can_not_connected'); - } - - if (this._options.appName) { - await suggestApp(transport, this._options.appName); - } - - const eth = new AppEth(transport); - - const response = await eth.getAddress(hdPath, true); - - resp = response.address; - this.emit('confirmAddress', true); - } catch (e) { - if (e instanceof Error) { - this.emit('confirmAddress', false, e.message); - throw new Error(e.message); - } - } - return resp; + await this.suggestApp(); + return firstValueFrom( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + const {domainSeparatorHex, hashStructMessageHex} = + prepareHashedEip712Data(typedData); + + const eth = new AppEth(transport); + + const signature = await eth.signEIP712HashedMessage( + hdPath, + domainSeparatorHex, + hashStructMessageHex, + ); + + const v = (signature.v - 27).toString(16).padStart(2, '0'); + return '0x' + signature.r + signature.s + v; + }; + + run() + .then(result => { + o.next(result); + o.complete(); + }) + .catch(e => { + try { + o.error(e); // resolve in genericCanRetryOnError + } catch (_) { + o.next(''); + o.complete(); + this.catchError(e, 'signTypedData'); + } + }); + }), + ), + ); } - async awaitForTransport(deviceId: string, taskId?: string) { - let attempts = 0; - let canceled = false; - const _taskId = taskId?.trim?.()?.toLowerCase(); - const stopTaskEventName = `stop-task-${_taskId}`; - const handleStopTask = () => { - canceled = true; - }; - - if (_taskId) { - this.once(stopTaskEventName, handleStopTask); - } - - while (!this._transport && !this.stop && attempts < 115) { - if (canceled) { - throw new Error('canceled'); - } - - try { - const device = await getDeviceConnection(deviceId); - - this._transport = await TransportBLE.open(device); - if (this._transport) { - this._transport.on('disconnect', this.onDisconnectTransport); - } - } catch (e) { - this.emit('awaitForTransport', new Date(), e, attempts); - await sleep(250); - attempts += 1; - } - } + suggestApp = async () => { + return firstValueFrom( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + if (this._options.appName) { + await suggestApp(transport, this._options.appName); + } + }; + + run() + .then(() => { + o.next(true); + o.complete(); + }) + .catch(e => { + try { + o.error(e); // resolve in genericCanRetryOnError + } catch (_) { + o.next(false); + o.complete(); + } + }); + }), + ), + ); + }; - if (_taskId) { - this.off(stopTaskEventName, handleStopTask); - } - return this._transport; + async abort() { + this.emit('abortCall'); + return firstValueFrom( + this.withDevice()( + transport => + new Observable(o => { + const run = async () => { + if (transport.isConnected) { + if (await transport.device.isConnected()) { + transport.device.cancelConnection(); + } + transport.close(); + } + }; + + run().finally(() => { + o.next(); + o.complete(); + }); + }), + ), + ); } - onDisconnectTransport = () => { - if (this._transport) { - this._transport.off('disconnect', this.onDisconnectTransport); - this._transport = null; - } - }; - catchError(e: Error, source: string) { switch (e.name) { case 'TransportStatusError': From f64245e0759415ebf55cc749b67edca64ed1a212 Mon Sep 17 00:00:00 2001 From: iGroza Date: Wed, 14 Feb 2024 07:42:19 +0700 Subject: [PATCH 2/2] chore: update deps --- package.json | 11 +- src/provider.ts | 9 +- yarn.lock | 377 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 305 insertions(+), 92 deletions(-) diff --git a/package.json b/package.json index 19d04c4..31c7618 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@haqq/provider-ledger-react-native", - "version": "0.0.25", + "version": "0.0.26", "description": "Provider for react-native ledger", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -20,9 +20,9 @@ }, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", - "@ledgerhq/hw-app-eth": "6.30.0", - "@ledgerhq/hw-transport": "^6.27.8", - "@ledgerhq/react-native-hw-transport-ble": "6.27.9", + "@ledgerhq/hw-app-eth": "6.35.4", + "@ledgerhq/hw-transport": "6.30.3", + "@ledgerhq/react-native-hw-transport-ble": "6.30.0", "ethers": "^5.7.2", "events": "^3.3.0", "rxjs": "^7.8.0" @@ -35,6 +35,7 @@ }, "devDependencies": { "@haqq/provider-base": "0.0.20", + "@ledgerhq/types-devices": "^6.23.0", "@types/jest": "^29.4.0", "@types/node": "^18.14.1", "@types/react-native": "^0.71.3", @@ -50,4 +51,4 @@ "typedoc-plugin-markdown": "^3.14.0", "typescript": "^4.9.5" } -} \ No newline at end of file +} diff --git a/src/provider.ts b/src/provider.ts index 9ef9948..d18af10 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -38,7 +38,7 @@ export class ProviderLedgerReactNative ); }; }; - + async confirmAddress(hdPath: string) { return (await this.getAccountInfo(hdPath, true)).address; } @@ -63,6 +63,7 @@ export class ProviderLedgerReactNative .then(result => { o.next(result); o.complete(); + this.emit('getPublicKeyForHDPath', true); }) .catch(e => { try { @@ -115,6 +116,7 @@ export class ProviderLedgerReactNative .then(result => { o.next(result); o.complete(); + this.emit('signTransaction', true); }) .catch(e => { try { @@ -159,6 +161,7 @@ export class ProviderLedgerReactNative .then(result => { o.next(result); o.complete(); + this.emit('signPersonalMessage', true); }) .catch(e => { try { @@ -200,6 +203,7 @@ export class ProviderLedgerReactNative .then(result => { o.next(result); o.complete(); + this.emit('signTypedData', true); }) .catch(e => { try { @@ -230,6 +234,7 @@ export class ProviderLedgerReactNative .then(() => { o.next(true); o.complete(); + this.emit('suggestApp', true); }) .catch(e => { try { @@ -237,6 +242,7 @@ export class ProviderLedgerReactNative } catch (_) { o.next(false); o.complete(); + this.emit('suggestApp', false); } }); }), @@ -269,6 +275,7 @@ export class ProviderLedgerReactNative } catchError(e: Error, source: string) { + this.emit('error', e, source); switch (e.name) { case 'TransportStatusError': // @ts-ignore diff --git a/yarn.lock b/yarn.lock index 7c3b5d2..f1ffec9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1563,91 +1563,148 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@ledgerhq/cryptoassets@^6.37.0": - version "6.37.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/cryptoassets/-/cryptoassets-6.37.0.tgz#302833777bcd210809ca7820afb82cff8da5c296" - integrity sha512-xwrDKTS9koQBNNzc7CqgV6zfGHvNFWJjlIL0Kc4O4DVWYR2vUdztUHcvwHD1KPjxNYhVnsgIopmtq47fHt3nMg== +"@ledgerhq/cryptoassets@^11.4.0": + version "11.4.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/cryptoassets/-/cryptoassets-11.4.0.tgz#e32a3ac8eac82530ff5d7ac5df1912b0f187b8cf" + integrity sha512-1M0iNyZlmf4MbLGk6vl5CK3gyHAT0yeUzkMbQn+Eo3JL0Y8ng7bl39GGRVasD7X7d/ue2nrG1bX6peGhLcDL/Q== dependencies: + axios "^1.6.0" + bs58check "^2.1.2" invariant "2" -"@ledgerhq/devices@^7.0.4": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-7.0.7.tgz#3499304a1c9d3aa7399de2ad390719bef5d1e89c" - integrity sha512-PZ9TtaTGBYUm/g0qNKPbECZt7DDNvqM3ILS5wAtOMna2cBR+mrywUGXrkjuOWlHpuqZ8wenaAKveQBbzF2ba8w== +"@ledgerhq/devices@^8.0.8", "@ledgerhq/devices@^8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.2.0.tgz#ef67bf49628252d1779acaa151b1a941acba790e" + integrity sha512-XROTW2gTmmuy+YPPDjdtKKTQ3mfxrPtKtV+a9QFbj8f5MnjVMV0Zpy1BIB4CyIMsVVi4z6+nI67auT7IlsM3SQ== dependencies: - "@ledgerhq/errors" "^6.12.3" - "@ledgerhq/logs" "^6.10.1" - rxjs "6" - semver "^7.3.5" - -"@ledgerhq/devices@^8.0.8": - version "8.0.8" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.0.8.tgz#cd233eb54a044913160c9183be9fb22adae4e071" - integrity sha512-0j7E8DY2jeSSATc8IJk+tXDZ9u+Z7tXxB8I4TzXrfV/8A5exMh/K1IwX6Jt1zlw1wre4CT9MV4mzUs3M/TE7lg== - dependencies: - "@ledgerhq/errors" "^6.15.0" - "@ledgerhq/logs" "^6.11.0" + "@ledgerhq/errors" "^6.16.1" + "@ledgerhq/logs" "^6.12.0" rxjs "^7.8.1" semver "^7.3.5" -"@ledgerhq/errors@^6.12.0", "@ledgerhq/errors@^6.12.3", "@ledgerhq/errors@^6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.15.0.tgz#45cda73915f695cc072cb8a99650830bc5dc6668" - integrity sha512-6xaw5/mgoht62TnL3rXsaQYEFwpnXyNDk1AOSJksIjFHx9bHUnkyVmrnGQDj0JLzi+E7bHEgTrpCs8wpeDh9jA== - -"@ledgerhq/hw-app-eth@6.30.0": - version "6.30.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-6.30.0.tgz#a8e5878b0eac725f0f4fa5e9222ab6e71b536063" - integrity sha512-Mr0apxn/oUXD4DZ2gw3fWJQ1rHDzLCzvoGV7Y1/CLoLy85A3w5nROTrFY0+SZNAIB/tqzWZJ9SQpBg5yXVzmmA== +"@ledgerhq/domain-service@^1.1.17": + version "1.1.17" + resolved "https://registry.yarnpkg.com/@ledgerhq/domain-service/-/domain-service-1.1.17.tgz#55cfd96fc2dc498a9ea6fd7c5aca5efd11a0c982" + integrity sha512-EAnbuuuWJpFYHp1a4fMh8cNk5Lic+4Rwf4xGXAOHKcUUT90Q3/VYiom1+ZZwKA8PBgebbxE695UDKK1SzPvh8Q== + dependencies: + "@ledgerhq/errors" "^6.16.1" + "@ledgerhq/logs" "^6.12.0" + "@ledgerhq/types-live" "^6.44.0" + axios "^1.3.4" + eip55 "^2.1.1" + react "^18.2.0" + react-dom "^18.2.0" + +"@ledgerhq/errors@^6.15.0", "@ledgerhq/errors@^6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.16.1.tgz#df650a9ba105397dee2e8c0ceddf6931c5b25ede" + integrity sha512-4D4wKecGzQpIu7sx03Sg4uE1e8g1oZUndWgw9gw776H8h9ov9c5TxPaldTn2j6orPECAERViLf7LTO4L5pE2Cw== + +"@ledgerhq/evm-tools@^1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@ledgerhq/evm-tools/-/evm-tools-1.0.14.tgz#968dcb0ba74a1f509ea44a35e291aed4d891ec71" + integrity sha512-L1fj3mbcZPueCJ/ZwxKXQegpY561NkxGd8nljF/JVqwH/B1N+usdZb9HZswrsgWjQdxqeQykgz7ZZgYolU+vlg== + dependencies: + "@ledgerhq/cryptoassets" "^11.4.0" + "@ledgerhq/live-env" "^0.9.0" + "@ledgerhq/live-network" "^1.1.11" + crypto-js "4.2.0" + ethers "5.7.2" + +"@ledgerhq/hw-app-eth@6.35.4": + version "6.35.4" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-6.35.4.tgz#e15566d313724ebc8532603fe8f6bf59fde2a2e4" + integrity sha512-afTaEr7AxDLoFI4ThyJTFEKSjCVTcYynQhg/WSH9nZoTEY4Qg9sF6iUvRIC7iyoEv5tjT7L+Ooz/9Q4sh201zQ== dependencies: "@ethersproject/abi" "^5.5.0" "@ethersproject/rlp" "^5.5.0" - "@ledgerhq/cryptoassets" "^6.37.0" - "@ledgerhq/errors" "^6.12.0" - "@ledgerhq/hw-transport" "^6.27.7" - "@ledgerhq/hw-transport-mocker" "^6.27.7" - "@ledgerhq/logs" "^6.10.1" - axios "^0.26.1" - bignumber.js "^9.1.0" - crypto-js "^4.1.1" - -"@ledgerhq/hw-transport-mocker@^6.27.7": - version "6.27.20" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.27.20.tgz#d2b5f82797fad20544995220bb080a527f125198" - integrity sha512-o5nGuMLs/akXUvgD1f2u1DqhiC7Ii8x3fCmdE5KExCMo3dVWYkeeV3LTUzx+bp+daJFeYNKOa9+Z7XpqIuEJtA== + "@ledgerhq/cryptoassets" "^11.4.0" + "@ledgerhq/domain-service" "^1.1.17" + "@ledgerhq/errors" "^6.16.1" + "@ledgerhq/evm-tools" "^1.0.14" + "@ledgerhq/hw-transport" "^6.30.3" + "@ledgerhq/hw-transport-mocker" "^6.28.3" + "@ledgerhq/logs" "^6.12.0" + "@ledgerhq/types-live" "^6.44.0" + axios "^1.3.4" + bignumber.js "^9.1.2" + +"@ledgerhq/hw-transport-mocker@^6.28.3": + version "6.28.3" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.28.3.tgz#d1020727d4d7d5fb6c5feeb876af79daba75aff0" + integrity sha512-V5hf6oPytSgoBx+3eaCMoSZGFHXwEP+89g3somX1paGwJXwnzNX1+ADVr0a/xYQE+l7j3Os8TdVmEj0eF0U75A== + dependencies: + "@ledgerhq/hw-transport" "^6.30.3" + "@ledgerhq/logs" "^6.12.0" + rxjs "^7.8.1" + +"@ledgerhq/hw-transport@6.30.3", "@ledgerhq/hw-transport@^6.29.0", "@ledgerhq/hw-transport@^6.30.3": + version "6.30.3" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.30.3.tgz#5904adb57ac4459e219551aa97ce2d0772393f2b" + integrity sha512-eqtTCGy8wFCxl+hZSEpjVqn1EDjQhFCne/qUyY0aA36efhWUF6bCRAhkq1e5i7g2P6TbxcIM5P5PW67dILuqIQ== + dependencies: + "@ledgerhq/devices" "^8.2.0" + "@ledgerhq/errors" "^6.16.1" + "@ledgerhq/logs" "^6.12.0" + events "^3.3.0" + +"@ledgerhq/live-env@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/live-env/-/live-env-0.9.0.tgz#0f7ccb3ace40a3837e67f4aa2e8690176599358b" + integrity sha512-IRRyYw17Bc5TepOY1c0E1fG9YaCD7Mjl8SCn6VGhGtH932nJkqaGwPqJnrFhFjHXDx4unMSYedmMRWoaR2j0+Q== dependencies: - "@ledgerhq/hw-transport" "^6.29.0" - "@ledgerhq/logs" "^6.11.0" rxjs "^7.8.1" + utility-types "^3.10.0" -"@ledgerhq/hw-transport@^6.27.7", "@ledgerhq/hw-transport@^6.27.8", "@ledgerhq/hw-transport@^6.29.0": - version "6.29.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.29.0.tgz#2b85f39d90b093930f0c7bfc513b29eb47ba97fa" - integrity sha512-WQfzxt3EnnbOmzZVYiCgSmNsqafBOFQn40awvUPY2IZviJRs23/1ANPHAo76bzPV88+Qk0+1wZlcnIanGN6fFA== +"@ledgerhq/live-network@^1.1.11": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@ledgerhq/live-network/-/live-network-1.1.11.tgz#a1217a005065bffa363328741b6b969a226a011e" + integrity sha512-TamiftFWGC8tPkDNv1xSWtPxEbpu5xCmTbmXo9QD+pjjCApWqukuaJeNrW7VkkRYWdY7K8HA4Jz/PgPllNKs5A== + dependencies: + "@ledgerhq/errors" "^6.16.1" + "@ledgerhq/live-env" "^0.9.0" + "@ledgerhq/live-promise" "^0.0.3" + "@ledgerhq/logs" "^6.12.0" + axios "0.26.1" + invariant "^2.2.2" + lru-cache "^7.14.1" + +"@ledgerhq/live-promise@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@ledgerhq/live-promise/-/live-promise-0.0.3.tgz#432693468ddd48f94a24437c01791d59d393adbc" + integrity sha512-/49dRz5XoxUw4TFq0kytU2Vz9w+FoGgG28U8RH9nuUWVPjVhAPvhY/QXUQA+7qqaorEIAYPHF0Rappalawhr+g== + dependencies: + "@ledgerhq/logs" "^6.12.0" + +"@ledgerhq/logs@^6.11.0", "@ledgerhq/logs@^6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-6.12.0.tgz#ad903528bf3687a44da435d7b2479d724d374f5d" + integrity sha512-ExDoj1QV5eC6TEbMdLUMMk9cfvNKhhv5gXol4SmULRVCx/3iyCPhJ74nsb3S0Vb+/f+XujBEj3vQn5+cwS0fNA== + +"@ledgerhq/react-native-hw-transport-ble@6.30.0": + version "6.30.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/react-native-hw-transport-ble/-/react-native-hw-transport-ble-6.30.0.tgz#a5201cef9c4b3dae40674560c97b4e83a31824cf" + integrity sha512-GE3zaGfrpnADmmqS23z/IZWHEBJ4qHUhgc8yBD+czzg/kbGlNpWF3h/kH8dqPov2Vp4Vzvo+5Sxn5TCLzvIKRA== dependencies: "@ledgerhq/devices" "^8.0.8" "@ledgerhq/errors" "^6.15.0" + "@ledgerhq/hw-transport" "^6.29.0" "@ledgerhq/logs" "^6.11.0" - events "^3.3.0" + react-native-ble-plx "2.0.3" + rxjs "^7.8.1" -"@ledgerhq/logs@^6.10.1", "@ledgerhq/logs@^6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-6.11.0.tgz#0d28e7edcf71548506f4304686cba480ba91bbcf" - integrity sha512-HHK9y4GGe4X7CXbRUCh7z8Mp+WggpJn1dmUjmuk1rNugESF6o8nAOnXA+BxwtRRNV3CgNJR3Wxdos4J9qV0Zsg== +"@ledgerhq/types-devices@^6.23.0": + version "6.23.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/types-devices/-/types-devices-6.23.0.tgz#6417fd6fd10981b5a9646e48fca7885ff3573e77" + integrity sha512-aqCwB7R1mrrh5RI4nWtzOEheiri/v4gdH6DwTL4lZPjGHd7WFLIkffBgk1eZxMwvyo/ZbqoiJrSFMB6MGOnS7Q== -"@ledgerhq/react-native-hw-transport-ble@6.27.9": - version "6.27.9" - resolved "https://registry.yarnpkg.com/@ledgerhq/react-native-hw-transport-ble/-/react-native-hw-transport-ble-6.27.9.tgz#4ed065a4d22e4810b6a35430b6d615cced15c683" - integrity sha512-C/eohF5Jz/TekdNoih0dC0E+ZDuvBCI3Y5iHSCpXBkXyMD5lgpYvJjOVEhNJ+FdkHFRPfeiWRGhea93tLVgcrw== +"@ledgerhq/types-live@^6.44.0": + version "6.44.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/types-live/-/types-live-6.44.0.tgz#7fcc95c3ae3b54261e429ad1c65ac887114e8bd0" + integrity sha512-WFXLHsgAm+rJ5oxCl5c+Cr0lNVsX0av0wctEQjLZUF2FSWFvAiqmGMLUd5B0NsLhJaQYFw+iFo7C178DRfoh3w== dependencies: - "@ledgerhq/devices" "^7.0.4" - "@ledgerhq/errors" "^6.12.0" - "@ledgerhq/hw-transport" "^6.27.7" - "@ledgerhq/logs" "^6.10.1" - invariant "^2.2.4" - react-native-ble-plx "2.0.3" - rxjs "6" - uuid "^3.4.0" + bignumber.js "^9.1.2" + rxjs "^7.8.1" "@react-native-community/cli-clean@^10.1.1": version "10.1.1" @@ -2187,18 +2244,32 @@ async@^3.2.2: resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -axios@^0.26.1: +axios@0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== dependencies: follow-redirects "^1.14.8" +axios@^1.3.4, axios@^1.6.0: + version "1.6.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" + integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" @@ -2379,7 +2450,7 @@ big-integer@1.6.36: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36" integrity sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg== -bignumber.js@^9.1.0: +bignumber.js@^9.1.2: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== @@ -2468,13 +2539,22 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "2.x" -bs58@^4.0.1: +bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== dependencies: base-x "^3.0.2" +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -2599,6 +2679,14 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.1.tgz#708a6cdae38915d597afdf3b145f2f8e1ff55f3f" integrity sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w== +cipher-base@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + cjs-module-lexer@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" @@ -2705,6 +2793,13 @@ colorette@^1.0.7: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + command-exists@^1.2.8: version "1.2.9" resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" @@ -2807,6 +2902,17 @@ cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: js-yaml "^3.13.1" parse-json "^4.0.0" +create-hash@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + create-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" @@ -2853,7 +2959,7 @@ crypto-addr-codec@^0.1.7: safe-buffer "^5.2.0" sha3 "^2.1.1" -crypto-js@^4.1.1: +crypto-js@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== @@ -2936,6 +3042,11 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + denodeify@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" @@ -2985,6 +3096,13 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +eip55@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eip55/-/eip55-2.1.1.tgz#28b743c4701ac3c811b1e9fe67e39cf1d0781b96" + integrity sha512-WcagVAmNu2Ww2cDUfzuWVntYwFxbvZ5MvIyLZpMjTTkjD6sCvkGOiS86jTppzu9/gWsc8isLHAeMBWK02OnZmA== + dependencies: + keccak "^3.0.3" + electron-to-chromium@^1.4.251: version "1.4.284" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" @@ -3082,7 +3200,7 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -ethers@^5.7.2: +ethers@5.7.2, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -3321,11 +3439,25 @@ follow-redirects@^1.14.8: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== +follow-redirects@^1.15.4: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -3476,6 +3608,15 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" @@ -3572,12 +3713,12 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -invariant@*, invariant@2, invariant@^2.2.4: +invariant@*, invariant@2, invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -4413,6 +4554,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +keccak@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4527,6 +4677,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" @@ -4576,6 +4731,15 @@ marked@^4.2.12: resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + memoize-one@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -4996,7 +5160,7 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.27, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -5124,6 +5288,11 @@ nocache@^3.0.1: resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.4.tgz#5b37a56ec6e09fc7d401dceaed2eab40c8bfdf79" integrity sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw== +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -5138,6 +5307,11 @@ node-fetch@^2.2.0, node-fetch@^2.6.0: dependencies: whatwg-url "^5.0.0" +node-gyp-build@^4.2.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -5488,6 +5662,11 @@ prop-types@*: object-assign "^4.1.1" react-is "^16.13.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -5514,6 +5693,14 @@ react-devtools-core@^4.26.1: shell-quote "^1.6.1" ws "^7" +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + "react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -5602,7 +5789,7 @@ react-shallow-renderer@^16.15.0: object-assign "^4.1.1" react-is "^16.12.0 || ^17.0.0 || ^18.0.0" -react@18.2.0: +react@18.2.0, react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -5618,6 +5805,15 @@ readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -5788,12 +5984,13 @@ ripemd160-min@0.0.6: resolved "https://registry.yarnpkg.com/ripemd160-min/-/ripemd160-min-0.0.6.tgz#a904b77658114474d02503e819dcc55853b67e62" integrity sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A== -rxjs@6: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== +ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== dependencies: - tslib "^1.9.0" + hash-base "^3.0.0" + inherits "^2.0.1" rxjs@^7.8.0, rxjs@^7.8.1: version "7.8.1" @@ -5807,7 +6004,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5909,6 +6106,14 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +sha.js@^2.4.0: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + sha3@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/sha3/-/sha3-2.1.4.tgz#000fac0fe7c2feac1f48a25e7a31b52a6492cc8f" @@ -6326,7 +6531,7 @@ ts-jest@^29.0.5: semver "^7.5.3" yargs-parser "^21.0.1" -tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.13.0, tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -6501,16 +6706,16 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +utility-types@^3.10.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.11.0.tgz#607c40edb4f258915e901ea7995607fdf319424c" + integrity sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw== + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4"