@@ -9,6 +9,41 @@ import { eth_gasPrice, getRpcClient, type Address } from "thirdweb";
99import { thirdwebClient } from "../../../shared/utils/sdk" ;
1010import { getAddress } from "thirdweb" ;
1111
12+ // Helper constants and functions for bigint formatting
13+ const WEI_PER_ETH = 10n ** 18n ;
14+
15+ const formatWei = ( value : bigint , fractionDigits = 6 ) : string => {
16+ const sign = value < 0n ? "-" : "" ;
17+ const abs = value < 0n ? - value : value ;
18+ const integer = abs / WEI_PER_ETH ;
19+ const remainder = abs % WEI_PER_ETH ;
20+ if ( fractionDigits === 0 ) {
21+ return `${ sign } ${ integer . toString ( ) } ` ;
22+ }
23+ const scale = 10n ** BigInt ( fractionDigits ) ;
24+ const fractional = ( remainder * scale ) / WEI_PER_ETH ;
25+ return `${ sign } ${ integer . toString ( ) } .${ fractional
26+ . toString ( )
27+ . padStart ( fractionDigits , "0" ) } `;
28+ } ;
29+
30+ const formatPercent = (
31+ numerator : bigint ,
32+ denominator : bigint ,
33+ fractionDigits = 1 ,
34+ ) : string => {
35+ if ( denominator === 0n || numerator === 0n ) {
36+ return `0.${ "0" . repeat ( fractionDigits ) } ` ;
37+ }
38+ const scale = 10n ** BigInt ( fractionDigits ) ;
39+ const scaled = ( numerator * 100n * scale ) / denominator ;
40+ const integer = scaled / scale ;
41+ const remainder = scaled % scale ;
42+ return `${ integer . toString ( ) } .${ remainder
43+ . toString ( )
44+ . padStart ( fractionDigits , "0" ) } `;
45+ } ;
46+
1247const batchRequestSchema = Type . Object ( {
1348 fromAddress : Type . String ( {
1449 description : "The wallet address to send transactions from" ,
@@ -204,12 +239,20 @@ export async function estimateBatchTransactions(fastify: FastifyInstance) {
204239 ) ;
205240 const totalCostWei = totalGasEstimate * gasPrice ;
206241
207- // Calculate savings vs individual transactions
208- // Batching saves on base gas and reduces total gas by ~15%
209- const individualCostWei =
210- BigInt ( transactions . length ) * ( 21000n * gasPrice ) ;
242+ // Calculate savings vs individual transactions with proper gas estimation
243+ // Apply expected savings percentages based on optimization strategy
244+ const savingsBpsByStrategy : Record < "speed" | "balanced" | "cost" , bigint > = {
245+ speed : 0n , // No savings for speed mode
246+ balanced : 15n , // 15% savings for balanced
247+ cost : 25n , // 25% savings for cost mode
248+ } ;
249+ const savingsBps = savingsBpsByStrategy [ optimization ] ?? 15n ;
250+
251+ // Individual gas estimate = batch gas * (100 + savings%) / 100
252+ const individualGasEstimate = ( totalGasEstimate * ( 100n + savingsBps ) ) / 100n ;
253+ const individualCostWei = individualGasEstimate * gasPrice ;
254+ const savingsGas = individualGasEstimate - totalGasEstimate ;
211255 const savingsWei = individualCostWei - totalCostWei ;
212- const savingsPercent = Number ( ( savingsWei * 100n ) / individualCostWei ) ;
213256
214257 // Optimization strategy recommendations
215258 let estimatedTimeSeconds = 30 ;
@@ -266,12 +309,12 @@ export async function estimateBatchTransactions(fastify: FastifyInstance) {
266309 totalGasEstimate : totalGasEstimate . toString ( ) ,
267310 gasPrice : gasPrice . toString ( ) ,
268311 totalCostWei : totalCostWei . toString ( ) ,
269- totalCostEth : ( Number ( totalCostWei ) / 1e18 ) . toFixed ( 6 ) ,
312+ totalCostEth : formatWei ( totalCostWei , 6 ) ,
270313 perTransactionCostWei : ( totalCostWei / BigInt ( transactions . length ) ) . toString ( ) ,
271314 } ,
272315 optimization : {
273316 strategy : optimization ,
274- savingsVsIndividual : `${ savingsPercent . toFixed ( 1 ) } % (${ ( Number ( savingsWei ) / 1e18 ) . toFixed ( 6 ) } ETH)` ,
317+ savingsVsIndividual : `${ formatPercent ( savingsGas , individualGasEstimate , 1 ) } % (${ formatWei ( savingsWei , 6 ) } ETH)` ,
275318 estimatedTimeSeconds,
276319 recommendation,
277320 } ,
0 commit comments