|
1 | 1 | 'use strict';
|
2 | 2 | Object.defineProperty(exports, '__esModule', { value: true });
|
3 |
| -exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootInputFields = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0; |
| 3 | +exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.getNewTaprootScriptAndAddress = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0; |
4 | 4 | const types_1 = require('../types');
|
5 | 5 | const psbtutils_1 = require('./psbtutils');
|
6 | 6 | const taprootutils_1 = require('../payments/taprootutils');
|
| 7 | +const payments_1 = require('../payments'); |
7 | 8 | const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
|
8 | 9 | exports.toXOnly = toXOnly;
|
9 | 10 | /**
|
@@ -52,11 +53,54 @@ function isTaprootInput(input) {
|
52 | 53 | );
|
53 | 54 | }
|
54 | 55 | exports.isTaprootInput = isTaprootInput;
|
| 56 | +function isTaprootOutput(output, script) { |
| 57 | + return ( |
| 58 | + output && |
| 59 | + !!( |
| 60 | + output.tapInternalKey || |
| 61 | + output.tapTree || |
| 62 | + (output.tapBip32Derivation && output.tapBip32Derivation.length) || |
| 63 | + (script && (0, psbtutils_1.isP2TR)(script)) |
| 64 | + ) |
| 65 | + ); |
| 66 | +} |
| 67 | +exports.isTaprootOutput = isTaprootOutput; |
55 | 68 | function checkTaprootInputFields(inputData, newInputData, action) {
|
56 |
| - checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action); |
| 69 | + checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action); |
57 | 70 | checkIfTapLeafInTree(inputData, newInputData, action);
|
58 | 71 | }
|
59 | 72 | exports.checkTaprootInputFields = checkTaprootInputFields;
|
| 73 | +function checkTaprootOutputFields(outputData, newOutputData, action) { |
| 74 | + checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action); |
| 75 | +} |
| 76 | +exports.checkTaprootOutputFields = checkTaprootOutputFields; |
| 77 | +function getNewTaprootScriptAndAddress(outputData, newOutputData, network) { |
| 78 | + if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return; |
| 79 | + const tapInternalKey = |
| 80 | + newOutputData.tapInternalKey || outputData.tapInternalKey; |
| 81 | + const tapTree = newOutputData.tapTree || outputData.tapTree; |
| 82 | + if (tapInternalKey) { |
| 83 | + const { script, address } = getTaprootScriptAndAddress( |
| 84 | + tapInternalKey, |
| 85 | + tapTree, |
| 86 | + network, |
| 87 | + ); |
| 88 | + const { script: newScript } = newOutputData; |
| 89 | + if (newScript && !newScript.equals(script)) |
| 90 | + throw new Error('Error adding output. Script or address missmatch.'); |
| 91 | + return { script, address }; |
| 92 | + } |
| 93 | +} |
| 94 | +exports.getNewTaprootScriptAndAddress = getNewTaprootScriptAndAddress; |
| 95 | +function getTaprootScriptAndAddress(tapInternalKey, tapTree, network) { |
| 96 | + const scriptTree = tapTree && tapTreeFromList(tapTree.leaves); |
| 97 | + const { output, address } = (0, payments_1.p2tr)({ |
| 98 | + internalPubkey: tapInternalKey, |
| 99 | + scriptTree, |
| 100 | + network, |
| 101 | + }); |
| 102 | + return { script: output, address: address }; |
| 103 | +} |
60 | 104 | function tweakInternalPubKey(inputIndex, input) {
|
61 | 105 | const tapInternalKey = input.tapInternalKey;
|
62 | 106 | const outputKey =
|
@@ -144,14 +188,36 @@ function instertLeafInTree(leaf, tree, depth = 0) {
|
144 | 188 | const rightSide = instertLeafInTree(leaf, tree && tree[1], depth + 1);
|
145 | 189 | if (rightSide) return [tree && tree[0], rightSide];
|
146 | 190 | }
|
147 |
| -function checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action) { |
| 191 | +function checkMixedTaprootAndNonTaprootInputFields( |
| 192 | + inputData, |
| 193 | + newInputData, |
| 194 | + action, |
| 195 | +) { |
148 | 196 | const isBadTaprootUpdate =
|
149 |
| - isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData); |
| 197 | + isTaprootInput(inputData) && hasNonTaprootFields(newInputData); |
150 | 198 | const isBadNonTaprootUpdate =
|
151 |
| - hasNonTaprootInputFields(inputData) && isTaprootInput(newInputData); |
| 199 | + hasNonTaprootFields(inputData) && isTaprootInput(newInputData); |
152 | 200 | const hasMixedFields =
|
153 | 201 | inputData === newInputData &&
|
154 |
| - (isTaprootInput(newInputData) && hasNonTaprootInputFields(newInputData)); |
| 202 | + (isTaprootInput(newInputData) && hasNonTaprootFields(newInputData)); // todo: bad? use !=== |
| 203 | + if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields) |
| 204 | + throw new Error( |
| 205 | + `Invalid arguments for Psbt.${action}. ` + |
| 206 | + `Cannot use both taproot and non-taproot fields.`, |
| 207 | + ); |
| 208 | +} |
| 209 | +function checkMixedTaprootAndNonTaprootOutputFields( |
| 210 | + inputData, |
| 211 | + newInputData, |
| 212 | + action, |
| 213 | +) { |
| 214 | + const isBadTaprootUpdate = |
| 215 | + isTaprootOutput(inputData) && hasNonTaprootFields(newInputData); |
| 216 | + const isBadNonTaprootUpdate = |
| 217 | + hasNonTaprootFields(inputData) && isTaprootOutput(newInputData); |
| 218 | + const hasMixedFields = |
| 219 | + inputData === newInputData && |
| 220 | + (isTaprootOutput(newInputData) && hasNonTaprootFields(newInputData)); |
155 | 221 | if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
|
156 | 222 | throw new Error(
|
157 | 223 | `Invalid arguments for Psbt.${action}. ` +
|
@@ -244,13 +310,13 @@ function canFinalizeLeaf(leaf, tapScriptSig, hash) {
|
244 | 310 | tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined
|
245 | 311 | );
|
246 | 312 | }
|
247 |
| -function hasNonTaprootInputFields(input) { |
| 313 | +function hasNonTaprootFields(io) { |
248 | 314 | return (
|
249 |
| - input && |
| 315 | + io && |
250 | 316 | !!(
|
251 |
| - input.redeemScript || |
252 |
| - input.witnessScript || |
253 |
| - (input.bip32Derivation && input.bip32Derivation.length) |
| 317 | + io.redeemScript || |
| 318 | + io.witnessScript || |
| 319 | + (io.bip32Derivation && io.bip32Derivation.length) |
254 | 320 | )
|
255 | 321 | );
|
256 | 322 | }
|
0 commit comments