@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
144 lines • 6.06 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAction = exports.signMessageExec = exports.prepareMessageToSign = void 0;
const errors_1 = require("@ledgerhq/errors");
const logs_1 = require("@ledgerhq/logs");
const invariant_1 = __importDefault(require("invariant"));
const react_1 = require("react");
const rxjs_1 = require("rxjs");
const wallet_api_acre_module_1 = require("@ledgerhq/wallet-api-acre-module");
const hw_signMessage_1 = __importDefault(require("../../generated/hw-signMessage"));
const app_1 = require("../actions/app");
const deviceAccess_1 = require("../deviceAccess");
const ACRESetup_1 = require("../../families/bitcoin/ACRESetup");
const account_1 = require("../../account");
const prepareMessageToSign = (account, message) => {
const utf8Message = Buffer.from(message, "hex").toString();
if (!hw_signMessage_1.default[account.currency.family]) {
throw new Error("Crypto does not support signMessage");
}
if ("prepareMessageToSign" in hw_signMessage_1.default[account.currency.family]) {
return hw_signMessage_1.default[account.currency.family].prepareMessageToSign({
account,
message: utf8Message,
});
}
// Default implementation
return { message: utf8Message };
};
exports.prepareMessageToSign = prepareMessageToSign;
const signMessage = (transport, account, opts) => {
const { currency } = account;
let signMessage = hw_signMessage_1.default[currency.family].signMessage;
if ("type" in opts) {
switch (opts.type) {
case wallet_api_acre_module_1.AcreMessageType.Withdraw:
signMessage = ACRESetup_1.messageSigner.signWithdraw;
break;
case wallet_api_acre_module_1.AcreMessageType.SignIn:
signMessage = ACRESetup_1.messageSigner.signIn;
break;
default:
signMessage = ACRESetup_1.messageSigner.signMessage;
break;
}
}
(0, invariant_1.default)(signMessage, `signMessage is not implemented for ${currency.id}`);
return signMessage(transport, account, opts)
.then(result => {
const path = "path" in opts && opts.path ? opts.path : account.freshAddressPath;
(0, logs_1.log)("hw", `signMessage ${currency.id} on ${path} with message [${opts.message}]`, result);
return result;
})
.catch(e => {
const path = "path" in opts && opts.path ? opts.path : account.freshAddressPath;
(0, logs_1.log)("hw", `signMessage ${currency.id} on ${path} FAILED ${String(e)}`);
if (e && e.name === "TransportStatusError") {
if (e.statusCode === 0x6985 || e.statusCode === 0x5501) {
throw new errors_1.UserRefusedAddress();
}
}
throw e;
});
};
const signMessageExec = ({ request, deviceId }) => {
if (!request.account) {
throw new Error("account is required");
}
const { type } = (0, account_1.decodeAccountId)(request.account.id);
if (type === "mock") {
return (0, rxjs_1.from)(Promise.resolve({
signature: "mockedSignature",
}));
}
const result = (0, deviceAccess_1.withDevice)(deviceId)(transport => (0, rxjs_1.from)(signMessage(transport, request.account, request.message)));
return result;
};
exports.signMessageExec = signMessageExec;
const initialState = {
signMessageRequested: null,
signMessageError: null,
signMessageResult: null,
};
const createAction = (connectAppExec, signMessage = exports.signMessageExec) => {
const useHook = (reduxDevice, request) => {
const appState = (0, app_1.createAction)(connectAppExec).useHook(reduxDevice, {
appName: request.appName,
dependencies: request.dependencies,
account: request.isACRE ? undefined : request.account, // Bypass derivation check with ACRE as we can use other addresses than the freshest
});
const { device, opened, inWrongDeviceForAccount, error } = appState;
const [state, setState] = (0, react_1.useState)({
...initialState,
signMessageRequested: request.message,
});
const signedFired = (0, react_1.useRef)(undefined);
const sign = (0, react_1.useCallback)(async () => {
let result;
if (!device) {
setState({
...initialState,
signMessageError: new Error("no Device"),
});
return;
}
try {
result = await (0, rxjs_1.firstValueFrom)(signMessage({
request,
deviceId: device.deviceId,
}));
}
catch (e) {
if (e.name === "UserRefusedAddress") {
e.name = "UserRefusedOnDevice";
e.message = "UserRefusedOnDevice";
}
return setState({ ...initialState, signMessageError: e });
}
setState({ ...initialState, signMessageResult: result?.signature });
}, [device, request]);
(0, react_1.useEffect)(() => {
if (!device || !opened || inWrongDeviceForAccount || error) {
return;
}
if (state.signMessageRequested && !signedFired.current) {
signedFired.current = true;
sign();
}
}, [device, opened, inWrongDeviceForAccount, error, sign, state.signMessageRequested]);
return { ...appState, ...state };
};
return {
useHook,
mapResult: (state) => ({
signature: state.signMessageResult,
error: state.signMessageError,
}),
};
};
exports.createAction = createAction;
exports.default = signMessage;
//# sourceMappingURL=index.js.map