Open gregdhill opened 5 days ago
Can't reproduce, please provide specific input that fails.
witnessUtxo
, then script of input will be user wallet script -> there is nothing to checknonWitnessUtxo
:
checkScript(prevOut && prevOut.script, res.redeemScript, res.witnessScript);
but it happens only on output (which is input for out tx) prevOut = res.nonWitnessUtxo.outputs[res.index]
1.3.2
, which you use according to your package.json
Here is an example of this specific case working (attempt at reproduction):
should.only('GH-114: unwrapped multisig', () => {
const privKey1 = hex.decode('0101010101010101010101010101010101010101010101010101010101010101');
const P1 = secp256k1.getPublicKey(privKey1, true);
const wpkh = btc.p2wpkh(P1);
// multisig utxo
const compressed = hex.decode(
'030000000000000000000000000000000000000000000000000000000000000001'
);
const compressed2 = hex.decode(
'030000000000000000000000000000000000000000000000000000000000000002'
);
const compressed3 = hex.decode(
'030000000000000000000000000000000000000000000000000000000000000003'
);
const ms = btc.p2ms(2, [compressed, compressed2, compressed3]);
const oldBrokenTx = new btc.Transaction({
// NOTE: here we need disableScriptCheck, because we construct raw tx
// in mentioned use case this tx will be signed and serialized by somebody else.
disableScriptCheck: true,
allowLegacyWitnessUtxo: true,
});
oldBrokenTx.addInput({
txid: hex.decode('c061c23190ed3370ad5206769651eaf6fac6d87d85b5db34e30a74e0c4a6da3e'),
index: 0,
witnessUtxo: { script: ms.script, amount: 100_000n },
});
oldBrokenTx.addOutputAddress(wpkh.address, 90_000n);
// Add broken signatures
oldBrokenTx.updateInput(
0,
{
partialSig: [
[compressed, new Uint8Array(33)],
[compressed2, new Uint8Array(33)],
],
},
true
);
oldBrokenTx.finalize();
const brokenCheck = btc.Transaction.fromRaw(hex.decode(oldBrokenTx.hex));
// Now, lets try to spend output of that transaction
// we spend wpkh output from this tx, but input inside this tx is broken
const INPUT = {
...wpkh,
txid: oldBrokenTx.id,
index: 0,
nonWitnessUtxo: oldBrokenTx.hex,
};
const spendTx = new btc.Transaction();
spendTx.addInput(INPUT);
spendTx.addOutputAddress(wpkh.address, 80_000n);
spendTx.sign(privKey1);
spendTx.finalize();
deepStrictEqual(spendTx.id, '63f33dac6b7ed734c1720ed32865601d85fcbdec370df08f8562d40ec9e79c6b');
deepStrictEqual(
spendTx.hex,
'02000000000101ec495ac2d31a09a8511203caec7cade7bdd2f1c9ff9acf106042e1d0e2bcfc8d0000000000ffffffff01803801000000000016001479b000887626b294a914501a4cd226b58b23598302483045022100ca2b3abb71e8b207dd9630cb9c7d5d5b2824183e9a2b79b1a4eff7cf7787f5ab0220464b4b3f688497a7fdb45d2403becd86d4a05d2c211a8a21724b98bdc7742b510121031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f00000000'
);
const transaction = btc.selectUTXO([INPUT], [], 'default', {
changeAddress: wpkh.address, // Refund surplus to the payment address
feePerByte: BigInt(Math.ceil(1)), // round up to the nearest integer
bip69: true, // Sort inputs and outputs according to BIP69
createTx: true, // Create the transaction
dust: BigInt(546), // TODO: update scure-btc-signer
});
//console.log(transaction);
// no crash here!
});
We're hitting this error when spending from a UTXO whose input(s) come from a multisig. It looks like we can get around this by setting
disableScriptCheck
to true but I'm not sure why this is flagged as an error since we are not spending from a multisig. Our code is here for reference but to reproduce it should be enough to provide an input toselectUTXO
with an array ofpossibleInputs
where at least one input has a UTXO which spends from a multisig to the user's wallet.