@deserialize/multi-vm-wallet 1.5.32 → 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/constant.js +17 -0
- package/dist/evm/evm.d.ts +2 -1
- package/dist/evm/evm.js +10 -0
- package/dist/svm/svm.d.ts +5 -0
- package/dist/svm/svm.js +100 -0
- package/package.json +1 -1
- package/utils/constant.ts +23 -0
- package/utils/evm/evm.ts +11 -0
- package/utils/svm/svm.ts +138 -1
package/dist/constant.js
CHANGED
|
@@ -19,6 +19,23 @@ exports.DefaultChains = [{
|
|
|
19
19
|
tokens: []
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
chainId: 42101,
|
|
24
|
+
name: "Push Chain Donut Testnet",
|
|
25
|
+
rpcUrl: "https://evm.donut.rpc.push.org",
|
|
26
|
+
explorerUrl: "https://donut.push.network",
|
|
27
|
+
nativeToken: {
|
|
28
|
+
name: "PC",
|
|
29
|
+
symbol: "PC",
|
|
30
|
+
decimals: 18,
|
|
31
|
+
},
|
|
32
|
+
testnet: true,
|
|
33
|
+
logoUrl: "https://push.org/assets/website/favicons/favicon.svg",
|
|
34
|
+
vmType: "EVM",
|
|
35
|
+
savings: {
|
|
36
|
+
tokens: []
|
|
37
|
+
}
|
|
38
|
+
},
|
|
22
39
|
{
|
|
23
40
|
chainId: 1,
|
|
24
41
|
name: "Ethereum",
|
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
package/utils/constant.ts
CHANGED
|
@@ -18,6 +18,29 @@ export const DefaultChains: ChainWalletConfig[] = [{
|
|
|
18
18
|
tokens: []
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
,
|
|
23
|
+
{
|
|
24
|
+
chainId: 42101,
|
|
25
|
+
name: "Push Chain Donut Testnet",
|
|
26
|
+
rpcUrl: "https://evm.donut.rpc.push.org",
|
|
27
|
+
explorerUrl: "https://donut.push.network",
|
|
28
|
+
nativeToken: {
|
|
29
|
+
name: "PC",
|
|
30
|
+
symbol: "PC",
|
|
31
|
+
decimals: 18,
|
|
32
|
+
},
|
|
33
|
+
testnet: true,
|
|
34
|
+
logoUrl: "https://push.org/assets/website/favicons/favicon.svg",
|
|
35
|
+
vmType: "EVM",
|
|
36
|
+
savings: {
|
|
37
|
+
tokens: []
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
21
44
|
, {
|
|
22
45
|
chainId: 1,
|
|
23
46
|
name: "Ethereum",
|
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
|
*
|