@@ -114,20 +114,57 @@ export class ExportInPTxBuilder extends AtomicTransactionBuilder {
114114 const sortedAddresses = [ ...this . transaction . _fromAddresses ] . sort ( ( a , b ) => Buffer . compare ( a , b ) ) ;
115115
116116 // When credentials were extracted, use them directly to preserve existing signatures
117- // Otherwise, create empty credentials with embedded addresses for slot identification
117+ // Otherwise, create empty credentials with dynamic ordering based on addressesIndex
118+ // Match avaxp behavior: order depends on UTXO address positions
118119 const txCredentials =
119120 credentials . length > 0
120121 ? credentials
121- : exportTx . baseTx . inputs . map ( ( input ) => {
122+ : exportTx . baseTx . inputs . map ( ( input , inputIdx ) => {
122123 const transferInput = input . input as TransferInput ;
123124 const inputThreshold = transferInput . sigIndicies ( ) . length || this . transaction . _threshold ;
124- // Create empty signatures with embedded addresses for slot identification
125- const sigSlots : ReturnType < typeof utils . createEmptySigWithAddress > [ ] = [ ] ;
126- for ( let i = 0 ; i < inputThreshold ; i ++ ) {
127- const addrHex = Buffer . from ( sortedAddresses [ i ] ) . toString ( 'hex' ) ;
128- sigSlots . push ( utils . createEmptySigWithAddress ( addrHex ) ) ;
125+
126+ // Get UTXO for this input to determine addressesIndex
127+ const utxo = this . transaction . _utxos [ inputIdx ] ;
128+
129+ // either user (0) or recovery (2)
130+ const firstIndex = this . recoverSigner ? 2 : 0 ;
131+ const bitgoIndex = 1 ;
132+
133+ // If UTXO has addresses, compute dynamic ordering
134+ if ( utxo && utxo . addresses && utxo . addresses . length > 0 ) {
135+ const utxoAddresses = utxo . addresses . map ( ( a ) => utils . parseAddress ( a ) ) ;
136+ const addressesIndex = this . transaction . _fromAddresses . map ( ( a ) =>
137+ utxoAddresses . findIndex ( ( u ) => Buffer . compare ( Buffer . from ( u ) , Buffer . from ( a ) ) === 0 )
138+ ) ;
139+
140+ // Dynamic ordering based on addressesIndex
141+ let sigSlots : ReturnType < typeof utils . createNewSig > [ ] ;
142+ if ( addressesIndex [ bitgoIndex ] < addressesIndex [ firstIndex ] ) {
143+ // Bitgo comes first: [zeros, userAddress]
144+ sigSlots = [
145+ utils . createNewSig ( '' ) ,
146+ utils . createEmptySigWithAddress (
147+ Buffer . from ( this . transaction . _fromAddresses [ firstIndex ] ) . toString ( 'hex' )
148+ ) ,
149+ ] ;
150+ } else {
151+ // User comes first: [userAddress, zeros]
152+ sigSlots = [
153+ utils . createEmptySigWithAddress (
154+ Buffer . from ( this . transaction . _fromAddresses [ firstIndex ] ) . toString ( 'hex' )
155+ ) ,
156+ utils . createNewSig ( '' ) ,
157+ ] ;
158+ }
159+ return new Credential ( sigSlots ) ;
160+ } else {
161+ // Fallback: use all zeros if no UTXO addresses available
162+ const sigSlots : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
163+ for ( let i = 0 ; i < inputThreshold ; i ++ ) {
164+ sigSlots . push ( utils . createNewSig ( '' ) ) ;
165+ }
166+ return new Credential ( sigSlots ) ;
129167 }
130- return new Credential ( sigSlots ) ;
131168 } ) ;
132169
133170 // Create address maps for signing - one per input/credential
@@ -277,14 +314,43 @@ export class ExportInPTxBuilder extends AtomicTransactionBuilder {
277314
278315 inputs . push ( transferableInput ) ;
279316
280- // Create credential with empty signatures that have embedded addresses for slot identification
281- // This allows the signing logic to determine which slot belongs to which address
282- const sortedAddrs = [ ...this . transaction . _fromAddresses ] . sort ( ( a , b ) => Buffer . compare ( a , b ) ) ;
283- const emptySignatures = sigIndices . map ( ( idx ) => {
284- const addrHex = Buffer . from ( sortedAddrs [ idx ] ) . toString ( 'hex' ) ;
285- return utils . createEmptySigWithAddress ( addrHex ) ;
286- } ) ;
287- credentials . push ( new Credential ( emptySignatures ) ) ;
317+ // Create credential with empty signatures for slot identification
318+ // Match avaxp behavior: dynamic ordering based on addressesIndex from UTXO
319+ const hasAddresses =
320+ this . transaction . _fromAddresses && this . transaction . _fromAddresses . length >= this . transaction . _threshold ;
321+
322+ if ( ! hasAddresses ) {
323+ // If addresses not available, use all zeros
324+ const emptySignatures = sigIndices . map ( ( ) => utils . createNewSig ( '' ) ) ;
325+ credentials . push ( new Credential ( emptySignatures ) ) ;
326+ } else {
327+ // Compute addressesIndex: position of each _fromAddresses in UTXO's address list
328+ const utxoAddresses = utxo . addresses . map ( ( a ) => utils . parseAddress ( a ) ) ;
329+ const addressesIndex = this . transaction . _fromAddresses . map ( ( a ) =>
330+ utxoAddresses . findIndex ( ( u ) => Buffer . compare ( Buffer . from ( u ) , Buffer . from ( a ) ) === 0 )
331+ ) ;
332+
333+ // either user (0) or recovery (2)
334+ const firstIndex = this . recoverSigner ? 2 : 0 ;
335+ const bitgoIndex = 1 ;
336+
337+ // Dynamic ordering based on addressesIndex
338+ let emptySignatures : ReturnType < typeof utils . createNewSig > [ ] ;
339+ if ( addressesIndex [ bitgoIndex ] < addressesIndex [ firstIndex ] ) {
340+ // Bitgo comes first in signature order: [zeros, userAddress]
341+ emptySignatures = [
342+ utils . createNewSig ( '' ) ,
343+ utils . createEmptySigWithAddress ( Buffer . from ( this . transaction . _fromAddresses [ firstIndex ] ) . toString ( 'hex' ) ) ,
344+ ] ;
345+ } else {
346+ // User comes first in signature order: [userAddress, zeros]
347+ emptySignatures = [
348+ utils . createEmptySigWithAddress ( Buffer . from ( this . transaction . _fromAddresses [ firstIndex ] ) . toString ( 'hex' ) ) ,
349+ utils . createNewSig ( '' ) ,
350+ ] ;
351+ }
352+ credentials . push ( new Credential ( emptySignatures ) ) ;
353+ }
288354 }
289355
290356 // Create change output if there is remaining amount after export and fee
0 commit comments