@@ -8,9 +8,13 @@ import { parseTransaction } from '../../../../src/transaction/fixedScript/parseT
88import { ParsedTransaction } from '../../../../src/transaction/types' ;
99import { UtxoWallet } from '../../../../src/wallet' ;
1010import { getUtxoCoin } from '../../util' ;
11- import { explainPsbt } from '../../../../src/transaction/fixedScript' ;
12- import type { TransactionExplanation } from '../../../../src/transaction/fixedScript/explainTransaction' ;
11+ import { explainLegacyTx , explainPsbt } from '../../../../src/transaction/fixedScript' ;
12+ import type {
13+ TransactionExplanation ,
14+ ChangeAddressInfo ,
15+ } from '../../../../src/transaction/fixedScript/explainTransaction' ;
1316import { getChainFromNetwork } from '../../../../src/names' ;
17+ import { TransactionPrebuild } from '../../../../src/abstractUtxoCoin' ;
1418
1519function getTxParamsFromExplanation ( explanation : TransactionExplanation ) : {
1620 recipients : ITransactionRecipient [ ] ;
@@ -30,15 +34,39 @@ function getTxParamsFromExplanation(explanation: TransactionExplanation): {
3034 } ;
3135}
3236
37+ function getChangeInfoFromPsbt ( psbt : utxolib . bitgo . UtxoPsbt ) : ChangeAddressInfo [ ] | undefined {
38+ try {
39+ return utxolib . bitgo . findInternalOutputIndices ( psbt ) . map ( ( i ) => {
40+ const output = psbt . data . outputs [ i ] ;
41+ const derivations = output . bip32Derivation ?? output . tapBip32Derivation ?? undefined ;
42+ if ( ! derivations || derivations . length !== 3 ) {
43+ throw new Error ( 'expected 3 derivation paths' ) ;
44+ }
45+ const path = derivations [ 0 ] . path ;
46+ const { chain, index } = utxolib . bitgo . getChainAndIndexFromPath ( path ) ;
47+ return {
48+ address : utxolib . address . fromOutputScript ( psbt . txOutputs [ i ] . script , psbt . network ) ,
49+ chain,
50+ index,
51+ } ;
52+ } ) ;
53+ } catch ( e ) {
54+ if ( e instanceof utxolib . bitgo . ErrorNoMultiSigInputFound ) {
55+ return undefined ;
56+ }
57+ throw e ;
58+ }
59+ }
60+
3361function describeParseTransactionWith (
3462 acidTest : utxolib . testutil . AcidTest ,
63+ label : string ,
3564 {
36- label = 'default' ,
3765 txParams,
3866 expectedExplicitExternalSpendAmount,
3967 expectedImplicitExternalSpendAmount,
68+ txFormat = 'psbt' ,
4069 } : {
41- label ?: string ;
4270 txParams :
4371 | {
4472 recipients : ITransactionRecipient [ ] ;
@@ -47,6 +75,7 @@ function describeParseTransactionWith(
4775 | 'inferFromExplanation' ;
4876 expectedExplicitExternalSpendAmount : bigint ;
4977 expectedImplicitExternalSpendAmount : bigint ;
78+ txFormat ?: 'psbt' | 'legacy' ;
5079 }
5180) {
5281 describe ( `${ acidTest . name } /${ label } ` , function ( ) {
@@ -61,9 +90,21 @@ function describeParseTransactionWith(
6190
6291 // Create PSBT and explanation
6392 const psbt = acidTest . createPsbt ( ) ;
64- const explanation = explainPsbt ( psbt , { pubs : acidTest . rootWalletKeys } , acidTest . network , {
65- strict : true ,
66- } ) ;
93+
94+ let explanation : TransactionExplanation ;
95+ if ( txFormat === 'psbt' ) {
96+ explanation = explainPsbt ( psbt , { pubs : acidTest . rootWalletKeys } , acidTest . network , {
97+ strict : true ,
98+ } ) ;
99+ } else if ( txFormat === 'legacy' ) {
100+ const tx = psbt . getUnsignedTx ( ) ;
101+ const pubs = acidTest . rootWalletKeys . triple . map ( ( k ) => k . neutered ( ) . toBase58 ( ) ) ;
102+ // Extract change info from PSBT to pass to explainLegacyTx
103+ const changeInfo = getChangeInfoFromPsbt ( psbt ) ;
104+ explanation = explainLegacyTx ( tx , { pubs, changeInfo } , acidTest . network ) ;
105+ } else {
106+ throw new Error ( `Invalid txFormat: ${ txFormat } ` ) ;
107+ }
67108
68109 // Determine txParams
69110 const resolvedTxParams =
@@ -92,12 +133,23 @@ function describeParseTransactionWith(
92133 // Stub explainTransaction to return the explanation without making network calls
93134 stubExplainTransaction = sinon . stub ( coin , 'explainTransaction' ) . resolves ( explanation ) ;
94135
136+ let txPrebuild : TransactionPrebuild < bigint > ;
137+ if ( txFormat === 'psbt' ) {
138+ txPrebuild = {
139+ txHex : psbt . toHex ( ) ,
140+ } ;
141+ } else if ( txFormat === 'legacy' ) {
142+ txPrebuild = {
143+ txHex : psbt . getUnsignedTx ( ) . toHex ( ) ,
144+ } ;
145+ } else {
146+ throw new Error ( `Invalid txFormat: ${ txFormat } ` ) ;
147+ }
148+
95149 refParsedTransaction = await parseTransaction ( coin , {
96150 wallet : mockWallet as unknown as UtxoWallet ,
97151 txParams : resolvedTxParams ,
98- txPrebuild : {
99- txHex : psbt . toHex ( ) ,
100- } ,
152+ txPrebuild,
101153 verification,
102154 } ) ;
103155 } ) ;
@@ -143,19 +195,26 @@ function describeParseTransactionWith(
143195 } ) ;
144196}
145197
146- describe ( 'parsePsbt ' , function ( ) {
198+ describe ( 'parseTransaction ' , function ( ) {
147199 utxolib . testutil . AcidTest . suite ( ) . forEach ( ( test ) => {
148- // Default case: infer recipients from explanation
149- describeParseTransactionWith ( test , {
200+ // Default case: psbt format, infer recipients from explanation
201+ describeParseTransactionWith ( test , 'default' , {
150202 txParams : 'inferFromExplanation' ,
151203 expectedExplicitExternalSpendAmount : 2700n ,
152204 expectedImplicitExternalSpendAmount : 0n ,
153205 } ) ;
154206
155207 if ( test . network === utxolib . networks . bitcoin ) {
156208 // extended test suite for bitcoin
157- describeParseTransactionWith ( test , {
158- label : 'empty recipients' ,
209+
210+ describeParseTransactionWith ( test , 'legacy' , {
211+ txFormat : 'legacy' ,
212+ txParams : 'inferFromExplanation' ,
213+ expectedExplicitExternalSpendAmount : 2700n ,
214+ expectedImplicitExternalSpendAmount : 0n ,
215+ } ) ;
216+
217+ describeParseTransactionWith ( test , 'empty recipients' , {
159218 txParams : {
160219 recipients : [ ] ,
161220 changeAddress : undefined ,
0 commit comments