UNPKG

@ledgerhq/coin-celo

Version:
85 lines 3.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildSignOperation = void 0; const bignumber_js_1 = require("bignumber.js"); const rxjs_1 = require("rxjs"); const errors_1 = require("@ledgerhq/errors"); const wallet_base_1 = require("@celo/wallet-base"); const index_1 = require("@ledgerhq/coin-framework/account/index"); const buildOptimisticOperation_1 = require("./buildOptimisticOperation"); const buildTransaction_1 = __importDefault(require("./buildTransaction")); const sdk_1 = require("../network/sdk"); /** * Sign Transaction with Ledger hardware */ const buildSignOperation = (signerContext) => ({ account, transaction, deviceId, }) => new rxjs_1.Observable(o => { let cancelled; async function main() { const { fees } = transaction; if (!fees) throw new errors_1.FeeNotLoaded(); const unsignedTransaction = await (0, buildTransaction_1.default)(account, transaction); const { chainId, to } = unsignedTransaction; const subAccount = (0, index_1.findSubAccountById)(account, transaction.subAccountId ?? ""); const isTokenTransaction = subAccount?.type === "TokenAccount"; await signerContext(deviceId, signer => { return signer.verifyTokenInfo(isTokenTransaction ? subAccount.token.contractAddress : to, chainId); }); const finalTransaction = { ...unsignedTransaction, to: isTokenTransaction ? subAccount.token.contractAddress : to, value: isTokenTransaction ? 0 : unsignedTransaction.value, }; await (0, sdk_1.determineFees)(finalTransaction); const rlpEncodedTransaction = await signerContext(deviceId, signer => { return signer.rlpEncodedTxForLedger(finalTransaction); }); o.next({ type: "device-signature-requested" }); const response = (await signerContext(deviceId, signer => { return signer.signTransaction(account.freshAddressPath, trimLeading0x(rlpEncodedTransaction.rlpEncode)); })); const { address } = await signerContext(deviceId, signer => { return signer.getAddress(account.freshAddressPath); }); const convertedResponse = { ...response, v: response.v.toString() }; if (cancelled) return; const signature = parseSigningResponse(convertedResponse, chainId); o.next({ type: "device-signature-granted" }); const encodedTransaction = await (0, wallet_base_1.encodeTransaction)(rlpEncodedTransaction, signature); const [_, recoveredAddress] = (0, wallet_base_1.recoverTransaction)(encodedTransaction.raw); if (recoveredAddress !== address) { throw new Error("celo: there was a signing error, the recovered address doesn't match the your ledger address, the operation was cancelled"); } const operation = (0, buildOptimisticOperation_1.buildOptimisticOperation)(account, transaction, transaction.fees ?? new bignumber_js_1.BigNumber(0)); o.next({ type: "signed", signedOperation: { operation, signature: encodedTransaction.raw, }, }); } main().then(() => o.complete(), e => o.error(e)); return () => { cancelled = true; }; }); exports.buildSignOperation = buildSignOperation; const trimLeading0x = (input) => (input.startsWith("0x") ? input.slice(2) : input); const parseSigningResponse = (response, chainId) => { // EIP155 const sigV = parseInt(response.v, 16); let eip155V = chainId * 2 + 35; eip155V = sigV; return { s: Buffer.from(response.s, "hex"), v: eip155V, r: Buffer.from(response.r, "hex"), }; }; exports.default = exports.buildSignOperation; //# sourceMappingURL=signOperation.js.map