diff --git a/packages/cashscript/src/TransactionBuilder.ts b/packages/cashscript/src/TransactionBuilder.ts index 497287c5..9a92b5f3 100644 --- a/packages/cashscript/src/TransactionBuilder.ts +++ b/packages/cashscript/src/TransactionBuilder.ts @@ -17,6 +17,7 @@ import { isUnlockableUtxo, isStandardUnlockableUtxo, StandardUnlockableUtxo, + isP2PKHUnlocker, } from './interfaces.js'; import { NetworkProvider } from './network/index.js'; import { @@ -161,6 +162,11 @@ export class TransactionBuilder { } debug(): DebugResults { + // do not debug a pure P2PKH-spend transaction + if (this.inputs.every((input) => isP2PKHUnlocker(input.unlocker))) { + return {}; + } + if (this.inputs.some((input) => !isStandardUnlockableUtxo(input))) { throw new Error('Cannot debug a transaction with custom unlocker'); } diff --git a/packages/cashscript/test/TransactionBuilder.test.ts b/packages/cashscript/test/TransactionBuilder.test.ts index fc8ee52c..8051d053 100644 --- a/packages/cashscript/test/TransactionBuilder.test.ts +++ b/packages/cashscript/test/TransactionBuilder.test.ts @@ -9,6 +9,8 @@ import { carolAddress, carolPriv, bobTokenAddress, + aliceAddress, + alicePriv, } from './fixture/vars.js'; import { Network } from '../src/interfaces.js'; import { utxoComparator, calculateDust, randomUtxo, randomToken, isNonTokenUtxo, isFungibleTokenUtxo } from '../src/utils.js'; @@ -263,4 +265,19 @@ describe('Transaction Builder', () => { .build(); }).toThrow('Input is undefined'); }); + + it('should not fail when spending from only P2PKH inputs', async () => { + const aliceUtxos = (await provider.getUtxos(aliceAddress)).filter(isNonTokenUtxo); + const sigTemplate = new SignatureTemplate(alicePriv); + + expect(aliceUtxos.length).toBeGreaterThan(2); + + const change = aliceUtxos[0].satoshis + aliceUtxos[1].satoshis - 1000n; + + await expect(new TransactionBuilder({ provider }) + .addInput(aliceUtxos[0], sigTemplate.unlockP2PKH()) + .addInput(aliceUtxos[1], sigTemplate.unlockP2PKH()) + .addOutput({ to: aliceAddress, amount: change }) + .send()).resolves.not.toThrow(); + }); });