@@ -288,4 +288,134 @@ export abstract class AtomicTransactionBuilder extends TransactionBuilder {
288288
289289 return addressMap ;
290290 }
291+
292+ /**
293+ * Create credential using the ACTUAL sigIndices from FlareJS.
294+ *
295+ * This method determines which sender addresses correspond to which sigIndex positions,
296+ * then creates the credential with signatures in the correct order matching the sigIndices.
297+ *
298+ * sigIndices tell us which positions in the UTXO's owner addresses need to sign.
299+ * We need to figure out which sender addresses are at those positions and create
300+ * signature slots in the same order as sigIndices.
301+ *
302+ * @param utxo - The UTXO to create credential for
303+ * @param threshold - Number of signatures required
304+ * @param actualSigIndices - The actual sigIndices from FlareJS's built input
305+ * @returns Credential with signatures ordered to match sigIndices
306+ * @protected
307+ */
308+ protected createCredentialForUtxoWithSigIndices (
309+ utxo : DecodedUtxoObj ,
310+ threshold : number ,
311+ actualSigIndices : number [ ]
312+ ) : Credential {
313+ const sender = this . transaction . _fromAddresses ;
314+ const addressesIndex = utxo . addressesIndex ?? [ ] ;
315+
316+ // either user (0) or recovery (2)
317+ const firstIndex = this . recoverSigner ? 2 : 0 ;
318+ const bitgoIndex = 1 ;
319+
320+ if ( threshold === 1 ) {
321+ if ( sender && sender . length > firstIndex && addressesIndex [ firstIndex ] !== undefined ) {
322+ return new Credential ( [ utils . createEmptySigWithAddress ( Buffer . from ( sender [ firstIndex ] ) . toString ( 'hex' ) ) ] ) ;
323+ }
324+ return new Credential ( [ utils . createNewSig ( '' ) ] ) ;
325+ }
326+
327+ // For threshold >= 2, use the actual sigIndices order from FlareJS
328+ // sigIndices[i] = position in UTXO's owner addresses that needs to sign
329+ // addressesIndex[senderIdx] = position in UTXO's owner addresses for that sender
330+ //
331+ // We need to find which sender corresponds to each sigIndex and create signatures
332+ // in the sigIndices order.
333+ if ( actualSigIndices . length >= 2 && addressesIndex . length >= 2 && sender && sender . length >= threshold ) {
334+ const emptySignatures : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
335+
336+ for ( const sigIdx of actualSigIndices ) {
337+ // Find which sender address is at this UTXO position
338+ // addressesIndex[senderIdx] tells us which UTXO position each sender is at
339+ const senderIdx = addressesIndex . findIndex ( ( utxoPos ) => utxoPos === sigIdx ) ;
340+
341+ if ( senderIdx === bitgoIndex ) {
342+ // This sigIndex slot is for BitGo (HSM) - empty signature
343+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
344+ } else if ( senderIdx === firstIndex ) {
345+ // This sigIndex slot is for user/recovery - embed their address
346+ emptySignatures . push ( utils . createEmptySigWithAddress ( Buffer . from ( sender [ firstIndex ] ) . toString ( 'hex' ) ) ) ;
347+ } else {
348+ // Fallback for unknown sender - empty signature
349+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
350+ }
351+ }
352+
353+ return new Credential ( emptySignatures ) ;
354+ }
355+
356+ // Fallback: create threshold empty signatures
357+ const emptySignatures : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
358+ for ( let i = 0 ; i < threshold ; i ++ ) {
359+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
360+ }
361+ return new Credential ( emptySignatures ) ;
362+ }
363+
364+ /**
365+ * Create AddressMap using the ACTUAL sigIndices from FlareJS.
366+ *
367+ * Maps sender addresses to signature slots based on the actual sigIndices order.
368+ *
369+ * @param utxo - The UTXO to create AddressMap for
370+ * @param threshold - Number of signatures required
371+ * @param actualSigIndices - The actual sigIndices from FlareJS's built input
372+ * @returns AddressMap that maps addresses to signature slots
373+ * @protected
374+ */
375+ protected createAddressMapForUtxoWithSigIndices (
376+ utxo : DecodedUtxoObj ,
377+ threshold : number ,
378+ actualSigIndices : number [ ]
379+ ) : FlareUtils . AddressMap {
380+ const addressMap = new FlareUtils . AddressMap ( ) ;
381+ const sender = this . transaction . _fromAddresses ;
382+ const addressesIndex = utxo . addressesIndex ?? [ ] ;
383+
384+ const firstIndex = this . recoverSigner ? 2 : 0 ;
385+ const bitgoIndex = 1 ;
386+
387+ if ( threshold === 1 ) {
388+ if ( sender && sender . length > firstIndex ) {
389+ addressMap . set ( new Address ( sender [ firstIndex ] ) , 0 ) ;
390+ } else if ( sender && sender . length > 0 ) {
391+ addressMap . set ( new Address ( sender [ 0 ] ) , 0 ) ;
392+ }
393+ return addressMap ;
394+ }
395+
396+ // For threshold >= 2, map addresses based on actual sigIndices order
397+ if ( actualSigIndices . length >= 2 && addressesIndex . length >= 2 && sender && sender . length >= threshold ) {
398+ actualSigIndices . forEach ( ( sigIdx , slotIdx ) => {
399+ // Find which sender is at this UTXO position
400+ const senderIdx = addressesIndex . findIndex ( ( utxoPos ) => utxoPos === sigIdx ) ;
401+
402+ if ( senderIdx === bitgoIndex ) {
403+ addressMap . set ( new Address ( sender [ bitgoIndex ] ) , slotIdx ) ;
404+ } else if ( senderIdx === firstIndex ) {
405+ addressMap . set ( new Address ( sender [ firstIndex ] ) , slotIdx ) ;
406+ }
407+ } ) ;
408+
409+ return addressMap ;
410+ }
411+
412+ // Fallback
413+ if ( sender && sender . length >= threshold ) {
414+ sender . slice ( 0 , threshold ) . forEach ( ( addr , i ) => {
415+ addressMap . set ( new Address ( addr ) , i ) ;
416+ } ) ;
417+ }
418+
419+ return addressMap ;
420+ }
291421}
0 commit comments