diff --git a/modules/abstract-utxo/src/abstractUtxoCoin.ts b/modules/abstract-utxo/src/abstractUtxoCoin.ts index b5d04a47a7..6248c96e08 100644 --- a/modules/abstract-utxo/src/abstractUtxoCoin.ts +++ b/modules/abstract-utxo/src/abstractUtxoCoin.ts @@ -572,10 +572,10 @@ export abstract class AbstractUtxoCoin return (chainhead as any).height; } - checkRecipient(recipient: { address: string; amount: number | string }): void { + checkRecipient(recipient: { address?: string; amount: number | string }): void { assertValidTransactionRecipient(recipient); - if (!isScriptRecipient(recipient.address)) { - super.checkRecipient(recipient); + if (recipient.address && !isScriptRecipient(recipient.address)) { + super.checkRecipient({ address: recipient.address, amount: recipient.amount }); } } diff --git a/modules/abstract-utxo/test/unit/transaction/recipient.ts b/modules/abstract-utxo/test/unit/transaction/recipient.ts new file mode 100644 index 0000000000..1dbf838fba --- /dev/null +++ b/modules/abstract-utxo/test/unit/transaction/recipient.ts @@ -0,0 +1,39 @@ +import assert from 'assert'; + +import { getUtxoCoin } from '../util/utxoCoins'; + +describe('AbstractUtxoCoin.checkRecipient', function () { + const coin = getUtxoCoin('btc'); + + it('does not throw for OP_RETURN output with no address field', function () { + // Simulates { amount: '0', script: '6a0c...' } coming from buildParams.recipients + assert.doesNotThrow(() => { + coin.checkRecipient({ amount: '0' }); + }); + }); + + it('does not throw for script-prefixed address with zero amount', function () { + assert.doesNotThrow(() => { + coin.checkRecipient({ address: 'scriptPubKey:6a0c68656c6c6f20776f726c64', amount: '0' }); + }); + }); + + it('does not throw for a regular address', function () { + // A valid mainnet P2PKH address + assert.doesNotThrow(() => { + coin.checkRecipient({ address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf', amount: '1000' }); + }); + }); + + it('throws when OP_RETURN output (no address) has non-zero amount', function () { + assert.throws(() => { + coin.checkRecipient({ amount: '1000' }); + }, /Only zero amounts allowed for non-encodeable scriptPubkeys/); + }); + + it('throws when script-prefixed address has non-zero amount', function () { + assert.throws(() => { + coin.checkRecipient({ address: 'scriptPubKey:6a0c68656c6c6f20776f726c64', amount: '500' }); + }, /Only zero amounts allowed for non-encodeable scriptPubkeys/); + }); +});