UNPKG

@ledgerhq/live-common

Version:
91 lines (81 loc) 3.02 kB
import { log } from "@ledgerhq/logs"; import { Observable, firstValueFrom, from } from "rxjs"; import semver from "semver"; import { ExchangeTypes, createExchange, isExchangeTypeNg } from "@ledgerhq/hw-app-exchange"; import { withDevice } from "../../hw/deviceAccess"; import type { ExchangeRequestEvent } from "../../hw/actions/startExchange"; import { StartExchangeInput } from "./types"; import { getProviderConfig, getSwapProvider } from "../providers"; const withDevicePromise = (deviceId, fn) => firstValueFrom(withDevice(deviceId)(transport => from(fn(transport)))); const startExchange = (input: StartExchangeInput): Observable<ExchangeRequestEvent> => { return new Observable(o => { let unsubscribed = false; const { device, exchangeType, appVersion, provider } = input; const startExchangeAsync = async () => { await withDevicePromise(device.deviceId, async transport => { log("exchange", `attempt to connect to ${device.deviceId}`); let version; if (unsubscribed) return; if (provider) { switch (exchangeType) { case ExchangeTypes.Swap: { const providerConfig = await getSwapProvider(provider); if (providerConfig.useInExchangeApp === false) { throw new Error(`Unsupported provider type ${providerConfig.type}`); } version = providerConfig.version; break; } default: { const providerConfig = await getProviderConfig(exchangeType, provider); version = providerConfig.version; } } } if (!checkNgPrerequisite(exchangeType, appVersion)) { throw new Error("Incompatible AppExchange version with NG command"); } /** * Note: `transactionRate` is not needed at this stage. It is only used * at the `completeExchange` step */ const exchange = createExchange(transport, exchangeType, undefined, version); const nonce: string = await exchange.startNewTransaction(); o.next({ type: "start-exchange-result", startExchangeResult: { nonce, device }, }); }); }; startExchangeAsync().then( () => { o.complete(); unsubscribed = true; }, error => { o.next({ type: "start-exchange-error", startExchangeError: { error, device }, }); o.complete(); unsubscribed = true; }, ); return () => { unsubscribed = true; }; }); }; // AppExchange Min version supporting NG types const MIN_APP_EXCHANGE_NG = "3.3.0"; /** * If the App-Exchnage version is not high enough, "NG" type can't worked */ function checkNgPrerequisite(exchangeType: ExchangeTypes, appVersion?: string) { if (isExchangeTypeNg(exchangeType) && appVersion && semver.lt(appVersion, MIN_APP_EXCHANGE_NG)) { return false; } return true; } export default startExchange;