UNPKG

@bsv/wallet-toolbox-client

Version:
106 lines 5.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.completeSignedTransaction = completeSignedTransaction; exports.verifyUnlockScripts = verifyUnlockScripts; const sdk_1 = require("@bsv/sdk"); const WERR_errors_1 = require("../../sdk/WERR_errors"); const utilityHelpers_1 = require("../../utility/utilityHelpers"); const ScriptTemplateBRC29_1 = require("../../utility/ScriptTemplateBRC29"); const WalletError_1 = require("../../sdk/WalletError"); async function completeSignedTransaction(prior, spends, wallet) { ///////////////////// // Insert the user provided unlocking scripts from "spends" arg ///////////////////// for (const [key, spend] of Object.entries(spends)) { const vin = Number(key); const createInput = prior.args.inputs[vin]; const input = prior.tx.inputs[vin]; if (!createInput || !input || createInput.unlockingScript || !Number.isInteger(createInput.unlockingScriptLength)) throw new WERR_errors_1.WERR_INVALID_PARAMETER('args', `spend does not correspond to prior input with valid unlockingScriptLength.`); if (spend.unlockingScript.length / 2 > createInput.unlockingScriptLength) throw new WERR_errors_1.WERR_INVALID_PARAMETER('args', `spend unlockingScript length ${spend.unlockingScript.length} exceeds expected length ${createInput.unlockingScriptLength}`); input.unlockingScript = (0, utilityHelpers_1.asBsvSdkScript)(spend.unlockingScript); if (spend.sequenceNumber !== undefined) input.sequence = spend.sequenceNumber; } const results = { sdk: {} }; ///////////////////// // Insert SABPPP unlock templates for wallet signed inputs ///////////////////// for (const pdi of prior.pdi) { const sabppp = new ScriptTemplateBRC29_1.ScriptTemplateBRC29({ derivationPrefix: pdi.derivationPrefix, derivationSuffix: pdi.derivationSuffix, keyDeriver: wallet.keyDeriver }); const keys = wallet.getClientChangeKeyPair(); const lockerPrivKey = keys.privateKey; const unlockerPubKey = pdi.unlockerPubKey || keys.publicKey; const sourceSatoshis = pdi.sourceSatoshis; const lockingScript = (0, utilityHelpers_1.asBsvSdkScript)(pdi.lockingScript); const unlockTemplate = sabppp.unlock(lockerPrivKey, unlockerPubKey, sourceSatoshis, lockingScript); const input = prior.tx.inputs[pdi.vin]; input.unlockingScriptTemplate = unlockTemplate; } ///////////////////// // Sign wallet signed inputs making transaction fully valid. ///////////////////// await prior.tx.sign(); return prior.tx; } /** * @param txid The TXID of a transaction in the beef for which all unlocking scripts must be valid. * @param beef Must contain transactions for txid and all its inputs. * @throws WERR_INVALID_PARAMETER if any unlocking script is invalid, if sourceTXID is invalid, if beef doesn't contain required transactions. */ function verifyUnlockScripts(txid, beef) { var _a, _b, _c, _d; const tx = (_a = beef.findTxid(txid)) === null || _a === void 0 ? void 0 : _a.tx; if (!tx) throw new WERR_errors_1.WERR_INVALID_PARAMETER(`txid`, `contained in beef, txid ${txid}`); for (let i = 0; i < tx.inputs.length; i++) { const input = tx.inputs[i]; if (!input.sourceTXID) throw new WERR_errors_1.WERR_INVALID_PARAMETER(`inputs[${i}].sourceTXID`, `valid`); if (!input.unlockingScript) throw new WERR_errors_1.WERR_INVALID_PARAMETER(`inputs[${i}].unlockingScript`, `valid`); input.sourceTransaction = (_b = beef.findTxid(input.sourceTXID)) === null || _b === void 0 ? void 0 : _b.tx; if (!input.sourceTransaction) { // The beef doesn't contain all the source transactions only if advanced features // such as knownTxids are used. // Skip unlock script checks. return; // throw new WERR_INVALID_PARAMETER(`inputs[${i}].sourceTXID`, `contained in beef`) } } for (let i = 0; i < tx.inputs.length; i++) { const input = tx.inputs[i]; const sourceOutput = input.sourceTransaction.outputs[input.sourceOutputIndex]; const otherInputs = tx.inputs.filter((_, idx) => idx !== i); const spend = new sdk_1.Spend({ sourceTXID: input.sourceTXID, sourceOutputIndex: input.sourceOutputIndex, lockingScript: sourceOutput.lockingScript, sourceSatoshis: (_c = sourceOutput.satoshis) !== null && _c !== void 0 ? _c : 0, transactionVersion: tx.version, otherInputs, unlockingScript: input.unlockingScript, inputSequence: (_d = input.sequence) !== null && _d !== void 0 ? _d : 0, inputIndex: i, outputs: tx.outputs, lockTime: tx.lockTime }); try { const spendValid = spend.validate(); if (!spendValid) throw new WERR_errors_1.WERR_INVALID_PARAMETER(`inputs[${i}].unlockScript`, `valid`); } catch (eu) { const e = WalletError_1.WalletError.fromUnknown(eu); throw new WERR_errors_1.WERR_INVALID_PARAMETER(`inputs[${i}].unlockScript`, `valid. ${e.message}`); } } } //# sourceMappingURL=completeSignedTransaction.js.map