@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 +2 -1
- package/dist/evm/evm.js +10 -0
- package/dist/svm/svm.d.ts +6 -0
- package/dist/svm/svm.js +103 -0
- package/package.json +1 -1
- package/utils/evm/evm.ts +11 -0
- package/utils/svm/svm.ts +143 -2
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
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
|
*
|