@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
108 lines • 4.21 kB
JavaScript
import { of } from "rxjs";
import { scan, catchError, tap } from "rxjs/operators";
import { useEffect, useState } from "react";
import { log } from "@ledgerhq/logs";
import { TransportStatusError } from "@ledgerhq/errors";
import { TransactionRefusedOnDevice } from "../../errors";
import { getMainAccount } from "../../account";
import { getAccountBridge } from "../../bridge";
import { createAction as createAppAction } from "./app";
const mapResult = ({ device, signedOperation, transactionSignError, }) => {
if (signedOperation && device) {
return {
signedOperation,
device,
};
}
if (transactionSignError) {
return {
transactionSignError,
};
}
return null;
};
const initialState = {
signedOperation: null,
deviceSignatureRequested: false,
deviceStreamingProgress: null,
transactionSignError: null,
transactionChecksOptInTriggered: false,
transactionChecksOptIn: null,
};
const reducer = (state, e) => {
switch (e.type) {
case "error": {
const { error } = e;
const transactionSignError = error instanceof TransportStatusError && error.statusCode === 0x6985
? new TransactionRefusedOnDevice()
: error;
return { ...initialState, transactionSignError };
}
case "signed":
return { ...state, signedOperation: e.signedOperation };
case "device-signature-requested":
return { ...state, deviceSignatureRequested: true };
case "device-signature-granted":
return { ...state, deviceSignatureRequested: false };
case "device-streaming":
return { ...state, deviceStreamingProgress: e.progress };
case "transaction-checks-opt-in-triggered":
return { ...state, transactionChecksOptInTriggered: true };
case "transaction-checks-opt-in":
return { ...state, transactionChecksOptIn: true };
case "transaction-checks-opt-out":
return { ...state, transactionChecksOptIn: false };
default:
return state;
}
};
export const createAction = (connectAppExec) => {
const useHook = (reduxDevice, { account, parentAccount, transaction, broadcast, appName, dependencies, requireLatestFirmware, manifestId, manifestName, }) => {
const mainAccount = getMainAccount(account, parentAccount);
const appState = createAppAction(connectAppExec).useHook(reduxDevice, {
account: mainAccount,
appName,
dependencies,
requireLatestFirmware,
});
const { device, opened, inWrongDeviceForAccount, error } = appState;
const [state, setState] = useState(initialState);
useEffect(() => {
if (!device || !opened || inWrongDeviceForAccount || error) {
setState(initialState);
return;
}
const bridge = getAccountBridge(mainAccount);
const sub = bridge
.signRawOperation({
account: mainAccount,
transaction,
deviceId: device.deviceId,
deviceModelId: device.modelId,
broadcast,
})
.pipe(catchError(error => of({
type: "error",
error,
})), tap((e) => log("actions-transaction-event", e.type, e)), scan(reducer, initialState))
.subscribe((x) => setState(x));
return () => {
sub.unsubscribe();
};
}, [device, mainAccount, transaction, broadcast, opened, inWrongDeviceForAccount, error]);
return {
...appState,
...state,
manifestId,
manifestName,
deviceStreamingProgress: state.signedOperation || state.transactionSignError
? null // when good app is opened, we start the progress so it doesn't "blink"
: state.deviceStreamingProgress || (appState.opened ? 0 : null),
};
};
return {
useHook,
mapResult,
};
};
//# sourceMappingURL=rawTransaction.js.map