@@ -15,6 +15,7 @@ import type {
1515} from '../../../../src/transaction/fixedScript/explainTransaction' ;
1616import { getChainFromNetwork } from '../../../../src/names' ;
1717import { TransactionPrebuild } from '../../../../src/abstractUtxoCoin' ;
18+ import { isScriptRecipient } from '../../../../src/transaction/recipient' ;
1819
1920function getTxParamsFromExplanation ( explanation : TransactionExplanation ) : {
2021 recipients : ITransactionRecipient [ ] ;
@@ -72,6 +73,9 @@ function describeParseTransactionWith(
7273 recipients : ITransactionRecipient [ ] ;
7374 changeAddress ?: string ;
7475 }
76+ | {
77+ rbfTxIds : string [ ] ;
78+ }
7579 | 'inferFromExplanation' ;
7680 expectedExplicitExternalSpendAmount : bigint ;
7781 expectedImplicitExternalSpendAmount : bigint ;
@@ -90,14 +94,15 @@ function describeParseTransactionWith(
9094
9195 // Create PSBT and explanation
9296 const psbt = acidTest . createPsbt ( ) ;
97+ const tx = psbt . getUnsignedTx ( ) ;
98+ const txHash = tx . getId ( ) ;
9399
94100 let explanation : TransactionExplanation ;
95101 if ( txFormat === 'psbt' ) {
96102 explanation = explainPsbt ( psbt , { pubs : acidTest . rootWalletKeys } , acidTest . network , {
97103 strict : true ,
98104 } ) ;
99105 } else if ( txFormat === 'legacy' ) {
100- const tx = psbt . getUnsignedTx ( ) ;
101106 const pubs = acidTest . rootWalletKeys . triple . map ( ( k ) => k . neutered ( ) . toBase58 ( ) ) ;
102107 // Extract change info from PSBT to pass to explainLegacyTx
103108 const changeInfo = getChangeInfoFromPsbt ( psbt ) ;
@@ -107,17 +112,36 @@ function describeParseTransactionWith(
107112 }
108113
109114 // Determine txParams
110- const resolvedTxParams =
111- txParams === 'inferFromExplanation' || txParams === undefined
112- ? getTxParamsFromExplanation ( explanation )
113- : txParams ;
115+ let resolvedTxParams ;
116+ if ( txParams === 'inferFromExplanation' || txParams === undefined ) {
117+ resolvedTxParams = getTxParamsFromExplanation ( explanation ) ;
118+ } else if ( 'rbfTxIds' in txParams ) {
119+ // Replace placeholder txHash with actual computed txHash
120+ resolvedTxParams = {
121+ rbfTxIds : txParams . rbfTxIds . map ( ( hash ) => ( hash === 'PLACEHOLDER' ? txHash : hash ) ) ,
122+ } ;
123+ } else {
124+ resolvedTxParams = txParams ;
125+ }
114126
115127 // Create mock wallet
116128 mockWallet = sinon . createStubInstance ( Wallet ) ;
117129 mockWallet . id . returns ( 'test-wallet-id' ) ;
118130 mockWallet . coin . returns ( coin . getChain ( ) ) ;
119131 mockWallet . coinSpecific . returns ( undefined ) ;
120132
133+ // Mock getTransaction for RBF case
134+ if ( 'rbfTxIds' in resolvedTxParams ) {
135+ const rbfTxParams = getTxParamsFromExplanation ( explanation ) ;
136+ mockWallet . getTransaction . resolves ( {
137+ outputs : rbfTxParams . recipients . map ( ( r ) => ( {
138+ valueString : typeof r . amount === 'string' ? r . amount : r . amount . toString ( ) ,
139+ address : r . address ,
140+ // wallet field is undefined for external outputs (not self-sends)
141+ } ) ) ,
142+ } ) ;
143+ }
144+
121145 // Mock verification options with keychains to disable networking
122146 // Use the same keychains that were used to create the PSBT
123147 const pubs = acidTest . rootWalletKeys . triple . map ( ( k ) => k . neutered ( ) . toBase58 ( ) ) ;
@@ -224,5 +248,13 @@ describe('parseTransaction', function () {
224248 expectedExplicitExternalSpendAmount : 0n ,
225249 expectedImplicitExternalSpendAmount : 1800n ,
226250 } ) ;
251+
252+ describeParseTransactionWith ( test , 'rbf' , {
253+ txParams : {
254+ rbfTxIds : [ 'PLACEHOLDER' ] ,
255+ } ,
256+ expectedExplicitExternalSpendAmount : 1800n ,
257+ expectedImplicitExternalSpendAmount : 0n ,
258+ } ) ;
227259 } ) ;
228260} ) ;
0 commit comments