@@ -15,23 +15,39 @@ 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' ;
1918
20- function getTxParamsFromExplanation ( explanation : TransactionExplanation ) : {
19+ function getTxParamsFromExplanation (
20+ explanation : TransactionExplanation ,
21+ { externalCustomChangeAddress } : { externalCustomChangeAddress : boolean }
22+ ) : {
2123 recipients : ITransactionRecipient [ ] ;
2224 changeAddress ?: string ;
2325} {
2426 // The external outputs are the ones that are in outputs but not in changeOutputs
2527 const changeAddresses = new Set ( explanation . changeOutputs . map ( ( o ) => o . address ) ) ;
26- const externalOutputs = explanation . outputs . filter ( ( o ) => o . address && ! changeAddresses . has ( o . address ) ) ;
28+ let externalOutputs = explanation . outputs . filter ( ( o ) => o . address && ! changeAddresses . has ( o . address ) ) ;
29+
30+ let changeAddress : string | undefined ;
31+ if ( externalCustomChangeAddress ) {
32+ // convert an external output to a change output
33+ //
34+ // in combination with allowExternalChangeAddress, this allows an external
35+ // output on the transaction without a size constraint
36+ const externalOutput = externalOutputs [ 0 ] ;
37+ if ( ! externalOutput ) {
38+ throw new Error ( 'no external output found' ) ;
39+ }
40+ changeAddress = externalOutput . address ;
41+ externalOutputs = externalOutputs . slice ( 1 ) ;
42+ }
2743
2844 return {
2945 recipients : externalOutputs . map ( ( output ) => ( {
3046 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3147 address : output . address ! ,
3248 amount : output . amount ,
3349 } ) ) ,
34- changeAddress : undefined ,
50+ changeAddress,
3551 } ;
3652}
3753
@@ -64,19 +80,20 @@ function describeParseTransactionWith(
6480 label : string ,
6581 {
6682 txParams,
83+ externalCustomChangeAddress = false ,
6784 expectedExplicitExternalSpendAmount,
6885 expectedImplicitExternalSpendAmount,
6986 txFormat = 'psbt' ,
7087 } : {
7188 txParams :
7289 | {
7390 recipients : ITransactionRecipient [ ] ;
74- changeAddress ?: string ;
7591 }
7692 | {
7793 rbfTxIds : string [ ] ;
7894 }
7995 | 'inferFromExplanation' ;
96+ externalCustomChangeAddress ?: boolean ;
8097 expectedExplicitExternalSpendAmount : bigint ;
8198 expectedImplicitExternalSpendAmount : bigint ;
8299 txFormat ?: 'psbt' | 'legacy' ;
@@ -114,7 +131,7 @@ function describeParseTransactionWith(
114131 // Determine txParams
115132 let resolvedTxParams ;
116133 if ( txParams === 'inferFromExplanation' || txParams === undefined ) {
117- resolvedTxParams = getTxParamsFromExplanation ( explanation ) ;
134+ resolvedTxParams = getTxParamsFromExplanation ( explanation , { externalCustomChangeAddress } ) ;
118135 } else if ( 'rbfTxIds' in txParams ) {
119136 // Replace placeholder txHash with actual computed txHash
120137 resolvedTxParams = {
@@ -124,6 +141,10 @@ function describeParseTransactionWith(
124141 resolvedTxParams = txParams ;
125142 }
126143
144+ if ( externalCustomChangeAddress ) {
145+ resolvedTxParams . allowExternalChangeAddress = true ;
146+ }
147+
127148 // Create mock wallet
128149 mockWallet = sinon . createStubInstance ( Wallet ) ;
129150 mockWallet . id . returns ( 'test-wallet-id' ) ;
@@ -132,7 +153,7 @@ function describeParseTransactionWith(
132153
133154 // Mock getTransaction for RBF case
134155 if ( 'rbfTxIds' in resolvedTxParams ) {
135- const rbfTxParams = getTxParamsFromExplanation ( explanation ) ;
156+ const rbfTxParams = getTxParamsFromExplanation ( explanation , { externalCustomChangeAddress : false } ) ;
136157 mockWallet . getTransaction . resolves ( {
137158 outputs : rbfTxParams . recipients . map ( ( r ) => ( {
138159 valueString : typeof r . amount === 'string' ? r . amount : r . amount . toString ( ) ,
@@ -243,7 +264,6 @@ describe('parseTransaction', function () {
243264 describeParseTransactionWith ( test , 'empty recipients' , {
244265 txParams : {
245266 recipients : [ ] ,
246- changeAddress : undefined ,
247267 } ,
248268 expectedExplicitExternalSpendAmount : 0n ,
249269 expectedImplicitExternalSpendAmount : 1800n ,
@@ -256,5 +276,12 @@ describe('parseTransaction', function () {
256276 expectedExplicitExternalSpendAmount : 1800n ,
257277 expectedImplicitExternalSpendAmount : 0n ,
258278 } ) ;
279+
280+ describeParseTransactionWith ( test , 'allowExternalChangeAddress' , {
281+ txParams : 'inferFromExplanation' ,
282+ externalCustomChangeAddress : true ,
283+ expectedExplicitExternalSpendAmount : 1800n ,
284+ expectedImplicitExternalSpendAmount : 0n ,
285+ } ) ;
259286 } ) ;
260287} ) ;
0 commit comments