@bsv/wallet-toolbox-client
Version:
Client only Wallet Storage
106 lines • 5.43 kB
JavaScript
;
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