UNPKG

@ledgerhq/live-common

Version:
104 lines 5.52 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.genericSignOperation = void 0; const rxjs_1 = require("rxjs"); const alpaca_1 = require("./alpaca"); const bridge_1 = require("./bridge"); const utils_1 = require("./utils"); const errors_1 = require("@ledgerhq/errors"); const logs_1 = require("@ledgerhq/logs"); const bignumber_js_1 = __importDefault(require("bignumber.js")); /** * Enriches transaction intent with memo and asset information */ function enrichTransactionIntent(transactionIntent, transaction, publicKey) { // Set sender public key transactionIntent.senderPublicKey = publicKey; // Apply memo information transactionIntent = (0, utils_1.applyMemoToIntent)(transactionIntent, transaction); return transactionIntent; } /** * Sign Transaction with Ledger hardware */ const genericSignOperation = (network, kind) => (signerContext) => ({ account, transaction, deviceId, }) => new rxjs_1.Observable(o => { async function main() { const alpacaApi = (0, alpaca_1.getAlpacaApi)(account.currency.id, kind); const bridgeApi = (0, bridge_1.getBridgeApi)(account.currency, network); if (!transaction.fees) throw new errors_1.FeeNotLoaded(); const customFees = (0, utils_1.bigNumberToBigIntDeep)({ value: transaction.fees ?? new bignumber_js_1.default(0), parameters: { gasLimit: transaction.customGasLimit ?? transaction.gasLimit, gasPrice: transaction.gasPrice, maxFeePerGas: transaction.maxFeePerGas, maxPriorityFeePerGas: transaction.maxPriorityFeePerGas, additionalFees: transaction.additionalFees, }, }); if (transaction.useAllAmount) { const draftTransaction = { mode: transaction.mode, recipient: transaction.recipient, amount: transaction.amount ?? 0, useAllAmount: !!transaction.useAllAmount, assetReference: transaction?.assetReference || "", assetOwner: transaction?.assetOwner || "", subAccountId: transaction.subAccountId || "", family: transaction.family, feesStrategy: transaction.feesStrategy, data: transaction.data, type: transaction.type, }; // TODO Remove the call to `validateIntent` https://ledgerhq.atlassian.net/browse/LIVE-22227 const { amount } = await alpacaApi.validateIntent((0, utils_1.transactionToIntent)(account, draftTransaction, alpacaApi.computeIntentType), (0, utils_1.extractBalances)(account, bridgeApi.getAssetFromToken), customFees); transaction.amount = new bignumber_js_1.default(amount.toString()); } const signedInfo = await signerContext(deviceId, async (signer) => { const derivationPath = account.freshAddressPath; const { publicKey } = (await signer.getAddress(derivationPath)); let transactionIntent = (0, utils_1.transactionToIntent)(account, { ...transaction }, alpacaApi.computeIntentType); transactionIntent.senderPublicKey = publicKey; // Enrich with memo and asset information transactionIntent = enrichTransactionIntent(transactionIntent, transaction, publicKey); if (typeof transactionIntent.sequence !== "bigint" || transactionIntent.sequence < 0n) { // TODO: should compute it and pass it down to craftTransaction (duplicate call right now) const sequenceNumber = await alpacaApi.getNextSequence(transactionIntent.sender); transactionIntent.sequence = sequenceNumber; } /* Craft unsigned blob via Alpaca */ const { transaction: unsigned } = await alpacaApi.craftTransaction(transactionIntent, customFees); /* Notify UI that the device is now showing the tx */ o.next({ type: "device-signature-requested" }); /* Sign on Ledger device */ const txnSig = await signer.signTransaction(derivationPath, unsigned, transaction.recipientDomain); return { unsigned, txnSig, publicKey, sequence: transactionIntent.sequence }; }); /* If the user cancelled inside signerContext */ if (!signedInfo) return; o.next({ type: "device-signature-granted" }); /* Combine payload + signature for broadcast */ const combined = await alpacaApi.combine(signedInfo.unsigned, signedInfo.txnSig, signedInfo.publicKey); const operation = (0, utils_1.buildOptimisticOperation)(account, transaction, signedInfo.sequence); if (!operation.id) { (0, logs_1.log)("Generic alpaca", "buildOptimisticOperation", operation); } // NOTE: we set the transactionSequenceNumber before on the operation // now that we create it in craftTransaction, we might need to return it back from craftTransaction also o.next({ type: "signed", signedOperation: { operation, signature: combined, }, }); } main().then(() => o.complete(), e => o.error(e)); }); exports.genericSignOperation = genericSignOperation; //# sourceMappingURL=signOperation.js.map