diff --git a/src/psbt.js b/src/psbt.js index 3bb1b3f..d89752b 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -338,6 +338,55 @@ class Psbt extends bip174_1.Psbt { } return results.every(res => res === true); } + sign(keyPair) { + if (!keyPair || !keyPair.publicKey) + throw new Error('Need Signer to sign input'); + // TODO: Add a pubkey/pubkeyhash cache to each input + // as input information is added, then eventually + // optimize this method. + const results = []; + for (const [i] of this.inputs.entries()) { + try { + this.signInput(i, keyPair); + results.push(true); + } catch (err) { + results.push(false); + } + } + if (results.every(v => v === false)) { + throw new Error('No inputs were signed'); + } + return this; + } + signAsync(keyPair) { + return new Promise((resolve, reject) => { + if (!keyPair || !keyPair.publicKey) + return reject(new Error('Need Signer to sign input')); + // TODO: Add a pubkey/pubkeyhash cache to each input + // as input information is added, then eventually + // optimize this method. + const results = []; + const promises = []; + for (const [i] of this.inputs.entries()) { + promises.push( + this.signInputAsync(i, keyPair).then( + () => { + results.push(true); + }, + () => { + results.push(false); + }, + ), + ); + } + return Promise.all(promises).then(() => { + if (results.every(v => v === false)) { + return reject(new Error('No inputs were signed')); + } + resolve(); + }); + }); + } signInput(inputIndex, keyPair) { if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); diff --git a/test/integration/transactions-psbt.js b/test/integration/transactions-psbt.js index 9fb76f7..37348c1 100644 --- a/test/integration/transactions-psbt.js +++ b/test/integration/transactions-psbt.js @@ -110,8 +110,13 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { const signer2 = bitcoin.Psbt.fromBase64(psbtBaseText) // Alice signs each input with the respective private keys - signer1.signInput(0, alice1.keys[0]) - signer2.signInput(1, alice2.keys[0]) + // signInput and signInputAsync are better + // (They take the input index explicitly as the first arg) + signer1.sign(alice1.keys[0]) + signer2.sign(alice2.keys[0]) + + // If your signer object's sign method returns a promise, use the following + // await signer2.signAsync(alice2.keys[0]) // encode to send back to combiner (signer 1 and 2 are not near each other) const s1text = signer1.toBase64() diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 6ccef08..3461b56 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -405,6 +405,61 @@ export class Psbt extends PsbtBase { return results.every(res => res === true); } + sign(keyPair: Signer): this { + if (!keyPair || !keyPair.publicKey) + throw new Error('Need Signer to sign input'); + + // TODO: Add a pubkey/pubkeyhash cache to each input + // as input information is added, then eventually + // optimize this method. + const results: boolean[] = []; + for (const [i] of this.inputs.entries()) { + try { + this.signInput(i, keyPair); + results.push(true); + } catch (err) { + results.push(false); + } + } + if (results.every(v => v === false)) { + throw new Error('No inputs were signed'); + } + return this; + } + + signAsync(keyPair: SignerAsync): Promise { + return new Promise( + (resolve, reject): any => { + if (!keyPair || !keyPair.publicKey) + return reject(new Error('Need Signer to sign input')); + + // TODO: Add a pubkey/pubkeyhash cache to each input + // as input information is added, then eventually + // optimize this method. + const results: boolean[] = []; + const promises: Array> = []; + for (const [i] of this.inputs.entries()) { + promises.push( + this.signInputAsync(i, keyPair).then( + () => { + results.push(true); + }, + () => { + results.push(false); + }, + ), + ); + } + return Promise.all(promises).then(() => { + if (results.every(v => v === false)) { + return reject(new Error('No inputs were signed')); + } + resolve(); + }); + }, + ); + } + signInput(inputIndex: number, keyPair: Signer): this { if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); diff --git a/types/psbt.d.ts b/types/psbt.d.ts index 1f9ee7b..b2893b8 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -30,6 +30,8 @@ export declare class Psbt extends PsbtBase { }; finalizeInput(inputIndex: number): boolean; validateSignatures(inputIndex: number, pubkey?: Buffer): boolean; + sign(keyPair: Signer): this; + signAsync(keyPair: SignerAsync): Promise; signInput(inputIndex: number, keyPair: Signer): this; signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise; }