99 Int ,
1010 Id ,
1111 TransferableInput ,
12- TypeSymbols ,
1312 Address ,
1413 utils as FlareUtils ,
1514 avmSerial ,
@@ -36,7 +35,7 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
3635 return TransactionType . Import ;
3736 }
3837
39- initBuilder ( tx : Tx ) : this {
38+ initBuilder ( tx : Tx , rawBytes ?: Buffer , parsedCredentials ?: Credential [ ] ) : this {
4039 const baseTx = tx as evmSerial . ImportTx ;
4140 if ( ! this . verifyTxType ( baseTx . _type ) ) {
4241 throw new NotSupported ( 'Transaction cannot be parsed or has an unsupported transaction type' ) ;
@@ -50,8 +49,7 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
5049 }
5150 const output = outputs [ 0 ] ;
5251
53- const assetIdStr = Buffer . from ( this . transaction . _assetId ) . toString ( 'hex' ) ;
54- if ( Buffer . from ( output . assetId . toBytes ( ) ) . toString ( 'hex' ) !== assetIdStr ) {
52+ if ( Buffer . from ( output . assetId . toBytes ( ) ) . toString ( 'hex' ) !== this . transaction . _assetId ) {
5553 throw new Error ( 'AssetID are not equals' ) ;
5654 }
5755 this . transaction . _to = [ Buffer . from ( output . address . toBytes ( ) ) ] ;
@@ -66,20 +64,55 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
6664 // Calculate fee based on input/output difference
6765 const fee = totalInputAmount - totalOutputAmount ;
6866 const feeSize = this . calculateFeeSize ( baseTx ) ;
69- const feeRate = Number ( fee ) / feeSize ;
67+ // Use integer division to ensure feeRate can be converted back to BigInt
68+ const feeRate = Math . floor ( Number ( fee ) / feeSize ) ;
7069
7170 this . transaction . _fee = {
7271 fee : fee . toString ( ) ,
7372 feeRate : feeRate ,
7473 size : feeSize ,
7574 } ;
7675
77- this . transaction . setTransaction ( tx ) ;
76+ // Use credentials passed from TransactionBuilderFactory (properly extracted using codec)
77+ const credentials = parsedCredentials || [ ] ;
78+ const hasCredentials = credentials . length > 0 ;
79+
80+ // If it's a signed transaction, store the original raw bytes to preserve exact format
81+ if ( hasCredentials && rawBytes ) {
82+ this . transaction . _rawSignedBytes = rawBytes ;
83+ }
84+
85+ // Extract threshold from first input's sigIndicies (number of required signatures)
86+ const firstInput = inputs [ 0 ] ;
87+ const inputThreshold = firstInput . sigIndicies ( ) . length || this . transaction . _threshold ;
88+ this . transaction . _threshold = inputThreshold ;
89+
90+ // Create proper UnsignedTx wrapper with credentials
91+ const toAddress = new Address ( output . address . toBytes ( ) ) ;
92+ const addressMap = new FlareUtils . AddressMap ( [ [ toAddress , 0 ] ] ) ;
93+ const addressMaps = new FlareUtils . AddressMaps ( [ addressMap ] ) ;
94+
95+ // When credentials were extracted, use them directly to preserve existing signatures
96+ let txCredentials : Credential [ ] ;
97+ if ( credentials . length > 0 ) {
98+ txCredentials = credentials ;
99+ } else {
100+ // Create empty credential with threshold number of signature slots
101+ const emptySignatures : ReturnType < typeof utils . createNewSig > [ ] = [ ] ;
102+ for ( let i = 0 ; i < inputThreshold ; i ++ ) {
103+ emptySignatures . push ( utils . createNewSig ( '' ) ) ;
104+ }
105+ txCredentials = [ new Credential ( emptySignatures ) ] ;
106+ }
107+
108+ const unsignedTx = new UnsignedTx ( baseTx , [ ] , addressMaps , txCredentials ) ;
109+
110+ this . transaction . setTransaction ( unsignedTx ) ;
78111 return this ;
79112 }
80113
81114 static verifyTxType ( txnType : string ) : boolean {
82- return txnType === FlareTransactionType . PvmImportTx ;
115+ return txnType === FlareTransactionType . EvmImportTx ;
83116 }
84117
85118 verifyTxType ( txnType : string ) : boolean {
@@ -91,8 +124,10 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
91124 * @protected
92125 */
93126 protected buildFlareTransaction ( ) : void {
94- // if tx has credentials, tx shouldn't change
127+ // if tx has credentials or was already recovered from raw , tx shouldn't change
95128 if ( this . transaction . hasCredentials ) return ;
129+ // If fee is already calculated (from initBuilder), the transaction is already built
130+ if ( this . transaction . _fee . fee ) return ;
96131 if ( this . transaction . _to . length !== 1 ) {
97132 throw new Error ( 'to is required' ) ;
98133 }
@@ -109,14 +144,12 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
109144 this . transaction . _fee . fee = fee . toString ( ) ;
110145 this . transaction . _fee . size = feeSize ;
111146
112- // Create output with required interface implementation
113- const output = {
114- _type : TypeSymbols . BaseTx ,
115- address : new Address ( this . transaction . _to [ 0 ] ) ,
116- amount : new BigIntPr ( amount - fee ) ,
117- assetId : new Id ( new Uint8Array ( Buffer . from ( this . transaction . _assetId , 'hex' ) ) ) ,
118- toBytes : ( ) => new Uint8Array ( ) ,
119- } ;
147+ // Create EVM output using proper FlareJS class
148+ const output = new evmSerial . Output (
149+ new Address ( this . transaction . _to [ 0 ] ) ,
150+ new BigIntPr ( amount - fee ) ,
151+ new Id ( new Uint8Array ( Buffer . from ( this . transaction . _assetId , 'hex' ) ) )
152+ ) ;
120153
121154 // Create the import transaction
122155 const importTx = new evmSerial . ImportTx (
@@ -127,8 +160,11 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
127160 [ output ]
128161 ) ;
129162
130- // Create unsigned transaction
131- const addressMap = new FlareUtils . AddressMap ( [ [ new Address ( this . transaction . _fromAddresses [ 0 ] ) , 0 ] ] ) ;
163+ // Create unsigned transaction with all potential signers in address map
164+ const addressMap = new FlareUtils . AddressMap ( ) ;
165+ this . transaction . _fromAddresses . forEach ( ( addr , i ) => {
166+ addressMap . set ( new Address ( addr ) , i ) ;
167+ } ) ;
132168 const addressMaps = new FlareUtils . AddressMaps ( [ addressMap ] ) ;
133169
134170 const unsignedTx = new UnsignedTx (
@@ -172,49 +208,29 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
172208 const amount = BigInt ( utxo . amount ) ;
173209 totalAmount += amount ;
174210
175- // Create input with proper interface implementation
176- const input = {
177- _type : TypeSymbols . Input ,
178- amount : ( ) => amount ,
179- sigIndices : sender . map ( ( _ , i ) => i ) ,
180- toBytes : ( ) => new Uint8Array ( ) ,
181- } ;
182-
183- // Create TransferableInput with proper UTXOID implementation
184- const txId = new Id ( new Uint8Array ( Buffer . from ( utxo . txid , 'hex' ) ) ) ;
185- const outputIdxInt = new Int ( Number ( utxo . outputidx ) ) ;
186- const outputIdxBytes = new Uint8Array ( Buffer . alloc ( 4 ) ) ;
187- new DataView ( outputIdxBytes . buffer ) . setInt32 ( 0 , Number ( utxo . outputidx ) , true ) ;
188- const outputIdxId = new Id ( outputIdxBytes ) ;
189-
190- // Create asset with complete Amounter interface
191- const assetIdBytes = new Uint8Array ( Buffer . from ( this . transaction . _assetId , 'hex' ) ) ;
192- const assetId = {
193- _type : TypeSymbols . BaseTx ,
194- amount : ( ) => amount ,
195- toBytes : ( ) => assetIdBytes ,
196- toString : ( ) => Buffer . from ( assetIdBytes ) . toString ( 'hex' ) ,
197- } ;
211+ // Create signature indices for threshold
212+ const sigIndices : number [ ] = [ ] ;
213+ for ( let i = 0 ; i < this . transaction . _threshold ; i ++ ) {
214+ sigIndices . push ( i ) ;
215+ }
198216
199- // Create TransferableInput with UTXOID using Int for outputIdx
200- const transferableInput = new TransferableInput (
201- {
202- _type : TypeSymbols . UTXOID ,
203- txID : txId ,
204- outputIdx : outputIdxInt ,
205- ID : ( ) => utxo . txid ,
206- toBytes : ( ) => new Uint8Array ( ) ,
207- } ,
208- outputIdxId , // Use Id type for TransferableInput constructor
209- assetId // Use asset with complete Amounter interface
217+ // Use fromNative to create TransferableInput (same pattern as ImportInPTxBuilder)
218+ // fromNative expects cb58-encoded strings for txId and assetId
219+ const txIdCb58 = utxo . txid ; // Already cb58 encoded
220+ const assetIdCb58 = utils . cb58Encode ( Buffer . from ( this . transaction . _assetId , 'hex' ) ) ;
221+
222+ const transferableInput = TransferableInput . fromNative (
223+ txIdCb58 ,
224+ Number ( utxo . outputidx ) ,
225+ assetIdCb58 ,
226+ amount ,
227+ sigIndices
210228 ) ;
211229
212- // Set input properties
213- Object . assign ( transferableInput , { input } ) ;
214230 inputs . push ( transferableInput ) ;
215231
216- // Create empty credential for each input
217- const emptySignatures = sender . map ( ( ) => utils . createNewSig ( '' ) ) ;
232+ // Create empty credential for each input with threshold signers
233+ const emptySignatures = sigIndices . map ( ( ) => utils . createNewSig ( '' ) ) ;
218234 const credential = new Credential ( emptySignatures ) ;
219235 credentials . push ( credential ) ;
220236 } ) ;
@@ -228,6 +244,7 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
228244
229245 /**
230246 * Calculate the fee size for the transaction
247+ * For C-chain imports, the feeRate is treated as an absolute fee value
231248 */
232249 private calculateFeeSize ( tx ?: evmSerial . ImportTx ) : number {
233250 // If tx is provided, calculate based on actual transaction size
@@ -236,14 +253,8 @@ export class ImportInCTxBuilder extends AtomicInCTransactionBuilder {
236253 return tx . toBytes ( codec ) . length ;
237254 }
238255
239- // Otherwise estimate based on typical import transaction size
240- const baseSize = 256 ; // Base transaction size
241- const inputSize = 128 ; // Size per input
242- const outputSize = 64 ; // Size per output
243- const numInputs = this . transaction . _utxos . length ;
244- const numOutputs = 1 ; // Import tx always has 1 output
245-
246- return baseSize + inputSize * numInputs + outputSize * numOutputs ;
256+ // For C-chain imports, treat feeRate as the absolute fee (multiplier of 1)
257+ return 1 ;
247258 }
248259
249260 /**
0 commit comments