@deserialize/multi-vm-wallet 1.5.33 → 1.5.35

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
@@ -20,6 +20,7 @@ export declare class SVMVM extends VM<PublicKey, Keypair, Connection> {
20
20
  constructor(seed: string);
21
21
  static getNativeBalance(address: PublicKey, connection: Connection): Promise<Balance>;
22
22
  static getTokenBalance(address: PublicKey, tokenAddress: PublicKey, connection: Connection): Promise<Balance>;
23
+ static generateMnemonicFromPrivateKey(privateKey: Keypair): string;
23
24
  static signAndSendTransaction: (transaction: VersionedTransaction | Transaction, connection: Connection, signers: Keypair, options?: {
24
25
  partialSign?: boolean;
25
26
  feePayerSigner?: Keypair;
@@ -66,6 +67,11 @@ export declare class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Conn
66
67
  sendTransaction(transaction: VersionedTransaction | Transaction): Promise<string>;
67
68
  signAndSendTransaction(transaction: VersionedTransaction | Transaction): Promise<string>;
68
69
  getTransactionHistory(): Promise<SVMTransactionHistoryItem[]>;
70
+ estimateGas(transaction: VersionedTransaction | Transaction): Promise<number>;
71
+ private extractComputeBudgetDetails;
72
+ private readU32LE;
73
+ private readU64LE;
74
+ private ceilDiv;
69
75
  getTokenInfo(tokenAddress: PublicKey): Promise<TokenInfo>;
70
76
  getPrices(tokenAddresses: string[]): Promise<PriceResponse>;
71
77
  swap(fromToken: TokenInfo, toToken: PublicKey, amount: number, slippage?: number): Promise<TransactionResult>;
package/dist/svm/svm.js CHANGED
@@ -75,6 +75,9 @@ class SVMVM extends vm_1.VM {
75
75
  }
76
76
  return { balance: new bn_js_1.default(balance.amount), formatted: balance.uiAmount || parseInt(balance.amount) / 10 ** balance.decimals, decimal: balance.decimals };
77
77
  }
78
+ static generateMnemonicFromPrivateKey(privateKey) {
79
+ return (0, walletBip32_1.EntropyToMnemonic)(bs58_1.default.encode(privateKey.secretKey));
80
+ }
78
81
  static signAndSendTransaction = utils_1.signAndSendTransaction;
79
82
  static signTransaction = utils_1.signTransaction;
80
83
  static sendTransaction = utils_1.sendTransaction;
@@ -438,6 +441,106 @@ class SVMChainWallet extends IChainWallet_1.ChainWallet {
438
441
  async getTransactionHistory() {
439
442
  return await (0, exports.getSvmTransactionHistoryForAddress)(this.connection, this.address);
440
443
  }
444
+ async estimateGas(transaction) {
445
+ const connection = this.connection;
446
+ if (transaction instanceof web3_js_1.Transaction) {
447
+ if (!transaction.feePayer) {
448
+ transaction.feePayer = this.address;
449
+ }
450
+ if (!transaction.recentBlockhash) {
451
+ const { blockhash } = await connection.getLatestBlockhash();
452
+ transaction.recentBlockhash = blockhash;
453
+ }
454
+ }
455
+ const message = transaction instanceof web3_js_1.Transaction
456
+ ? transaction.compileMessage()
457
+ : transaction.message;
458
+ const feeResponse = await connection.getFeeForMessage(message);
459
+ const baseFeeLamports = feeResponse.value ?? 0;
460
+ const { computeUnitPriceMicroLamports, computeUnitLimit } = this.extractComputeBudgetDetails(transaction);
461
+ if (computeUnitPriceMicroLamports === 0n) {
462
+ return baseFeeLamports;
463
+ }
464
+ let unitsConsumed;
465
+ try {
466
+ const simulation = transaction instanceof web3_js_1.Transaction
467
+ ? await connection.simulateTransaction(transaction)
468
+ : await connection.simulateTransaction(transaction, {
469
+ sigVerify: false,
470
+ replaceRecentBlockhash: true,
471
+ });
472
+ unitsConsumed = simulation.value.unitsConsumed ?? undefined;
473
+ }
474
+ catch {
475
+ }
476
+ const effectiveComputeUnits = BigInt(unitsConsumed ?? computeUnitLimit ?? 200_000);
477
+ const priorityFeeLamports = this.ceilDiv(effectiveComputeUnits * computeUnitPriceMicroLamports, 1000000n);
478
+ const totalFeeLamports = BigInt(baseFeeLamports) + priorityFeeLamports;
479
+ if (totalFeeLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
480
+ throw new Error("Estimated fee exceeds JavaScript safe integer range");
481
+ }
482
+ return Number(totalFeeLamports);
483
+ }
484
+ extractComputeBudgetDetails(transaction) {
485
+ let computeUnitPriceMicroLamports = 0n;
486
+ let computeUnitLimit;
487
+ if (transaction instanceof web3_js_1.Transaction) {
488
+ for (const instruction of transaction.instructions) {
489
+ if (!instruction.programId.equals(web3_js_1.ComputeBudgetProgram.programId)) {
490
+ continue;
491
+ }
492
+ const data = instruction.data;
493
+ if (!data || data.length === 0) {
494
+ continue;
495
+ }
496
+ const discriminator = data[0];
497
+ if (discriminator === 2 && data.length >= 5) {
498
+ computeUnitLimit = this.readU32LE(data, 1);
499
+ }
500
+ else if (discriminator === 3 && data.length >= 9) {
501
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
502
+ }
503
+ }
504
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
505
+ }
506
+ const message = transaction.message;
507
+ const compiledInstructions = message.compiledInstructions ?? [];
508
+ const staticAccountKeys = message.staticAccountKeys ?? [];
509
+ for (const instruction of compiledInstructions) {
510
+ const programId = staticAccountKeys[instruction.programIdIndex];
511
+ if (!programId || !programId.equals(web3_js_1.ComputeBudgetProgram.programId)) {
512
+ continue;
513
+ }
514
+ const data = instruction.data;
515
+ if (!data || data.length === 0) {
516
+ continue;
517
+ }
518
+ const discriminator = data[0];
519
+ if (discriminator === 2 && data.length >= 5) {
520
+ computeUnitLimit = this.readU32LE(data, 1);
521
+ }
522
+ else if (discriminator === 3 && data.length >= 9) {
523
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
524
+ }
525
+ }
526
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
527
+ }
528
+ readU32LE(data, offset) {
529
+ return (data[offset] |
530
+ (data[offset + 1] << 8) |
531
+ (data[offset + 2] << 16) |
532
+ (data[offset + 3] << 24)) >>> 0;
533
+ }
534
+ readU64LE(data, offset) {
535
+ let value = 0n;
536
+ for (let i = 0; i < 8; i++) {
537
+ value |= BigInt(data[offset + i]) << BigInt(8 * i);
538
+ }
539
+ return value;
540
+ }
541
+ ceilDiv(a, b) {
542
+ return (a + b - 1n) / b;
543
+ }
441
544
  async getTokenInfo(tokenAddress) {
442
545
  return await SVMVM.getTokenInfo(tokenAddress, this.connection);
443
546
  }
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.35",
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,5 +1,5 @@
1
- import { Connection, Keypair, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
2
- import { SVMDeriveChildPrivateKey } from "../walletBip32";
1
+ import { ComputeBudgetProgram, Connection, Keypair, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ import { EntropyToMnemonic, SVMDeriveChildPrivateKey } from "../walletBip32";
3
3
  import { VM } from "../vm";
4
4
  import { ChainAddress, ChainWallet } from "../IChainWallet";
5
5
  import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult, NFT, DiscoveredWallet, WalletDiscoveryOptions, WalletDiscoveryResult, PocketDiscoveryOptions } from "../types";
@@ -185,6 +185,10 @@ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
185
185
  }
186
186
  return { balance: new BN(balance.amount), formatted: balance.uiAmount || parseInt(balance.amount) / 10 ** balance.decimals, decimal: balance.decimals };
187
187
  }
188
+ static generateMnemonicFromPrivateKey(privateKey: Keypair): string {
189
+
190
+ return EntropyToMnemonic(base58.encode(privateKey.secretKey))
191
+ }
188
192
 
189
193
  static signAndSendTransaction = signAndSendTransaction
190
194
 
@@ -947,6 +951,143 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
947
951
  return await getSvmTransactionHistoryForAddress(this.connection!, this.address);
948
952
  }
949
953
 
954
+ //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
955
+ async estimateGas(transaction: VersionedTransaction | Transaction): Promise<number> {
956
+ const connection = this.connection!;
957
+
958
+ if (transaction instanceof Transaction) {
959
+ if (!transaction.feePayer) {
960
+ transaction.feePayer = this.address;
961
+ }
962
+
963
+ if (!transaction.recentBlockhash) {
964
+ const { blockhash } = await connection.getLatestBlockhash();
965
+ transaction.recentBlockhash = blockhash;
966
+ }
967
+ }
968
+
969
+ const message = transaction instanceof Transaction
970
+ ? transaction.compileMessage()
971
+ : transaction.message;
972
+
973
+ const feeResponse = await connection.getFeeForMessage(message);
974
+ const baseFeeLamports = feeResponse.value ?? 0;
975
+
976
+ const { computeUnitPriceMicroLamports, computeUnitLimit } =
977
+ this.extractComputeBudgetDetails(transaction);
978
+
979
+ if (computeUnitPriceMicroLamports === 0n) {
980
+ return baseFeeLamports;
981
+ }
982
+
983
+ let unitsConsumed: number | undefined;
984
+ try {
985
+ const simulation = transaction instanceof Transaction
986
+ ? await connection.simulateTransaction(transaction)
987
+ : await connection.simulateTransaction(transaction, {
988
+ sigVerify: false,
989
+ replaceRecentBlockhash: true,
990
+ });
991
+ unitsConsumed = simulation.value.unitsConsumed ?? undefined;
992
+ } catch {
993
+ // Non-fatal: fall back to declared CU limit or a conservative default.
994
+ }
995
+
996
+ const effectiveComputeUnits = BigInt(
997
+ unitsConsumed ?? computeUnitLimit ?? 200_000
998
+ );
999
+
1000
+ const priorityFeeLamports = this.ceilDiv(
1001
+ effectiveComputeUnits * computeUnitPriceMicroLamports,
1002
+ 1_000_000n
1003
+ );
1004
+
1005
+ const totalFeeLamports = BigInt(baseFeeLamports) + priorityFeeLamports;
1006
+ if (totalFeeLamports > BigInt(Number.MAX_SAFE_INTEGER)) {
1007
+ throw new Error("Estimated fee exceeds JavaScript safe integer range");
1008
+ }
1009
+
1010
+ return Number(totalFeeLamports);
1011
+ }
1012
+
1013
+ private extractComputeBudgetDetails(
1014
+ transaction: VersionedTransaction | Transaction
1015
+ ): { computeUnitPriceMicroLamports: bigint; computeUnitLimit?: number } {
1016
+ let computeUnitPriceMicroLamports = 0n;
1017
+ let computeUnitLimit: number | undefined;
1018
+
1019
+ if (transaction instanceof Transaction) {
1020
+ for (const instruction of transaction.instructions) {
1021
+ if (!instruction.programId.equals(ComputeBudgetProgram.programId)) {
1022
+ continue;
1023
+ }
1024
+
1025
+ const data = instruction.data;
1026
+ if (!data || data.length === 0) {
1027
+ continue;
1028
+ }
1029
+
1030
+ const discriminator = data[0];
1031
+ if (discriminator === 2 && data.length >= 5) {
1032
+ computeUnitLimit = this.readU32LE(data, 1);
1033
+ } else if (discriminator === 3 && data.length >= 9) {
1034
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
1035
+ }
1036
+ }
1037
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
1038
+ }
1039
+
1040
+ const message = transaction.message as {
1041
+ compiledInstructions?: Array<{ programIdIndex: number; data: Uint8Array }>;
1042
+ staticAccountKeys?: PublicKey[];
1043
+ };
1044
+
1045
+ const compiledInstructions = message.compiledInstructions ?? [];
1046
+ const staticAccountKeys = message.staticAccountKeys ?? [];
1047
+
1048
+ for (const instruction of compiledInstructions) {
1049
+ const programId = staticAccountKeys[instruction.programIdIndex];
1050
+ if (!programId || !programId.equals(ComputeBudgetProgram.programId)) {
1051
+ continue;
1052
+ }
1053
+
1054
+ const data = instruction.data;
1055
+ if (!data || data.length === 0) {
1056
+ continue;
1057
+ }
1058
+
1059
+ const discriminator = data[0];
1060
+ if (discriminator === 2 && data.length >= 5) {
1061
+ computeUnitLimit = this.readU32LE(data, 1);
1062
+ } else if (discriminator === 3 && data.length >= 9) {
1063
+ computeUnitPriceMicroLamports = this.readU64LE(data, 1);
1064
+ }
1065
+ }
1066
+
1067
+ return { computeUnitPriceMicroLamports, computeUnitLimit };
1068
+ }
1069
+
1070
+ private readU32LE(data: Uint8Array, offset: number): number {
1071
+ return (
1072
+ data[offset] |
1073
+ (data[offset + 1] << 8) |
1074
+ (data[offset + 2] << 16) |
1075
+ (data[offset + 3] << 24)
1076
+ ) >>> 0;
1077
+ }
1078
+
1079
+ private readU64LE(data: Uint8Array, offset: number): bigint {
1080
+ let value = 0n;
1081
+ for (let i = 0; i < 8; i++) {
1082
+ value |= BigInt(data[offset + i]) << BigInt(8 * i);
1083
+ }
1084
+ return value;
1085
+ }
1086
+
1087
+ private ceilDiv(a: bigint, b: bigint): bigint {
1088
+ return (a + b - 1n) / b;
1089
+ }
1090
+
950
1091
  /**
951
1092
  * Get token metadata for an SPL mint.
952
1093
  *