@@ -115,6 +115,130 @@ describe('Flrp Import In C Tx Builder', () => {
115115 const calculatedOutput = inputAmount - calculatedFee ;
116116 assert ( outputAmount === calculatedOutput , 'Output should equal input minus total fee' ) ;
117117 } ) ;
118+
119+ it ( 'should use consistent fee calculation in initBuilder and buildFlareTransaction' , async ( ) => {
120+ const inputAmount = '100000000' ; // 100M nanoFLRP (matches real-world transaction)
121+ const expectedFeeRate = 500 ; // Real feeRate from working transaction
122+ const threshold = 2 ;
123+
124+ const utxo : DecodedUtxoObj = {
125+ outputID : 0 ,
126+ amount : inputAmount ,
127+ txid : '2vPMx8P63adgBae7GAWFx7qvJDwRmMnDCyKddHRBXWhysjX4BP' ,
128+ outputidx : '0' ,
129+ addresses : [
130+ '0x3329be7d01cd3ebaae6654d7327dd9f17a2e1581' ,
131+ '0x7e918a5e8083ae4c9f2f0ed77055c24bf3665001' ,
132+ '0xc7324437c96c7c8a6a152da2385c1db5c3ab1f91' ,
133+ ] ,
134+ threshold : threshold ,
135+ } ;
136+
137+ const txBuilder = factory
138+ . getImportInCBuilder ( )
139+ . threshold ( threshold )
140+ . fromPubKey ( testData . pAddresses )
141+ . utxos ( [ utxo ] )
142+ . to ( testData . to )
143+ . feeRate ( expectedFeeRate . toString ( ) ) ;
144+
145+ const tx = await txBuilder . build ( ) ;
146+ const calculatedFee = BigInt ( ( tx as any ) . fee . fee ) ;
147+ const feeInfo = ( tx as any ) . fee ;
148+
149+ const maxReasonableFee = BigInt ( inputAmount ) / BigInt ( 10 ) ; // Max 10% of input
150+ assert (
151+ calculatedFee < maxReasonableFee ,
152+ `Fee ${ calculatedFee } should be less than 10% of input (${ maxReasonableFee } )`
153+ ) ;
154+
155+ const expectedMinFee = BigInt ( expectedFeeRate ) * BigInt ( 12000 ) ;
156+ const expectedMaxFee = BigInt ( expectedFeeRate ) * BigInt ( 13000 ) ;
157+
158+ assert ( calculatedFee >= expectedMinFee , `Fee ${ calculatedFee } should be at least ${ expectedMinFee } ` ) ;
159+ assert ( calculatedFee <= expectedMaxFee , `Fee ${ calculatedFee } should not exceed ${ expectedMaxFee } ` ) ;
160+
161+ const outputAmount = BigInt ( tx . outputs [ 0 ] . value ) ;
162+ assert ( outputAmount > BigInt ( 0 ) , 'Output should be positive' ) ;
163+
164+ const expectedOutput = BigInt ( inputAmount ) - calculatedFee ;
165+ assert (
166+ outputAmount === expectedOutput ,
167+ `Output ${ outputAmount } should equal input ${ inputAmount } minus fee ${ calculatedFee } `
168+ ) ;
169+
170+ const txHex = tx . toBroadcastFormat ( ) ;
171+ const parsedBuilder = factory . from ( txHex ) ;
172+ const parsedTx = await parsedBuilder . build ( ) ;
173+ const parsedFeeRate = ( parsedTx as any ) . fee . feeRate ;
174+
175+ assert ( parsedFeeRate !== undefined && parsedFeeRate > 0 , 'Parsed feeRate should be defined and positive' ) ;
176+
177+ const feeRateDiff = Math . abs ( parsedFeeRate ! - expectedFeeRate ) ;
178+ const maxAllowedDiff = 10 ;
179+ assert (
180+ feeRateDiff <= maxAllowedDiff ,
181+ `Parsed feeRate ${ parsedFeeRate } should be close to original ${ expectedFeeRate } (diff: ${ feeRateDiff } )`
182+ ) ;
183+
184+ const feeSize = feeInfo . size ! ;
185+ assert ( feeSize > 10000 , `Fee size ${ feeSize } should include fixed cost (10000) + input costs` ) ;
186+ assert ( feeSize < 20000 , `Fee size ${ feeSize } should be reasonable (< 20000)` ) ;
187+ } ) ;
188+
189+ it ( 'should prevent artificially inflated feeRate from using wrong calculation' , async ( ) => {
190+ const inputAmount = '100000000' ; // 100M nanoFLRP
191+ const threshold = 2 ;
192+
193+ const utxo : DecodedUtxoObj = {
194+ outputID : 0 ,
195+ amount : inputAmount ,
196+ txid : '2vPMx8P63adgBae7GAWFx7qvJDwRmMnDCyKddHRBXWhysjX4BP' ,
197+ outputidx : '0' ,
198+ addresses : [
199+ '0x3329be7d01cd3ebaae6654d7327dd9f17a2e1581' ,
200+ '0x7e918a5e8083ae4c9f2f0ed77055c24bf3665001' ,
201+ '0xc7324437c96c7c8a6a152da2385c1db5c3ab1f91' ,
202+ ] ,
203+ threshold : threshold ,
204+ } ;
205+
206+ const feeRate = 500 ;
207+
208+ const txBuilder = factory
209+ . getImportInCBuilder ( )
210+ . threshold ( threshold )
211+ . fromPubKey ( testData . pAddresses )
212+ . utxos ( [ utxo ] )
213+ . to ( testData . to )
214+ . feeRate ( feeRate . toString ( ) ) ;
215+
216+ let tx ;
217+ try {
218+ tx = await txBuilder . build ( ) ;
219+ } catch ( error : any ) {
220+ throw new Error (
221+ `Transaction build failed (this was the OLD bug behavior): ${ error . message } . ` +
222+ `The fix ensures calculateImportCost() is used consistently.`
223+ ) ;
224+ }
225+
226+ const calculatedFee = BigInt ( ( tx as any ) . fee . fee ) ;
227+
228+ const oldBugFee = BigInt ( 328000000 ) ;
229+ const reasonableFee = BigInt ( 10000000 ) ;
230+
231+ assert (
232+ calculatedFee < reasonableFee ,
233+ `Fee ${ calculatedFee } should be reasonable (< ${ reasonableFee } ), not inflated like OLD bug (~${ oldBugFee } )`
234+ ) ;
235+
236+ const outputAmount = BigInt ( tx . outputs [ 0 ] . value ) ;
237+ assert (
238+ outputAmount > BigInt ( 0 ) ,
239+ `Output ${ outputAmount } should be positive. OLD bug would make output negative due to excessive fee.`
240+ ) ;
241+ } ) ;
118242 } ) ;
119243
120244 describe ( 'on-chain verified transactions' , ( ) => {
0 commit comments