@deserialize/multi-vm-wallet 1.5.33 → 1.5.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/evm/evm.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionRes
3
3
  import { VM } from "../vm";
4
4
  import { JsonRpcProvider } from "ethers";
5
5
  import { EVMTransactionHistoryItem } from "./transactionParsing";
6
- import { Hex, WalletClient, PublicClient } from "viem";
6
+ import { Hex, Call, WalletClient, PublicClient } from "viem";
7
7
  import { EVMSmartWallet } from "./smartWallet";
8
8
  import { SmartWalletOptions } from "./aa-service";
9
9
  import { PriceResponse } from "../price.types";
@@ -45,6 +45,7 @@ export declare class EVMChainAddress extends ChainAddress<string, PublicClient>
45
45
  discoverToken(): Promise<UserTokenBalance<string>[]>;
46
46
  discoverNFT(): Promise<NFT[]>;
47
47
  getTransactionHistory(): Promise<EVMTransactionHistoryItem[]>;
48
+ estimateGas(transaction: Call): Promise<bigint>;
48
49
  getPrices(tokenAddresses: string[]): Promise<PriceResponse>;
49
50
  }
50
51
  export declare class EVMChainWallet extends ChainWallet<string, string, PublicClient> {
package/dist/evm/evm.js CHANGED
@@ -457,6 +457,16 @@ class EVMChainAddress extends IChainWallet_1.ChainAddress {
457
457
  async getTransactionHistory() {
458
458
  return await (0, exports.getEvmTransactionHistorySafe)(this.connection, this.address);
459
459
  }
460
+ async estimateGas(transaction) {
461
+ try {
462
+ const gasEstimate = await this.connection.estimateGas(transaction);
463
+ return gasEstimate;
464
+ }
465
+ catch (error) {
466
+ console.error('Gas estimation failed:', error);
467
+ throw new Error('Failed to estimate gas for the transaction.');
468
+ }
469
+ }
460
470
  async getPrices(tokenAddresses) {
461
471
  return await (0, exports.getSvmPricesForTokens)(this.config, tokenAddresses);
462
472
  }
package/dist/svm/svm.d.ts CHANGED
@@ -66,6 +66,11 @@ export declare class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Conn
66
66
  sendTransaction(transaction: VersionedTransaction | Transaction): Promise<string>;
67
67
  signAndSendTransaction(transaction: VersionedTransaction | Transaction): Promise<string>;
68
68
  getTransactionHistory(): Promise<SVMTransactionHistoryItem[]>;
69
+ estimateGas(transaction: VersionedTransaction | Transaction): Promise<number>;
70
+ private extractComputeBudgetDetails;
71
+ private readU32LE;
72
+ private readU64LE;
73
+ private ceilDiv;
69
74
  getTokenInfo(tokenAddress: PublicKey): Promise<TokenInfo>;
70
75
  getPrices(tokenAddresses: string[]): Promise<PriceResponse>;
71
76
  swap(fromToken: TokenInfo, toToken: PublicKey, amount: number, slippage?: number): Promise<TransactionResult>;
package/dist/svm/svm.js CHANGED
@@ -438,6 +438,106 @@ class SVMChainWallet extends IChainWallet_1.ChainWallet {
438
438
  async getTransactionHistory() {
439
439
  return await (0, exports.getSvmTransactionHistoryForAddress)(this.connection, this.address);
440
440
  }
441
+ async estimateGas(transaction) {
442
+ const connection = this.connection;
443
+ if (transaction instanceof web3_js_1.Transaction) {
444
+ if (!transaction.feePayer) {
445
+ transaction.feePayer = this.address;
446
+ }
447
+ if (!transaction.recentBlockhash) {
448
+ const { blockhash } = await connection.getLatestBlockhash();
449
+ transaction.recentBlockhash = blockhash;
450
+ }
451
+ }
452
+ const message = transaction instanceof web3_js_1.Transaction
453
+ ? transaction.compileMessage()
454
+ : transaction.message;
455
+ const feeResponse = await connection.getFeeForMessage(message);
456
+ const baseFeeLamports = feeResponse.value ?? 0;
457
+ const { computeUnitPriceMicroLamports, computeUnitLimit } = this.extractComputeBudgetDetails(transaction);
458
+ if (computeUnitPriceMicroLamports === 0n) {
459
+ return baseFeeLamports;
460
+ }
461
+ let unitsConsumed;
462
+ try {
463
+ const simulation = transaction instanceof web3_js_1.Transaction
464
+ ? await connection.simulateTransaction(transaction)
465
+ : await connection.simulateTransaction(transaction, {
466
+ sigVerify: false,
467
+ replaceRecentBlockhash: true,
468
+ });
469
+ unitsConsumed = simulation.value.unitsConsumed ?? undefined;
470
+ }
471
+ catch {
472
+ }
473
+ const effectiveComputeUnits = BigInt(unitsConsumed ?? computeUnitLimit ?? 200_000);
474
+ const priorityFeeLamports = this.ceilDiv(effectiveComputeUnits * computeUnitPriceMicroLamports, 1000000n);
475
+ const totalFeeLamports = BigInt(baseFeeLamports) + priorityFeeLamports;
476
+ if (totalFeeLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
477
+ throw new Error("Estimated fee exceeds JavaScript safe integer range");
478
+ }
479
+ return Number(totalFeeLamports);
480
+ }
481
+ extractComputeBudgetDetails(transaction) {
482
+ let computeUnitPriceMicroLamports = 0n;
483
+ let computeUnitLimit;
484
+ if (transaction instanceof web3_js_1.Transaction) {
485
+ for (const instruction of transaction.instructions) {
486
+ if (!instruction.programId.equals(web3_js_1.ComputeBudgetProgram.programId)) {
487
+ continue;
488
+ }
489
+ const data = instruction.data;
490
+ if (!data || data.length === 0) {
491
+ continue;
492
+ }
493
+ const discriminator = data[0];
494
+ if (discriminator === 2 && data.length >= 5) {
495
+ computeUnitLimit = this.readU32LE(data, 1);
496
+ }
497
+ else if (discriminator === 3 && data.length >= 9) {
498
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
499
+ }
500
+ }
501
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
502
+ }
503
+ const message = transaction.message;
504
+ const compiledInstructions = message.compiledInstructions ?? [];
505
+ const staticAccountKeys = message.staticAccountKeys ?? [];
506
+ for (const instruction of compiledInstructions) {
507
+ const programId = staticAccountKeys[instruction.programIdIndex];
508
+ if (!programId || !programId.equals(web3_js_1.ComputeBudgetProgram.programId)) {
509
+ continue;
510
+ }
511
+ const data = instruction.data;
512
+ if (!data || data.length === 0) {
513
+ continue;
514
+ }
515
+ const discriminator = data[0];
516
+ if (discriminator === 2 && data.length >= 5) {
517
+ computeUnitLimit = this.readU32LE(data, 1);
518
+ }
519
+ else if (discriminator === 3 && data.length >= 9) {
520
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
521
+ }
522
+ }
523
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
524
+ }
525
+ readU32LE(data, offset) {
526
+ return (data[offset] |
527
+ (data[offset + 1] << 8) |
528
+ (data[offset + 2] << 16) |
529
+ (data[offset + 3] << 24)) >>> 0;
530
+ }
531
+ readU64LE(data, offset) {
532
+ let value = 0n;
533
+ for (let i = 0; i < 8; i++) {
534
+ value |= BigInt(data[offset + i]) << BigInt(8 * i);
535
+ }
536
+ return value;
537
+ }
538
+ ceilDiv(a, b) {
539
+ return (a + b - 1n) / b;
540
+ }
441
541
  async getTokenInfo(tokenAddress) {
442
542
  return await SVMVM.getTokenInfo(tokenAddress, this.connection);
443
543
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deserialize/multi-vm-wallet",
3
- "version": "1.5.33",
3
+ "version": "1.5.34",
4
4
  "devDependencies": {
5
5
  "@types/bn.js": "^5.2.0",
6
6
  "@types/crypto-js": "^4.2.2",
package/utils/evm/evm.ts CHANGED
@@ -917,6 +917,17 @@ export class EVMChainAddress extends ChainAddress<string, PublicClient> {
917
917
  return await getEvmTransactionHistorySafe(this.connection!, this.address);
918
918
  }
919
919
 
920
+ //add gas estimation method here?
921
+ async estimateGas(transaction: Call): Promise<bigint> {
922
+ try {
923
+ const gasEstimate = await this.connection!.estimateGas(transaction);
924
+ return gasEstimate;
925
+ } catch (error) {
926
+ console.error('Gas estimation failed:', error);
927
+ throw new Error('Failed to estimate gas for the transaction.');
928
+ }
929
+ }
930
+
920
931
  /**
921
932
  * Fetch price data for the provided token addresses.
922
933
  *
package/utils/svm/svm.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Connection, Keypair, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
1
+ import { ComputeBudgetProgram, Connection, Keypair, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
2
2
  import { SVMDeriveChildPrivateKey } from "../walletBip32";
3
3
  import { VM } from "../vm";
4
4
  import { ChainAddress, ChainWallet } from "../IChainWallet";
@@ -947,6 +947,143 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
947
947
  return await getSvmTransactionHistoryForAddress(this.connection!, this.address);
948
948
  }
949
949
 
950
+ //add gas estimation method here if needed, but note that Solana transactions typically have a fixed fee per signature and do not require gas estimation like EVM chains
951
+ async estimateGas(transaction: VersionedTransaction | Transaction): Promise<number> {
952
+ const connection = this.connection!;
953
+
954
+ if (transaction instanceof Transaction) {
955
+ if (!transaction.feePayer) {
956
+ transaction.feePayer = this.address;
957
+ }
958
+
959
+ if (!transaction.recentBlockhash) {
960
+ const { blockhash } = await connection.getLatestBlockhash();
961
+ transaction.recentBlockhash = blockhash;
962
+ }
963
+ }
964
+
965
+ const message = transaction instanceof Transaction
966
+ ? transaction.compileMessage()
967
+ : transaction.message;
968
+
969
+ const feeResponse = await connection.getFeeForMessage(message);
970
+ const baseFeeLamports = feeResponse.value ?? 0;
971
+
972
+ const { computeUnitPriceMicroLamports, computeUnitLimit } =
973
+ this.extractComputeBudgetDetails(transaction);
974
+
975
+ if (computeUnitPriceMicroLamports === 0n) {
976
+ return baseFeeLamports;
977
+ }
978
+
979
+ let unitsConsumed: number | undefined;
980
+ try {
981
+ const simulation = transaction instanceof Transaction
982
+ ? await connection.simulateTransaction(transaction)
983
+ : await connection.simulateTransaction(transaction, {
984
+ sigVerify: false,
985
+ replaceRecentBlockhash: true,
986
+ });
987
+ unitsConsumed = simulation.value.unitsConsumed ?? undefined;
988
+ } catch {
989
+ // Non-fatal: fall back to declared CU limit or a conservative default.
990
+ }
991
+
992
+ const effectiveComputeUnits = BigInt(
993
+ unitsConsumed ?? computeUnitLimit ?? 200_000
994
+ );
995
+
996
+ const priorityFeeLamports = this.ceilDiv(
997
+ effectiveComputeUnits * computeUnitPriceMicroLamports,
998
+ 1_000_000n
999
+ );
1000
+
1001
+ const totalFeeLamports = BigInt(baseFeeLamports) + priorityFeeLamports;
1002
+ if (totalFeeLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
1003
+ throw new Error("Estimated fee exceeds JavaScript safe integer range");
1004
+ }
1005
+
1006
+ return Number(totalFeeLamports);
1007
+ }
1008
+
1009
+ private extractComputeBudgetDetails(
1010
+ transaction: VersionedTransaction | Transaction
1011
+ ): { computeUnitPriceMicroLamports: bigint; computeUnitLimit?: number } {
1012
+ let computeUnitPriceMicroLamports = 0n;
1013
+ let computeUnitLimit: number | undefined;
1014
+
1015
+ if (transaction instanceof Transaction) {
1016
+ for (const instruction of transaction.instructions) {
1017
+ if (!instruction.programId.equals(ComputeBudgetProgram.programId)) {
1018
+ continue;
1019
+ }
1020
+
1021
+ const data = instruction.data;
1022
+ if (!data || data.length === 0) {
1023
+ continue;
1024
+ }
1025
+
1026
+ const discriminator = data[0];
1027
+ if (discriminator === 2 && data.length >= 5) {
1028
+ computeUnitLimit = this.readU32LE(data, 1);
1029
+ } else if (discriminator === 3 && data.length >= 9) {
1030
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
1031
+ }
1032
+ }
1033
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
1034
+ }
1035
+
1036
+ const message = transaction.message as {
1037
+ compiledInstructions?: Array<{ programIdIndex: number; data: Uint8Array }>;
1038
+ staticAccountKeys?: PublicKey[];
1039
+ };
1040
+
1041
+ const compiledInstructions = message.compiledInstructions ?? [];
1042
+ const staticAccountKeys = message.staticAccountKeys ?? [];
1043
+
1044
+ for (const instruction of compiledInstructions) {
1045
+ const programId = staticAccountKeys[instruction.programIdIndex];
1046
+ if (!programId || !programId.equals(ComputeBudgetProgram.programId)) {
1047
+ continue;
1048
+ }
1049
+
1050
+ const data = instruction.data;
1051
+ if (!data || data.length === 0) {
1052
+ continue;
1053
+ }
1054
+
1055
+ const discriminator = data[0];
1056
+ if (discriminator === 2 && data.length >= 5) {
1057
+ computeUnitLimit = this.readU32LE(data, 1);
1058
+ } else if (discriminator === 3 && data.length >= 9) {
1059
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
1060
+ }
1061
+ }
1062
+
1063
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
1064
+ }
1065
+
1066
+ private readU32LE(data: Uint8Array, offset: number): number {
1067
+ return (
1068
+ data[offset] |
1069
+ (data[offset + 1] << 8) |
1070
+ (data[offset + 2] << 16) |
1071
+ (data[offset + 3] << 24)
1072
+ ) >>> 0;
1073
+ }
1074
+
1075
+ private readU64LE(data: Uint8Array, offset: number): bigint {
1076
+ let value = 0n;
1077
+ for (let i = 0; i < 8; i++) {
1078
+ value |= BigInt(data[offset + i]) << BigInt(8 * i);
1079
+ }
1080
+ return value;
1081
+ }
1082
+
1083
+ private ceilDiv(a: bigint, b: bigint): bigint {
1084
+ return (a + b - 1n) / b;
1085
+ }
1086
+
950
1087
  /**
951
1088
  * Get token metadata for an SPL mint.
952
1089
  *