forgex-cli 1.0.58 → 1.0.61
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/README.md +375 -368
- package/dist/bin/forgex.d.ts +5 -5
- package/dist/bin/forgex.js +14 -14
- package/dist/bin/forgex.js.map +1 -1
- package/dist/src/adapters/codex-adapter.d.ts +90 -90
- package/dist/src/adapters/codex-adapter.d.ts.map +1 -1
- package/dist/src/adapters/codex-adapter.js +76 -76
- package/dist/src/adapters/codex-adapter.js.map +1 -1
- package/dist/src/adapters/connection.d.ts +6 -6
- package/dist/src/adapters/connection.js +8 -8
- package/dist/src/adapters/connection.js.map +1 -1
- package/dist/src/adapters/ipfs.d.ts +3 -3
- package/dist/src/adapters/ipfs.js +3 -3
- package/dist/src/adapters/jito-adapter.d.ts +85 -85
- package/dist/src/adapters/jito-adapter.d.ts.map +1 -1
- package/dist/src/adapters/jito-adapter.js +111 -111
- package/dist/src/adapters/jito-adapter.js.map +1 -1
- package/dist/src/adapters/rpc-adapter.d.ts +53 -53
- package/dist/src/adapters/rpc-adapter.d.ts.map +1 -1
- package/dist/src/adapters/rpc-adapter.js +69 -69
- package/dist/src/adapters/rpc-adapter.js.map +1 -1
- package/dist/src/adapters/sdk-adapter.d.ts +21 -21
- package/dist/src/adapters/sdk-adapter.d.ts.map +1 -1
- package/dist/src/adapters/sdk-adapter.js +79 -79
- package/dist/src/adapters/sdk-adapter.js.map +1 -1
- package/dist/src/commands/config/index.d.ts +1 -1
- package/dist/src/commands/config/index.js +15 -15
- package/dist/src/commands/config/index.js.map +1 -1
- package/dist/src/commands/query/index.d.ts +2 -2
- package/dist/src/commands/query/index.js +82 -82
- package/dist/src/commands/query/index.js.map +1 -1
- package/dist/src/commands/token/index.d.ts +8 -8
- package/dist/src/commands/token/index.js +73 -73
- package/dist/src/commands/token/index.js.map +1 -1
- package/dist/src/commands/tools/index.d.ts +9 -9
- package/dist/src/commands/tools/index.js +137 -137
- package/dist/src/commands/tools/index.js.map +1 -1
- package/dist/src/commands/trade/index.d.ts +2 -2
- package/dist/src/commands/trade/index.js +82 -82
- package/dist/src/commands/trade/index.js.map +1 -1
- package/dist/src/commands/transfer/index.d.ts +8 -8
- package/dist/src/commands/transfer/index.js +106 -106
- package/dist/src/commands/transfer/index.js.map +1 -1
- package/dist/src/commands/wallet/index.d.ts +1 -1
- package/dist/src/commands/wallet/index.js +175 -175
- package/dist/src/commands/wallet/index.js.map +1 -1
- package/dist/src/config.d.ts +26 -26
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +28 -28
- package/dist/src/config.js.map +1 -1
- package/dist/src/const/index.js +1 -1
- package/dist/src/const/index.js.map +1 -1
- package/dist/src/data-source.d.ts +81 -81
- package/dist/src/data-source.d.ts.map +1 -1
- package/dist/src/data-source.js +149 -149
- package/dist/src/data-source.js.map +1 -1
- package/dist/src/data-store/index.d.ts +22 -22
- package/dist/src/data-store/index.d.ts.map +1 -1
- package/dist/src/data-store/index.js +46 -46
- package/dist/src/data-store/index.js.map +1 -1
- package/dist/src/data-store/types.d.ts +3 -3
- package/dist/src/data-store/types.js +3 -3
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +10 -10
- package/dist/src/index.js.map +1 -1
- package/dist/src/output.d.ts +18 -18
- package/dist/src/output.d.ts.map +1 -1
- package/dist/src/output.js +34 -34
- package/dist/src/output.js.map +1 -1
- package/dist/src/shims/store.d.ts +3 -2
- package/dist/src/shims/store.d.ts.map +1 -1
- package/dist/src/shims/store.js +6 -5
- package/dist/src/shims/store.js.map +1 -1
- package/dist/src/sol-sdk/batch/create.d.ts +4 -1
- package/dist/src/sol-sdk/batch/create.d.ts.map +1 -1
- package/dist/src/sol-sdk/batch/create.js +44 -44
- package/dist/src/sol-sdk/batch/create.js.map +1 -1
- package/dist/src/sol-sdk/batch/index.js +135 -135
- package/dist/src/sol-sdk/batch/index.js.map +1 -1
- package/dist/src/sol-sdk/calc.d.ts +63 -63
- package/dist/src/sol-sdk/calc.d.ts.map +1 -1
- package/dist/src/sol-sdk/calc.js +120 -120
- package/dist/src/sol-sdk/calc.js.map +1 -1
- package/dist/src/sol-sdk/jito/index.js +12 -12
- package/dist/src/sol-sdk/jito/index.js.map +1 -1
- package/dist/src/sol-sdk/launchlab/instructions/create.js +10 -10
- package/dist/src/sol-sdk/launchlab/instructions/create.js.map +1 -1
- package/dist/src/sol-sdk/meteora/index.d.ts +5 -5
- package/dist/src/sol-sdk/meteora/index.js +11 -11
- package/dist/src/sol-sdk/meteora/index.js.map +1 -1
- package/dist/src/sol-sdk/meteora/instructions/buy.js +8 -8
- package/dist/src/sol-sdk/meteora/instructions/buy.js.map +1 -1
- package/dist/src/sol-sdk/meteora/instructions/sell.js +6 -6
- package/dist/src/sol-sdk/meteora/instructions/sell.js.map +1 -1
- package/dist/src/sol-sdk/pump/index.js +3 -3
- package/dist/src/sol-sdk/pump/index.js.map +1 -1
- package/dist/src/sol-sdk/pump/instructions/buy.d.ts +12 -12
- package/dist/src/sol-sdk/pump/instructions/buy.d.ts.map +1 -1
- package/dist/src/sol-sdk/pump/instructions/buy.js +26 -26
- package/dist/src/sol-sdk/pump/instructions/buy.js.map +1 -1
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts +13 -13
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.js +17 -17
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.js.map +1 -1
- package/dist/src/sol-sdk/pump/instructions/sell.d.ts +2 -2
- package/dist/src/sol-sdk/pump/instructions/sell.d.ts.map +1 -1
- package/dist/src/sol-sdk/pump/instructions/sell.js +7 -7
- package/dist/src/sol-sdk/pump/instructions/sell.js.map +1 -1
- package/dist/src/sol-sdk/pumpswap/index.d.ts +4 -4
- package/dist/src/sol-sdk/pumpswap/index.js +5 -5
- package/dist/src/sol-sdk/pumpswap/index.js.map +1 -1
- package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts +8 -8
- package/dist/src/sol-sdk/pumpswap/instructions/buy.js +19 -19
- package/dist/src/sol-sdk/pumpswap/instructions/buy.js.map +1 -1
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.js +2 -2
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.js.map +1 -1
- package/dist/src/sol-sdk/pumpswap/instructions/sell.js +4 -4
- package/dist/src/sol-sdk/pumpswap/instructions/sell.js.map +1 -1
- package/dist/src/sol-sdk/pumpswap/rpc/index.js +1 -1
- package/dist/src/sol-sdk/pumpswap/rpc/index.js.map +1 -1
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js +3 -3
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js.map +1 -1
- package/dist/src/sol-sdk/raydium/instructions/sell.d.ts +40 -8520
- package/dist/src/sol-sdk/raydium/instructions/sell.d.ts.map +1 -1
- package/dist/src/sol-sdk/raydium/instructions/sell.js +6 -6
- package/dist/src/sol-sdk/raydium/instructions/sell.js.map +1 -1
- package/dist/src/sol-sdk/raydium/rpc/index.d.ts +4 -4
- package/dist/src/sol-sdk/rpc/index.d.ts +14 -14
- package/dist/src/sol-sdk/rpc/index.d.ts.map +1 -1
- package/dist/src/sol-sdk/rpc/index.js +17 -17
- package/dist/src/sol-sdk/rpc/index.js.map +1 -1
- package/dist/src/sol-sdk/transfer/index.js +5 -5
- package/dist/src/sol-sdk/transfer/index.js.map +1 -1
- package/dist/src/sol-sdk/turnover/index.d.ts +3 -3
- package/dist/src/sol-sdk/turnover/index.js +56 -56
- package/dist/src/sol-sdk/turnover/index.js.map +1 -1
- package/dist/src/telemetry.d.ts +8 -8
- package/dist/src/telemetry.d.ts.map +1 -1
- package/dist/src/telemetry.js +28 -27
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/tx-tracker/detail-adapter.d.ts +53 -53
- package/dist/src/tx-tracker/detail-adapter.d.ts.map +1 -1
- package/dist/src/tx-tracker/detail-adapter.js +68 -68
- package/dist/src/tx-tracker/detail-adapter.js.map +1 -1
- package/dist/src/tx-tracker/index.d.ts +67 -67
- package/dist/src/tx-tracker/index.d.ts.map +1 -1
- package/dist/src/tx-tracker/index.js +103 -103
- package/dist/src/tx-tracker/index.js.map +1 -1
- package/dist/src/types/index.d.ts +10 -10
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/websocket.js +1 -1
- package/dist/src/types/websocket.js.map +1 -1
- package/dist/src/utils/index.js +20 -20
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/wallet-store.d.ts +51 -51
- package/dist/src/wallet-store.d.ts.map +1 -1
- package/dist/src/wallet-store.js +104 -104
- package/dist/src/wallet-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ForgeX CLI RPC
|
|
2
|
+
* ForgeX CLI RPC Data Fetch Layer
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Provides on-chain data queries: balance, account info, transaction confirmation, etc.
|
|
5
|
+
* Reuses sol-sdk/rpc/ infrastructure with multi-endpoint fault tolerance and retry mechanism.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Design reference: ARCH-DESIGN-v2.md Section 2.4
|
|
8
8
|
*/
|
|
9
9
|
import { ParsedTransactionWithMeta, AccountInfo } from '@solana/web3.js';
|
|
10
|
-
/**
|
|
10
|
+
/** Single Token account info */
|
|
11
11
|
export interface TokenAccountInfo {
|
|
12
|
-
/** Token mint
|
|
12
|
+
/** Token mint address */
|
|
13
13
|
mint: string;
|
|
14
|
-
/**
|
|
14
|
+
/** Owner wallet address */
|
|
15
15
|
owner: string;
|
|
16
|
-
/** UI
|
|
16
|
+
/** UI-readable balance (divided by decimals) */
|
|
17
17
|
uiAmount: number;
|
|
18
|
-
/**
|
|
18
|
+
/** Raw balance (lamports/minimum unit) */
|
|
19
19
|
amount: string;
|
|
20
|
-
/** Token
|
|
20
|
+
/** Token decimals */
|
|
21
21
|
decimals: number;
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
23
|
+
/** Transaction status */
|
|
24
24
|
export type TransactionStatus = 'confirmed' | 'finalized' | 'failed' | 'not_found';
|
|
25
|
-
/**
|
|
25
|
+
/** Parsed transaction detail */
|
|
26
26
|
export interface ParsedTransactionDetail {
|
|
27
|
-
/**
|
|
27
|
+
/** Transaction signature */
|
|
28
28
|
txHash: string;
|
|
29
|
-
/** Slot
|
|
29
|
+
/** Slot height */
|
|
30
30
|
slot: number;
|
|
31
|
-
/**
|
|
31
|
+
/** Block time (Unix seconds) */
|
|
32
32
|
blockTime: number | null;
|
|
33
|
-
/**
|
|
33
|
+
/** Transaction fee (lamports) */
|
|
34
34
|
fee: number;
|
|
35
|
-
/**
|
|
35
|
+
/** Whether transaction failed */
|
|
36
36
|
err: any;
|
|
37
|
-
/**
|
|
37
|
+
/** Pre-transaction SOL balances array (lamports) */
|
|
38
38
|
preBalances: number[];
|
|
39
|
-
/**
|
|
39
|
+
/** Post-transaction SOL balances array (lamports) */
|
|
40
40
|
postBalances: number[];
|
|
41
|
-
/**
|
|
41
|
+
/** Pre-transaction Token balances array */
|
|
42
42
|
preTokenBalances: any[];
|
|
43
|
-
/**
|
|
43
|
+
/** Post-transaction Token balances array */
|
|
44
44
|
postTokenBalances: any[];
|
|
45
|
-
/**
|
|
45
|
+
/** Account address list */
|
|
46
46
|
accountKeys: string[];
|
|
47
|
-
/**
|
|
47
|
+
/** Raw ParsedTransactionWithMeta (for TxDetailAdapter use) */
|
|
48
48
|
raw: ParsedTransactionWithMeta;
|
|
49
49
|
}
|
|
50
50
|
export declare class RpcAdapter {
|
|
@@ -56,78 +56,78 @@ export declare class RpcAdapter {
|
|
|
56
56
|
endpoints?: string[];
|
|
57
57
|
maxRetries?: number;
|
|
58
58
|
});
|
|
59
|
-
/**
|
|
59
|
+
/** Get Connection for current active endpoint */
|
|
60
60
|
private getConnection;
|
|
61
|
-
/**
|
|
61
|
+
/** Switch to next endpoint */
|
|
62
62
|
private switchEndpoint;
|
|
63
|
-
/**
|
|
63
|
+
/** Get current endpoint URL (for debugging) */
|
|
64
64
|
getCurrentEndpoint(): string;
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
* 1.
|
|
68
|
-
* 2.
|
|
69
|
-
* 3.
|
|
66
|
+
* Executor with exponential backoff retry + endpoint rotation
|
|
67
|
+
* 1. Retry maxRetries times on current endpoint (exponential backoff)
|
|
68
|
+
* 2. If current endpoint fails all retries, switch to next endpoint
|
|
69
|
+
* 3. Throw last error after all endpoints fail
|
|
70
70
|
*/
|
|
71
71
|
private executeWithRetry;
|
|
72
|
-
/**
|
|
72
|
+
/** Check if error is retryable */
|
|
73
73
|
private isRetryableError;
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
76
|
-
* @returns SOL
|
|
75
|
+
* Get single wallet SOL balance
|
|
76
|
+
* @returns SOL balance (UI units, e.g. 1.5 SOL)
|
|
77
77
|
*/
|
|
78
78
|
getSolBalance(address: string): Promise<number>;
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* @returns Record
|
|
80
|
+
* Batch get SOL balances for multiple wallets
|
|
81
|
+
* Uses getMultipleAccountsInfo for batch queries, reducing RPC call count
|
|
82
|
+
* @returns Record<address, SOL balance>
|
|
83
83
|
*/
|
|
84
84
|
getBatchSolBalances(addresses: string[]): Promise<Record<string, number>>;
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
87
|
-
* @returns Token
|
|
86
|
+
* Get single token balance for a wallet
|
|
87
|
+
* @returns Token balance (UI units)
|
|
88
88
|
*/
|
|
89
89
|
getTokenBalance(walletAddress: string, tokenMint: string): Promise<number>;
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
91
|
+
* Get all token accounts for a wallet
|
|
92
|
+
* Queries directly via RPC, replacing forgex.online/api getTokenListFromAddress
|
|
93
93
|
*/
|
|
94
94
|
getTokenAccountsByOwner(walletAddress: string): Promise<TokenAccountInfo[]>;
|
|
95
95
|
/**
|
|
96
|
-
*
|
|
97
|
-
* @returns Record
|
|
96
|
+
* Batch get token balances for multiple wallets on a specific token
|
|
97
|
+
* @returns Record<wallet address, Token balance>
|
|
98
98
|
*/
|
|
99
99
|
getBatchTokenBalances(walletAddresses: string[], tokenMint: string): Promise<Record<string, number>>;
|
|
100
100
|
/**
|
|
101
|
-
*
|
|
101
|
+
* Query confirmation status of a single transaction
|
|
102
102
|
*/
|
|
103
103
|
getTransactionStatus(txHash: string): Promise<TransactionStatus>;
|
|
104
104
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
105
|
+
* Get transaction details
|
|
106
|
+
* Returns parsed transaction data including balance changes, token changes, etc.
|
|
107
107
|
*/
|
|
108
108
|
getTransactionDetail(txHash: string): Promise<ParsedTransactionDetail | null>;
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
110
|
+
* Batch query transaction statuses
|
|
111
111
|
* @returns Record<txHash, TransactionStatus>
|
|
112
112
|
*/
|
|
113
113
|
getBatchTransactionStatuses(txHashes: string[]): Promise<Record<string, TransactionStatus>>;
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
115
|
+
* Get account info (raw)
|
|
116
116
|
*/
|
|
117
117
|
getAccountInfo(address: string): Promise<AccountInfo<Buffer> | null>;
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* Get latest blockhash
|
|
120
120
|
*/
|
|
121
121
|
getLatestBlockhash(): Promise<{
|
|
122
122
|
blockhash: string;
|
|
123
123
|
lastValidBlockHeight: number;
|
|
124
124
|
}>;
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
126
|
+
* Get current slot
|
|
127
127
|
*/
|
|
128
128
|
getSlot(): Promise<number>;
|
|
129
129
|
/**
|
|
130
|
-
*
|
|
130
|
+
* Health check: verify current endpoint availability
|
|
131
131
|
*/
|
|
132
132
|
healthCheck(): Promise<{
|
|
133
133
|
healthy: boolean;
|
|
@@ -137,12 +137,12 @@ export declare class RpcAdapter {
|
|
|
137
137
|
}>;
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
140
|
+
* Get RpcAdapter singleton
|
|
141
|
+
* Creates instance from config RPC settings on first call
|
|
142
142
|
*/
|
|
143
143
|
export declare function getRpcAdapter(): RpcAdapter;
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
145
|
+
* Reset singleton (for re-initialization after config changes)
|
|
146
146
|
*/
|
|
147
147
|
export declare function resetRpcAdapter(): void;
|
|
148
148
|
//# sourceMappingURL=rpc-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/rpc-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAIL,yBAAyB,EAEzB,WAAW,EACZ,MAAM,iBAAiB,CAAC;AASzB,
|
|
1
|
+
{"version":3,"file":"rpc-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/rpc-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ForgeX CLI RPC
|
|
2
|
+
* ForgeX CLI RPC Data Fetch Layer
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Provides on-chain data queries: balance, account info, transaction confirmation, etc.
|
|
5
|
+
* Reuses sol-sdk/rpc/ infrastructure with multi-endpoint fault tolerance and retry mechanism.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Design reference: ARCH-DESIGN-v2.md Section 2.4
|
|
8
8
|
*/
|
|
9
9
|
import { Connection, PublicKey, LAMPORTS_PER_SOL, } from '@solana/web3.js';
|
|
10
10
|
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
11
11
|
import BigNumber from 'bignumber.js';
|
|
12
12
|
import { loadConfig } from '../config.js';
|
|
13
13
|
// ============================================================
|
|
14
|
-
//
|
|
14
|
+
// Constants
|
|
15
15
|
// ============================================================
|
|
16
|
-
/**
|
|
16
|
+
/** Default retry count */
|
|
17
17
|
const DEFAULT_MAX_RETRIES = 3;
|
|
18
|
-
/**
|
|
18
|
+
/** Initial retry delay (ms) */
|
|
19
19
|
const INITIAL_RETRY_DELAY_MS = 500;
|
|
20
|
-
/**
|
|
20
|
+
/** Batch query chunk size (getMultipleAccountsInfo limit 100) */
|
|
21
21
|
const BATCH_CHUNK_SIZE = 100;
|
|
22
22
|
// ============================================================
|
|
23
|
-
// RpcAdapter
|
|
23
|
+
// RpcAdapter Implementation
|
|
24
24
|
// ============================================================
|
|
25
25
|
export class RpcAdapter {
|
|
26
26
|
endpoints;
|
|
@@ -29,19 +29,19 @@ export class RpcAdapter {
|
|
|
29
29
|
maxRetries;
|
|
30
30
|
constructor(options) {
|
|
31
31
|
const config = loadConfig();
|
|
32
|
-
//
|
|
32
|
+
// Build endpoint list: primary endpoint + optional fallback endpoints
|
|
33
33
|
this.endpoints = [];
|
|
34
34
|
if (options?.endpoints && options.endpoints.length > 0) {
|
|
35
35
|
this.endpoints = [...options.endpoints];
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
|
-
//
|
|
38
|
+
// Read primary endpoint from config
|
|
39
39
|
if (config.rpcUrl) {
|
|
40
40
|
this.endpoints.push(config.rpcUrl);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
if (this.endpoints.length === 0) {
|
|
44
|
-
//
|
|
44
|
+
// Fallback: Solana public endpoint
|
|
45
45
|
this.endpoints.push('https://api.mainnet-beta.solana.com');
|
|
46
46
|
}
|
|
47
47
|
this.currentEndpointIndex = 0;
|
|
@@ -49,9 +49,9 @@ export class RpcAdapter {
|
|
|
49
49
|
this.maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
50
50
|
}
|
|
51
51
|
// ============================================================
|
|
52
|
-
//
|
|
52
|
+
// Connection Management
|
|
53
53
|
// ============================================================
|
|
54
|
-
/**
|
|
54
|
+
/** Get Connection for current active endpoint */
|
|
55
55
|
getConnection(commitment = 'processed') {
|
|
56
56
|
const url = this.endpoints[this.currentEndpointIndex];
|
|
57
57
|
const key = `${url}_${commitment}`;
|
|
@@ -60,27 +60,27 @@ export class RpcAdapter {
|
|
|
60
60
|
}
|
|
61
61
|
return this.connections.get(key);
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
63
|
+
/** Switch to next endpoint */
|
|
64
64
|
switchEndpoint() {
|
|
65
65
|
if (this.endpoints.length <= 1)
|
|
66
66
|
return false;
|
|
67
67
|
const oldIndex = this.currentEndpointIndex;
|
|
68
68
|
this.currentEndpointIndex = (this.currentEndpointIndex + 1) % this.endpoints.length;
|
|
69
|
-
//
|
|
69
|
+
// If cycled back to start, all endpoints have been tried
|
|
70
70
|
return this.currentEndpointIndex !== oldIndex;
|
|
71
71
|
}
|
|
72
|
-
/**
|
|
72
|
+
/** Get current endpoint URL (for debugging) */
|
|
73
73
|
getCurrentEndpoint() {
|
|
74
74
|
return this.endpoints[this.currentEndpointIndex];
|
|
75
75
|
}
|
|
76
76
|
// ============================================================
|
|
77
|
-
//
|
|
77
|
+
// Retry and Fault Tolerance
|
|
78
78
|
// ============================================================
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
81
|
-
* 1.
|
|
82
|
-
* 2.
|
|
83
|
-
* 3.
|
|
80
|
+
* Executor with exponential backoff retry + endpoint rotation
|
|
81
|
+
* 1. Retry maxRetries times on current endpoint (exponential backoff)
|
|
82
|
+
* 2. If current endpoint fails all retries, switch to next endpoint
|
|
83
|
+
* 3. Throw last error after all endpoints fail
|
|
84
84
|
*/
|
|
85
85
|
async executeWithRetry(operation, operationName) {
|
|
86
86
|
const triedEndpoints = new Set();
|
|
@@ -94,56 +94,56 @@ export class RpcAdapter {
|
|
|
94
94
|
}
|
|
95
95
|
catch (err) {
|
|
96
96
|
lastError = err;
|
|
97
|
-
//
|
|
97
|
+
// Check if error is retryable
|
|
98
98
|
const isRetryable = this.isRetryableError(err);
|
|
99
99
|
if (!isRetryable) {
|
|
100
|
-
throw err; //
|
|
100
|
+
throw err; // Non-retryable errors throw immediately (e.g. invalid params)
|
|
101
101
|
}
|
|
102
|
-
//
|
|
102
|
+
// Exponential backoff wait
|
|
103
103
|
if (attempt < this.maxRetries - 1) {
|
|
104
104
|
const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt);
|
|
105
105
|
await sleep(delay);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
//
|
|
109
|
+
// All retries failed on current endpoint, try switching
|
|
110
110
|
const switched = this.switchEndpoint();
|
|
111
111
|
if (!switched)
|
|
112
112
|
break;
|
|
113
113
|
}
|
|
114
|
-
throw lastError || new Error(`${operationName}:
|
|
114
|
+
throw lastError || new Error(`${operationName}: All RPC endpoints unavailable`);
|
|
115
115
|
}
|
|
116
|
-
/**
|
|
116
|
+
/** Check if error is retryable */
|
|
117
117
|
isRetryableError(err) {
|
|
118
118
|
const message = (err?.message || '').toLowerCase();
|
|
119
|
-
//
|
|
119
|
+
// Network error
|
|
120
120
|
if (message.includes('fetch failed') || message.includes('econnrefused') || message.includes('econnreset')) {
|
|
121
121
|
return true;
|
|
122
122
|
}
|
|
123
|
-
//
|
|
123
|
+
// Rate limit
|
|
124
124
|
if (message.includes('429') || message.includes('rate limit') || message.includes('too many requests')) {
|
|
125
125
|
return true;
|
|
126
126
|
}
|
|
127
|
-
//
|
|
127
|
+
// Server error
|
|
128
128
|
if (message.includes('503') || message.includes('502') || message.includes('500')) {
|
|
129
129
|
return true;
|
|
130
130
|
}
|
|
131
|
-
// RPC
|
|
131
|
+
// RPC timeout
|
|
132
132
|
if (message.includes('timeout') || message.includes('timed out')) {
|
|
133
133
|
return true;
|
|
134
134
|
}
|
|
135
|
-
// Solana RPC
|
|
135
|
+
// Solana RPC specific transient errors
|
|
136
136
|
if (message.includes('blockhash not found') || message.includes('slot skipped')) {
|
|
137
137
|
return true;
|
|
138
138
|
}
|
|
139
139
|
return false;
|
|
140
140
|
}
|
|
141
141
|
// ============================================================
|
|
142
|
-
// SOL
|
|
142
|
+
// SOL Balance Queries
|
|
143
143
|
// ============================================================
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
146
|
-
* @returns SOL
|
|
145
|
+
* Get single wallet SOL balance
|
|
146
|
+
* @returns SOL balance (UI units, e.g. 1.5 SOL)
|
|
147
147
|
*/
|
|
148
148
|
async getSolBalance(address) {
|
|
149
149
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -153,15 +153,15 @@ export class RpcAdapter {
|
|
|
153
153
|
}, 'getSolBalance');
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* @returns Record
|
|
156
|
+
* Batch get SOL balances for multiple wallets
|
|
157
|
+
* Uses getMultipleAccountsInfo for batch queries, reducing RPC call count
|
|
158
|
+
* @returns Record<address, SOL balance>
|
|
159
159
|
*/
|
|
160
160
|
async getBatchSolBalances(addresses) {
|
|
161
161
|
if (addresses.length === 0)
|
|
162
162
|
return {};
|
|
163
163
|
const result = {};
|
|
164
|
-
//
|
|
164
|
+
// Batch query (getMultipleAccountsInfo limit 100 accounts)
|
|
165
165
|
for (let i = 0; i < addresses.length; i += BATCH_CHUNK_SIZE) {
|
|
166
166
|
const chunk = addresses.slice(i, i + BATCH_CHUNK_SIZE);
|
|
167
167
|
const pubkeys = chunk.map(addr => new PublicKey(addr));
|
|
@@ -178,11 +178,11 @@ export class RpcAdapter {
|
|
|
178
178
|
return result;
|
|
179
179
|
}
|
|
180
180
|
// ============================================================
|
|
181
|
-
// SPL Token
|
|
181
|
+
// SPL Token Queries
|
|
182
182
|
// ============================================================
|
|
183
183
|
/**
|
|
184
|
-
*
|
|
185
|
-
* @returns Token
|
|
184
|
+
* Get single token balance for a wallet
|
|
185
|
+
* @returns Token balance (UI units)
|
|
186
186
|
*/
|
|
187
187
|
async getTokenBalance(walletAddress, tokenMint) {
|
|
188
188
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -190,7 +190,7 @@ export class RpcAdapter {
|
|
|
190
190
|
const { getAssociatedTokenAddress, TOKEN_2022_PROGRAM_ID } = await import('@solana/spl-token');
|
|
191
191
|
const mintPubkey = new PublicKey(tokenMint);
|
|
192
192
|
const ownerPubkey = new PublicKey(walletAddress);
|
|
193
|
-
//
|
|
193
|
+
// First try standard TOKEN_PROGRAM_ID
|
|
194
194
|
try {
|
|
195
195
|
const ataAddress = await getAssociatedTokenAddress(mintPubkey, ownerPubkey);
|
|
196
196
|
const balanceResp = await connection.getTokenAccountBalance(ataAddress);
|
|
@@ -199,9 +199,9 @@ export class RpcAdapter {
|
|
|
199
199
|
return balance;
|
|
200
200
|
}
|
|
201
201
|
catch {
|
|
202
|
-
//
|
|
202
|
+
// Standard ATA does not exist, try Token-2022
|
|
203
203
|
}
|
|
204
|
-
//
|
|
204
|
+
// Try TOKEN_2022_PROGRAM_ID (used by Pump.fun etc.)
|
|
205
205
|
try {
|
|
206
206
|
const ata2022 = await getAssociatedTokenAddress(mintPubkey, ownerPubkey, false, TOKEN_2022_PROGRAM_ID);
|
|
207
207
|
const balanceResp = await connection.getTokenAccountBalance(ata2022);
|
|
@@ -212,14 +212,14 @@ export class RpcAdapter {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
catch {
|
|
215
|
-
// ATA
|
|
215
|
+
// ATA does not exist = balance is 0
|
|
216
216
|
return 0;
|
|
217
217
|
}
|
|
218
218
|
}, 'getTokenBalance');
|
|
219
219
|
}
|
|
220
220
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
221
|
+
* Get all token accounts for a wallet
|
|
222
|
+
* Queries directly via RPC, replacing forgex.online/api getTokenListFromAddress
|
|
223
223
|
*/
|
|
224
224
|
async getTokenAccountsByOwner(walletAddress) {
|
|
225
225
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -245,14 +245,14 @@ export class RpcAdapter {
|
|
|
245
245
|
}, 'getTokenAccountsByOwner');
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
|
-
*
|
|
249
|
-
* @returns Record
|
|
248
|
+
* Batch get token balances for multiple wallets on a specific token
|
|
249
|
+
* @returns Record<wallet address, Token balance>
|
|
250
250
|
*/
|
|
251
251
|
async getBatchTokenBalances(walletAddresses, tokenMint) {
|
|
252
252
|
if (walletAddresses.length === 0)
|
|
253
253
|
return {};
|
|
254
254
|
const result = {};
|
|
255
|
-
//
|
|
255
|
+
// Concurrent queries with rate limiting (max 10 concurrent per batch)
|
|
256
256
|
const CONCURRENCY = 10;
|
|
257
257
|
for (let i = 0; i < walletAddresses.length; i += CONCURRENCY) {
|
|
258
258
|
const batch = walletAddresses.slice(i, i + CONCURRENCY);
|
|
@@ -272,10 +272,10 @@ export class RpcAdapter {
|
|
|
272
272
|
return result;
|
|
273
273
|
}
|
|
274
274
|
// ============================================================
|
|
275
|
-
//
|
|
275
|
+
// Transaction Status Queries
|
|
276
276
|
// ============================================================
|
|
277
277
|
/**
|
|
278
|
-
*
|
|
278
|
+
* Query confirmation status of a single transaction
|
|
279
279
|
*/
|
|
280
280
|
async getTransactionStatus(txHash) {
|
|
281
281
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -297,8 +297,8 @@ export class RpcAdapter {
|
|
|
297
297
|
}, 'getTransactionStatus');
|
|
298
298
|
}
|
|
299
299
|
/**
|
|
300
|
-
*
|
|
301
|
-
*
|
|
300
|
+
* Get transaction details
|
|
301
|
+
* Returns parsed transaction data including balance changes, token changes, etc.
|
|
302
302
|
*/
|
|
303
303
|
async getTransactionDetail(txHash) {
|
|
304
304
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -309,7 +309,7 @@ export class RpcAdapter {
|
|
|
309
309
|
if (!tx || !tx.meta) {
|
|
310
310
|
return null;
|
|
311
311
|
}
|
|
312
|
-
//
|
|
312
|
+
// Extract accountKeys
|
|
313
313
|
const accountKeys = tx.transaction.message.accountKeys.map((key) => typeof key === 'string' ? key : key.pubkey.toBase58());
|
|
314
314
|
return {
|
|
315
315
|
txHash,
|
|
@@ -327,14 +327,14 @@ export class RpcAdapter {
|
|
|
327
327
|
}, 'getTransactionDetail');
|
|
328
328
|
}
|
|
329
329
|
/**
|
|
330
|
-
*
|
|
330
|
+
* Batch query transaction statuses
|
|
331
331
|
* @returns Record<txHash, TransactionStatus>
|
|
332
332
|
*/
|
|
333
333
|
async getBatchTransactionStatuses(txHashes) {
|
|
334
334
|
if (txHashes.length === 0)
|
|
335
335
|
return {};
|
|
336
336
|
const result = {};
|
|
337
|
-
// getSignatureStatuses
|
|
337
|
+
// getSignatureStatuses supports max 256 signatures per call
|
|
338
338
|
const SIGNATURE_BATCH_SIZE = 256;
|
|
339
339
|
for (let i = 0; i < txHashes.length; i += SIGNATURE_BATCH_SIZE) {
|
|
340
340
|
const batch = txHashes.slice(i, i + SIGNATURE_BATCH_SIZE);
|
|
@@ -360,10 +360,10 @@ export class RpcAdapter {
|
|
|
360
360
|
return result;
|
|
361
361
|
}
|
|
362
362
|
// ============================================================
|
|
363
|
-
//
|
|
363
|
+
// General RPC Queries
|
|
364
364
|
// ============================================================
|
|
365
365
|
/**
|
|
366
|
-
*
|
|
366
|
+
* Get account info (raw)
|
|
367
367
|
*/
|
|
368
368
|
async getAccountInfo(address) {
|
|
369
369
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -371,7 +371,7 @@ export class RpcAdapter {
|
|
|
371
371
|
}, 'getAccountInfo');
|
|
372
372
|
}
|
|
373
373
|
/**
|
|
374
|
-
*
|
|
374
|
+
* Get latest blockhash
|
|
375
375
|
*/
|
|
376
376
|
async getLatestBlockhash() {
|
|
377
377
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -379,7 +379,7 @@ export class RpcAdapter {
|
|
|
379
379
|
}, 'getLatestBlockhash');
|
|
380
380
|
}
|
|
381
381
|
/**
|
|
382
|
-
*
|
|
382
|
+
* Get current slot
|
|
383
383
|
*/
|
|
384
384
|
async getSlot() {
|
|
385
385
|
return this.executeWithRetry(async (connection) => {
|
|
@@ -387,7 +387,7 @@ export class RpcAdapter {
|
|
|
387
387
|
}, 'getSlot');
|
|
388
388
|
}
|
|
389
389
|
/**
|
|
390
|
-
*
|
|
390
|
+
* Health check: verify current endpoint availability
|
|
391
391
|
*/
|
|
392
392
|
async healthCheck() {
|
|
393
393
|
const endpoint = this.getCurrentEndpoint();
|
|
@@ -401,12 +401,12 @@ export class RpcAdapter {
|
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
// ============================================================
|
|
404
|
-
//
|
|
404
|
+
// Singleton Management
|
|
405
405
|
// ============================================================
|
|
406
406
|
let _instance = null;
|
|
407
407
|
/**
|
|
408
|
-
*
|
|
409
|
-
*
|
|
408
|
+
* Get RpcAdapter singleton
|
|
409
|
+
* Creates instance from config RPC settings on first call
|
|
410
410
|
*/
|
|
411
411
|
export function getRpcAdapter() {
|
|
412
412
|
if (!_instance) {
|
|
@@ -415,13 +415,13 @@ export function getRpcAdapter() {
|
|
|
415
415
|
return _instance;
|
|
416
416
|
}
|
|
417
417
|
/**
|
|
418
|
-
*
|
|
418
|
+
* Reset singleton (for re-initialization after config changes)
|
|
419
419
|
*/
|
|
420
420
|
export function resetRpcAdapter() {
|
|
421
421
|
_instance = null;
|
|
422
422
|
}
|
|
423
423
|
// ============================================================
|
|
424
|
-
//
|
|
424
|
+
// Utility Functions
|
|
425
425
|
// ============================================================
|
|
426
426
|
function sleep(ms) {
|
|
427
427
|
return new Promise((resolve) => setTimeout(resolve, ms));
|