@@ -288,4 +288,128 @@ 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+
319+ if ( threshold === 1 ) {
320+ if ( sender && sender . length > firstIndex && addressesIndex [ firstIndex ] !== undefined ) {
321+ return new Credential ( [ utils . createEmptySigWithAddress ( Buffer . from ( sender [ firstIndex ] ) . toString ( 'hex' ) ) ] ) ;
322+ }
323+ return new Credential ( [ utils . createNewSig ( '' ) ] ) ;
324+ }
325+
326+ // For threshold >= 2, use the actual sigIndices order from FlareJS
327+ // sigIndices[i] = position in UTXO's owner addresses that needs to sign
328+ // addressesIndex[senderIdx] = position in UTXO's owner addresses for that sender
329+ //
330+ // We need to find which sender corresponds to each sigIndex and create signatures
331+ // in the sigIndices order.
332+ if ( actualSigIndices . length >= 2 && addressesIndex . length >= 2 && sender && sender . length >= threshold ) {
333+ const emptySignatures : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
334+
335+ for ( const sigIdx of actualSigIndices ) {
336+ // Find which sender address is at this UTXO position
337+ // addressesIndex[senderIdx] tells us which UTXO position each sender is at
338+ const senderIdx = addressesIndex . findIndex ( ( utxoPos ) => utxoPos === sigIdx ) ;
339+
340+ if ( senderIdx === firstIndex ) {
341+ // This sigIndex slot is for user/recovery - embed their address
342+ emptySignatures . push ( utils . createEmptySigWithAddress ( Buffer . from ( sender [ firstIndex ] ) . toString ( 'hex' ) ) ) ;
343+ } else {
344+ // BitGo (HSM) or unknown sender - empty signature
345+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
346+ }
347+ }
348+
349+ return new Credential ( emptySignatures ) ;
350+ }
351+
352+ // Fallback: create threshold empty signatures
353+ const emptySignatures : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
354+ for ( let i = 0 ; i < threshold ; i ++ ) {
355+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
356+ }
357+ return new Credential ( emptySignatures ) ;
358+ }
359+
360+ /**
361+ * Create AddressMap using the ACTUAL sigIndices from FlareJS.
362+ *
363+ * Maps sender addresses to signature slots based on the actual sigIndices order.
364+ *
365+ * @param utxo - The UTXO to create AddressMap for
366+ * @param threshold - Number of signatures required
367+ * @param actualSigIndices - The actual sigIndices from FlareJS's built input
368+ * @returns AddressMap that maps addresses to signature slots
369+ * @protected
370+ */
371+ protected createAddressMapForUtxoWithSigIndices (
372+ utxo : DecodedUtxoObj ,
373+ threshold : number ,
374+ actualSigIndices : number [ ]
375+ ) : FlareUtils . AddressMap {
376+ const addressMap = new FlareUtils . AddressMap ( ) ;
377+ const sender = this . transaction . _fromAddresses ;
378+ const addressesIndex = utxo . addressesIndex ?? [ ] ;
379+
380+ const firstIndex = this . recoverSigner ? 2 : 0 ;
381+ const bitgoIndex = 1 ;
382+
383+ if ( threshold === 1 ) {
384+ if ( sender && sender . length > firstIndex ) {
385+ addressMap . set ( new Address ( sender [ firstIndex ] ) , 0 ) ;
386+ } else if ( sender && sender . length > 0 ) {
387+ addressMap . set ( new Address ( sender [ 0 ] ) , 0 ) ;
388+ }
389+ return addressMap ;
390+ }
391+
392+ // For threshold >= 2, map addresses based on actual sigIndices order
393+ if ( actualSigIndices . length >= 2 && addressesIndex . length >= 2 && sender && sender . length >= threshold ) {
394+ actualSigIndices . forEach ( ( sigIdx , slotIdx ) => {
395+ // Find which sender is at this UTXO position
396+ const senderIdx = addressesIndex . findIndex ( ( utxoPos ) => utxoPos === sigIdx ) ;
397+
398+ if ( senderIdx === bitgoIndex || senderIdx === firstIndex ) {
399+ addressMap . set ( new Address ( sender [ senderIdx ] ) , slotIdx ) ;
400+ }
401+ } ) ;
402+
403+ return addressMap ;
404+ }
405+
406+ // Fallback
407+ if ( sender && sender . length >= threshold ) {
408+ sender . slice ( 0 , threshold ) . forEach ( ( addr , i ) => {
409+ addressMap . set ( new Address ( addr ) , i ) ;
410+ } ) ;
411+ }
412+
413+ return addressMap ;
414+ }
291415}
0 commit comments