@solana/web3.js 0.0.0-next → 0.0.0-pr-29130
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 +24 -25
- package/lib/index.browser.cjs.js +4583 -4238
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +4565 -4238
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +7072 -3604
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +3516 -2420
- package/lib/index.esm.js +7046 -3601
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +22171 -27053
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +8 -33
- package/lib/index.iife.min.js.map +1 -1
- package/lib/index.native.js +10407 -0
- package/lib/index.native.js.map +1 -0
- package/package.json +36 -36
- package/src/__forks__/browser/fetch-impl.ts +4 -0
- package/src/__forks__/react-native/fetch-impl.ts +4 -0
- package/src/account-data.ts +39 -0
- package/src/account.ts +20 -11
- package/src/bpf-loader.ts +2 -2
- package/src/connection.ts +2303 -635
- package/src/epoch-schedule.ts +1 -1
- package/src/errors.ts +41 -0
- package/src/fee-calculator.ts +2 -0
- package/src/fetch-impl.ts +13 -0
- package/src/index.ts +3 -10
- package/src/keypair.ts +20 -25
- package/src/layout.ts +45 -4
- package/src/loader.ts +3 -3
- package/src/message/account-keys.ts +79 -0
- package/src/message/compiled-keys.ts +165 -0
- package/src/message/index.ts +47 -0
- package/src/{message.ts → message/legacy.ts} +95 -40
- package/src/message/v0.ts +496 -0
- package/src/message/versioned.ts +36 -0
- package/src/nonce-account.ts +8 -4
- package/src/programs/address-lookup-table/index.ts +435 -0
- package/src/programs/address-lookup-table/state.ts +84 -0
- package/src/programs/compute-budget.ts +281 -0
- package/src/{ed25519-program.ts → programs/ed25519.ts} +6 -6
- package/src/programs/index.ts +7 -0
- package/src/{secp256k1-program.ts → programs/secp256k1.ts} +15 -16
- package/src/{stake-program.ts → programs/stake.ts} +7 -7
- package/src/{system-program.ts → programs/system.ts} +55 -18
- package/src/{vote-program.ts → programs/vote.ts} +137 -9
- package/src/publickey.ts +37 -79
- package/src/transaction/constants.ts +12 -0
- package/src/transaction/expiry-custom-errors.ts +48 -0
- package/src/transaction/index.ts +5 -0
- package/src/{transaction.ts → transaction/legacy.ts} +162 -67
- package/src/transaction/message.ts +140 -0
- package/src/transaction/versioned.ts +126 -0
- package/src/{util → utils}/assert.ts +0 -0
- package/src/utils/bigint.ts +43 -0
- package/src/{util → utils}/borsh-schema.ts +0 -0
- package/src/{util → utils}/cluster.ts +0 -0
- package/src/utils/ed25519.ts +46 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/makeWebsocketUrl.ts +26 -0
- package/src/{util → utils}/promise-timeout.ts +0 -0
- package/src/utils/secp256k1.ts +18 -0
- package/src/utils/send-and-confirm-raw-transaction.ts +105 -0
- package/src/utils/send-and-confirm-transaction.ts +98 -0
- package/src/{util → utils}/shortvec-encoding.ts +0 -0
- package/src/{util → utils}/sleep.ts +0 -0
- package/src/{util → utils}/to-buffer.ts +0 -0
- package/src/validator-info.ts +4 -6
- package/src/vote-account.ts +1 -1
- package/src/agent-manager.ts +0 -44
- package/src/util/send-and-confirm-raw-transaction.ts +0 -46
- package/src/util/send-and-confirm-transaction.ts +0 -50
- package/src/util/url.ts +0 -18
package/src/connection.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import Agent from 'agentkeepalive';
|
|
1
2
|
import bs58 from 'bs58';
|
|
2
3
|
import {Buffer} from 'buffer';
|
|
3
|
-
import crossFetch from 'cross-fetch';
|
|
4
4
|
// @ts-ignore
|
|
5
5
|
import fastStableStringify from 'fast-stable-stringify';
|
|
6
|
+
import type {Agent as HttpAgent} from 'http';
|
|
7
|
+
import {Agent as HttpsAgent} from 'https';
|
|
6
8
|
import {
|
|
7
9
|
type as pick,
|
|
8
10
|
number,
|
|
@@ -24,22 +26,32 @@ import {
|
|
|
24
26
|
import type {Struct} from 'superstruct';
|
|
25
27
|
import {Client as RpcWebSocketClient} from 'rpc-websockets';
|
|
26
28
|
import RpcClient from 'jayson/lib/client/browser';
|
|
27
|
-
import {
|
|
29
|
+
import {JSONRPCError} from 'jayson';
|
|
28
30
|
|
|
29
|
-
import {AgentManager} from './agent-manager';
|
|
30
31
|
import {EpochSchedule} from './epoch-schedule';
|
|
31
|
-
import {SendTransactionError} from './errors';
|
|
32
|
-
import {
|
|
32
|
+
import {SendTransactionError, SolanaJSONRPCError} from './errors';
|
|
33
|
+
import fetchImpl, {Response} from './fetch-impl';
|
|
34
|
+
import {DurableNonce, NonceAccount} from './nonce-account';
|
|
33
35
|
import {PublicKey} from './publickey';
|
|
34
36
|
import {Signer} from './keypair';
|
|
35
37
|
import {MS_PER_SLOT} from './timing';
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
Transaction,
|
|
40
|
+
TransactionStatus,
|
|
41
|
+
TransactionVersion,
|
|
42
|
+
VersionedTransaction,
|
|
43
|
+
} from './transaction';
|
|
44
|
+
import {Message, MessageHeader, MessageV0, VersionedMessage} from './message';
|
|
45
|
+
import {AddressLookupTableAccount} from './programs/address-lookup-table/state';
|
|
46
|
+
import assert from './utils/assert';
|
|
47
|
+
import {sleep} from './utils/sleep';
|
|
48
|
+
import {toBuffer} from './utils/to-buffer';
|
|
49
|
+
import {
|
|
50
|
+
TransactionExpiredBlockheightExceededError,
|
|
51
|
+
TransactionExpiredNonceInvalidError,
|
|
52
|
+
TransactionExpiredTimeoutError,
|
|
53
|
+
} from './transaction/expiry-custom-errors';
|
|
54
|
+
import {makeWebsocketUrl} from './utils/makeWebsocketUrl';
|
|
43
55
|
import type {Blockhash} from './blockhash';
|
|
44
56
|
import type {FeeCalculator} from './fee-calculator';
|
|
45
57
|
import type {TransactionSignature} from './transaction';
|
|
@@ -65,15 +77,32 @@ const BufferFromRawAccountData = coerce(
|
|
|
65
77
|
*/
|
|
66
78
|
export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
|
|
67
79
|
|
|
80
|
+
/**
|
|
81
|
+
* HACK.
|
|
82
|
+
* Copied from rpc-websockets/dist/lib/client.
|
|
83
|
+
* Otherwise, `yarn build` fails with:
|
|
84
|
+
* https://gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d
|
|
85
|
+
*/
|
|
86
|
+
interface IWSRequestParams {
|
|
87
|
+
[x: string]: any;
|
|
88
|
+
[x: number]: any;
|
|
89
|
+
}
|
|
90
|
+
|
|
68
91
|
type ClientSubscriptionId = number;
|
|
69
92
|
/** @internal */ type ServerSubscriptionId = number;
|
|
70
93
|
/** @internal */ type SubscriptionConfigHash = string;
|
|
71
94
|
/** @internal */ type SubscriptionDisposeFn = () => Promise<void>;
|
|
95
|
+
/** @internal */ type SubscriptionStateChangeCallback = (
|
|
96
|
+
nextState: StatefulSubscription['state'],
|
|
97
|
+
) => void;
|
|
98
|
+
/** @internal */ type SubscriptionStateChangeDisposeFn = () => void;
|
|
72
99
|
/**
|
|
73
100
|
* @internal
|
|
74
|
-
* Every subscription
|
|
101
|
+
* Every subscription contains the args used to open the subscription with
|
|
102
|
+
* the server, and a list of callers interested in notifications.
|
|
75
103
|
*/
|
|
76
104
|
type BaseSubscription<TMethod = SubscriptionConfig['method']> = Readonly<{
|
|
105
|
+
args: IWSRequestParams;
|
|
77
106
|
callbacks: Set<Extract<SubscriptionConfig, {method: TMethod}>['callback']>;
|
|
78
107
|
}>;
|
|
79
108
|
/**
|
|
@@ -114,62 +143,43 @@ type StatefulSubscription = Readonly<
|
|
|
114
143
|
}
|
|
115
144
|
>;
|
|
116
145
|
/**
|
|
117
|
-
*
|
|
146
|
+
* A type that encapsulates a subscription's RPC method
|
|
147
|
+
* names and notification (callback) signature.
|
|
118
148
|
*/
|
|
119
149
|
type SubscriptionConfig = Readonly<
|
|
120
150
|
| {
|
|
121
151
|
callback: AccountChangeCallback;
|
|
122
152
|
method: 'accountSubscribe';
|
|
123
|
-
params: Readonly<{
|
|
124
|
-
commitment?: Commitment; // Must default to 'finalized'
|
|
125
|
-
publicKey: string; // PublicKey of the account as a base 58 string
|
|
126
|
-
}>;
|
|
127
153
|
unsubscribeMethod: 'accountUnsubscribe';
|
|
128
154
|
}
|
|
129
155
|
| {
|
|
130
156
|
callback: LogsCallback;
|
|
131
157
|
method: 'logsSubscribe';
|
|
132
|
-
params: Readonly<{
|
|
133
|
-
commitment?: Commitment; // Must default to 'finalized'
|
|
134
|
-
filter: LogsFilter;
|
|
135
|
-
}>;
|
|
136
158
|
unsubscribeMethod: 'logsUnsubscribe';
|
|
137
159
|
}
|
|
138
160
|
| {
|
|
139
161
|
callback: ProgramAccountChangeCallback;
|
|
140
162
|
method: 'programSubscribe';
|
|
141
|
-
params: Readonly<{
|
|
142
|
-
commitment?: Commitment; // Must default to 'finalized'
|
|
143
|
-
filters?: GetProgramAccountsFilter[];
|
|
144
|
-
programId: string; // PublicKey of the program as a base 58 string
|
|
145
|
-
}>;
|
|
146
163
|
unsubscribeMethod: 'programUnsubscribe';
|
|
147
164
|
}
|
|
148
165
|
| {
|
|
149
166
|
callback: RootChangeCallback;
|
|
150
167
|
method: 'rootSubscribe';
|
|
151
|
-
params: undefined;
|
|
152
168
|
unsubscribeMethod: 'rootUnsubscribe';
|
|
153
169
|
}
|
|
154
170
|
| {
|
|
155
171
|
callback: SignatureSubscriptionCallback;
|
|
156
172
|
method: 'signatureSubscribe';
|
|
157
|
-
params: Readonly<{
|
|
158
|
-
signature: TransactionSignature; // TransactionSignature as a base 58 string
|
|
159
|
-
options?: SignatureSubscriptionOptions;
|
|
160
|
-
}>;
|
|
161
173
|
unsubscribeMethod: 'signatureUnsubscribe';
|
|
162
174
|
}
|
|
163
175
|
| {
|
|
164
176
|
callback: SlotChangeCallback;
|
|
165
177
|
method: 'slotSubscribe';
|
|
166
|
-
params: undefined;
|
|
167
178
|
unsubscribeMethod: 'slotUnsubscribe';
|
|
168
179
|
}
|
|
169
180
|
| {
|
|
170
181
|
callback: SlotUpdateCallback;
|
|
171
182
|
method: 'slotsUpdatesSubscribe';
|
|
172
|
-
params: undefined;
|
|
173
183
|
unsubscribeMethod: 'slotsUpdatesUnsubscribe';
|
|
174
184
|
}
|
|
175
185
|
>;
|
|
@@ -180,23 +190,24 @@ type SubscriptionConfig = Readonly<
|
|
|
180
190
|
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
181
191
|
? Omit<T, K>
|
|
182
192
|
: never;
|
|
183
|
-
type Subscription = BaseSubscription &
|
|
184
|
-
StatefulSubscription &
|
|
185
|
-
DistributiveOmit<SubscriptionConfig, 'callback'>;
|
|
186
|
-
|
|
187
193
|
/**
|
|
188
194
|
* @internal
|
|
195
|
+
* This type represents a single subscribable 'topic.' It's made up of:
|
|
196
|
+
*
|
|
197
|
+
* - The args used to open the subscription with the server,
|
|
198
|
+
* - The state of the subscription, in terms of its connectedness, and
|
|
199
|
+
* - The set of callbacks to call when the server publishes notifications
|
|
200
|
+
*
|
|
201
|
+
* This record gets indexed by `SubscriptionConfigHash` and is used to
|
|
202
|
+
* set up subscriptions, fan out notifications, and track subscription state.
|
|
189
203
|
*/
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}: SubscriptionConfig): SubscriptionConfigHash {
|
|
194
|
-
return fastStableStringify([method, params], true /* isArrayProp */);
|
|
195
|
-
}
|
|
204
|
+
type Subscription = BaseSubscription &
|
|
205
|
+
StatefulSubscription &
|
|
206
|
+
DistributiveOmit<SubscriptionConfig, 'callback'>;
|
|
196
207
|
|
|
197
|
-
type RpcRequest = (methodName: string, args: Array<any>) => any
|
|
208
|
+
type RpcRequest = (methodName: string, args: Array<any>) => Promise<any>;
|
|
198
209
|
|
|
199
|
-
type RpcBatchRequest = (requests: RpcParams[]) => any
|
|
210
|
+
type RpcBatchRequest = (requests: RpcParams[]) => Promise<any[]>;
|
|
200
211
|
|
|
201
212
|
/**
|
|
202
213
|
* @internal
|
|
@@ -231,6 +242,8 @@ export type SendOptions = {
|
|
|
231
242
|
preflightCommitment?: Commitment;
|
|
232
243
|
/** Maximum number of times for the RPC node to retry sending the transaction to the leader. */
|
|
233
244
|
maxRetries?: number;
|
|
245
|
+
/** The minimum slot that the request can be evaluated at */
|
|
246
|
+
minContextSlot?: number;
|
|
234
247
|
};
|
|
235
248
|
|
|
236
249
|
/**
|
|
@@ -245,6 +258,8 @@ export type ConfirmOptions = {
|
|
|
245
258
|
preflightCommitment?: Commitment;
|
|
246
259
|
/** Maximum number of times for the RPC node to retry sending the transaction to the leader. */
|
|
247
260
|
maxRetries?: number;
|
|
261
|
+
/** The minimum slot that the request can be evaluated at */
|
|
262
|
+
minContextSlot?: number;
|
|
248
263
|
};
|
|
249
264
|
|
|
250
265
|
/**
|
|
@@ -275,6 +290,8 @@ export type SignaturesForAddressOptions = {
|
|
|
275
290
|
until?: TransactionSignature;
|
|
276
291
|
/** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */
|
|
277
292
|
limit?: number;
|
|
293
|
+
/** The minimum slot that the request can be evaluated at */
|
|
294
|
+
minContextSlot?: number;
|
|
278
295
|
};
|
|
279
296
|
|
|
280
297
|
/**
|
|
@@ -287,6 +304,74 @@ export type RpcResponseAndContext<T> = {
|
|
|
287
304
|
value: T;
|
|
288
305
|
};
|
|
289
306
|
|
|
307
|
+
export type BlockhashWithExpiryBlockHeight = Readonly<{
|
|
308
|
+
blockhash: Blockhash;
|
|
309
|
+
lastValidBlockHeight: number;
|
|
310
|
+
}>;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* A strategy for confirming transactions that uses the last valid
|
|
314
|
+
* block height for a given blockhash to check for transaction expiration.
|
|
315
|
+
*/
|
|
316
|
+
export type BlockheightBasedTransactionConfirmationStrategy =
|
|
317
|
+
BaseTransactionConfirmationStrategy & BlockhashWithExpiryBlockHeight;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* A strategy for confirming durable nonce transactions.
|
|
321
|
+
*/
|
|
322
|
+
export type DurableNonceTransactionConfirmationStrategy =
|
|
323
|
+
BaseTransactionConfirmationStrategy & {
|
|
324
|
+
/**
|
|
325
|
+
* The lowest slot at which to fetch the nonce value from the
|
|
326
|
+
* nonce account. This should be no lower than the slot at
|
|
327
|
+
* which the last-known value of the nonce was fetched.
|
|
328
|
+
*/
|
|
329
|
+
minContextSlot: number;
|
|
330
|
+
/**
|
|
331
|
+
* The account where the current value of the nonce is stored.
|
|
332
|
+
*/
|
|
333
|
+
nonceAccountPubkey: PublicKey;
|
|
334
|
+
/**
|
|
335
|
+
* The nonce value that was used to sign the transaction
|
|
336
|
+
* for which confirmation is being sought.
|
|
337
|
+
*/
|
|
338
|
+
nonceValue: DurableNonce;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Properties shared by all transaction confirmation strategies
|
|
343
|
+
*/
|
|
344
|
+
export type BaseTransactionConfirmationStrategy = Readonly<{
|
|
345
|
+
/** A signal that, when aborted, cancels any outstanding transaction confirmation operations */
|
|
346
|
+
abortSignal?: AbortSignal;
|
|
347
|
+
signature: TransactionSignature;
|
|
348
|
+
}>;
|
|
349
|
+
|
|
350
|
+
/* @internal */
|
|
351
|
+
function assertEndpointUrl(putativeUrl: string) {
|
|
352
|
+
if (/^https?:/.test(putativeUrl) === false) {
|
|
353
|
+
throw new TypeError('Endpoint URL must start with `http:` or `https:`.');
|
|
354
|
+
}
|
|
355
|
+
return putativeUrl;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** @internal */
|
|
359
|
+
function extractCommitmentFromConfig<TConfig>(
|
|
360
|
+
commitmentOrConfig?: Commitment | ({commitment?: Commitment} & TConfig),
|
|
361
|
+
) {
|
|
362
|
+
let commitment: Commitment | undefined;
|
|
363
|
+
let config: Omit<TConfig, 'commitment'> | undefined;
|
|
364
|
+
if (typeof commitmentOrConfig === 'string') {
|
|
365
|
+
commitment = commitmentOrConfig;
|
|
366
|
+
} else if (commitmentOrConfig) {
|
|
367
|
+
const {commitment: specifiedCommitment, ...specifiedConfig} =
|
|
368
|
+
commitmentOrConfig;
|
|
369
|
+
commitment = specifiedCommitment;
|
|
370
|
+
config = specifiedConfig;
|
|
371
|
+
}
|
|
372
|
+
return {commitment, config};
|
|
373
|
+
}
|
|
374
|
+
|
|
290
375
|
/**
|
|
291
376
|
* @internal
|
|
292
377
|
*/
|
|
@@ -353,6 +438,32 @@ function notificationResultAndContext<T, U>(value: Struct<T, U>) {
|
|
|
353
438
|
});
|
|
354
439
|
}
|
|
355
440
|
|
|
441
|
+
/**
|
|
442
|
+
* @internal
|
|
443
|
+
*/
|
|
444
|
+
function versionedMessageFromResponse(
|
|
445
|
+
version: TransactionVersion | undefined,
|
|
446
|
+
response: MessageResponse,
|
|
447
|
+
): VersionedMessage {
|
|
448
|
+
if (version === 0) {
|
|
449
|
+
return new MessageV0({
|
|
450
|
+
header: response.header,
|
|
451
|
+
staticAccountKeys: response.accountKeys.map(
|
|
452
|
+
accountKey => new PublicKey(accountKey),
|
|
453
|
+
),
|
|
454
|
+
recentBlockhash: response.recentBlockhash,
|
|
455
|
+
compiledInstructions: response.instructions.map(ix => ({
|
|
456
|
+
programIdIndex: ix.programIdIndex,
|
|
457
|
+
accountKeyIndexes: ix.accounts,
|
|
458
|
+
data: bs58.decode(ix.data),
|
|
459
|
+
})),
|
|
460
|
+
addressTableLookups: response.addressTableLookups!,
|
|
461
|
+
});
|
|
462
|
+
} else {
|
|
463
|
+
return new Message(response);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
356
467
|
/**
|
|
357
468
|
* The level of commitment desired when querying state
|
|
358
469
|
* <pre>
|
|
@@ -389,6 +500,158 @@ export type Finality = 'confirmed' | 'finalized';
|
|
|
389
500
|
*/
|
|
390
501
|
export type LargestAccountsFilter = 'circulating' | 'nonCirculating';
|
|
391
502
|
|
|
503
|
+
/**
|
|
504
|
+
* Configuration object for changing `getAccountInfo` query behavior
|
|
505
|
+
*/
|
|
506
|
+
export type GetAccountInfoConfig = {
|
|
507
|
+
/** The level of commitment desired */
|
|
508
|
+
commitment?: Commitment;
|
|
509
|
+
/** The minimum slot that the request can be evaluated at */
|
|
510
|
+
minContextSlot?: number;
|
|
511
|
+
/** Optional data slice to limit the returned account data */
|
|
512
|
+
dataSlice?: DataSlice;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Configuration object for changing `getBalance` query behavior
|
|
517
|
+
*/
|
|
518
|
+
export type GetBalanceConfig = {
|
|
519
|
+
/** The level of commitment desired */
|
|
520
|
+
commitment?: Commitment;
|
|
521
|
+
/** The minimum slot that the request can be evaluated at */
|
|
522
|
+
minContextSlot?: number;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Configuration object for changing `getBlock` query behavior
|
|
527
|
+
*/
|
|
528
|
+
export type GetBlockConfig = {
|
|
529
|
+
/** The level of finality desired */
|
|
530
|
+
commitment?: Finality;
|
|
531
|
+
/**
|
|
532
|
+
* Whether to populate the rewards array. If parameter not provided, the default includes rewards.
|
|
533
|
+
*/
|
|
534
|
+
rewards?: boolean;
|
|
535
|
+
/**
|
|
536
|
+
* Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If
|
|
537
|
+
* parameter not provided, the default detail level is "full". If "accounts" are requested,
|
|
538
|
+
* transaction details only include signatures and an annotated list of accounts in each
|
|
539
|
+
* transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances,
|
|
540
|
+
* pre_token_balances, and post_token_balances.
|
|
541
|
+
*/
|
|
542
|
+
transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures';
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Configuration object for changing `getBlock` query behavior
|
|
547
|
+
*/
|
|
548
|
+
export type GetVersionedBlockConfig = {
|
|
549
|
+
/** The level of finality desired */
|
|
550
|
+
commitment?: Finality;
|
|
551
|
+
/** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */
|
|
552
|
+
maxSupportedTransactionVersion?: number;
|
|
553
|
+
/**
|
|
554
|
+
* Whether to populate the rewards array. If parameter not provided, the default includes rewards.
|
|
555
|
+
*/
|
|
556
|
+
rewards?: boolean;
|
|
557
|
+
/**
|
|
558
|
+
* Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If
|
|
559
|
+
* parameter not provided, the default detail level is "full". If "accounts" are requested,
|
|
560
|
+
* transaction details only include signatures and an annotated list of accounts in each
|
|
561
|
+
* transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances,
|
|
562
|
+
* pre_token_balances, and post_token_balances.
|
|
563
|
+
*/
|
|
564
|
+
transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures';
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Configuration object for changing `getStakeMinimumDelegation` query behavior
|
|
569
|
+
*/
|
|
570
|
+
export type GetStakeMinimumDelegationConfig = {
|
|
571
|
+
/** The level of commitment desired */
|
|
572
|
+
commitment?: Commitment;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Configuration object for changing `getBlockHeight` query behavior
|
|
577
|
+
*/
|
|
578
|
+
export type GetBlockHeightConfig = {
|
|
579
|
+
/** The level of commitment desired */
|
|
580
|
+
commitment?: Commitment;
|
|
581
|
+
/** The minimum slot that the request can be evaluated at */
|
|
582
|
+
minContextSlot?: number;
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Configuration object for changing `getEpochInfo` query behavior
|
|
587
|
+
*/
|
|
588
|
+
export type GetEpochInfoConfig = {
|
|
589
|
+
/** The level of commitment desired */
|
|
590
|
+
commitment?: Commitment;
|
|
591
|
+
/** The minimum slot that the request can be evaluated at */
|
|
592
|
+
minContextSlot?: number;
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Configuration object for changing `getInflationReward` query behavior
|
|
597
|
+
*/
|
|
598
|
+
export type GetInflationRewardConfig = {
|
|
599
|
+
/** The level of commitment desired */
|
|
600
|
+
commitment?: Commitment;
|
|
601
|
+
/** An epoch for which the reward occurs. If omitted, the previous epoch will be used */
|
|
602
|
+
epoch?: number;
|
|
603
|
+
/** The minimum slot that the request can be evaluated at */
|
|
604
|
+
minContextSlot?: number;
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Configuration object for changing `getLatestBlockhash` query behavior
|
|
609
|
+
*/
|
|
610
|
+
export type GetLatestBlockhashConfig = {
|
|
611
|
+
/** The level of commitment desired */
|
|
612
|
+
commitment?: Commitment;
|
|
613
|
+
/** The minimum slot that the request can be evaluated at */
|
|
614
|
+
minContextSlot?: number;
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Configuration object for changing `getSlot` query behavior
|
|
619
|
+
*/
|
|
620
|
+
export type GetSlotConfig = {
|
|
621
|
+
/** The level of commitment desired */
|
|
622
|
+
commitment?: Commitment;
|
|
623
|
+
/** The minimum slot that the request can be evaluated at */
|
|
624
|
+
minContextSlot?: number;
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Configuration object for changing `getSlotLeader` query behavior
|
|
629
|
+
*/
|
|
630
|
+
export type GetSlotLeaderConfig = {
|
|
631
|
+
/** The level of commitment desired */
|
|
632
|
+
commitment?: Commitment;
|
|
633
|
+
/** The minimum slot that the request can be evaluated at */
|
|
634
|
+
minContextSlot?: number;
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Configuration object for changing `getTransaction` query behavior
|
|
639
|
+
*/
|
|
640
|
+
export type GetTransactionConfig = {
|
|
641
|
+
/** The level of finality desired */
|
|
642
|
+
commitment?: Finality;
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Configuration object for changing `getTransaction` query behavior
|
|
647
|
+
*/
|
|
648
|
+
export type GetVersionedTransactionConfig = {
|
|
649
|
+
/** The level of finality desired */
|
|
650
|
+
commitment?: Finality;
|
|
651
|
+
/** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */
|
|
652
|
+
maxSupportedTransactionVersion?: number;
|
|
653
|
+
};
|
|
654
|
+
|
|
392
655
|
/**
|
|
393
656
|
* Configuration object for changing `getLargestAccounts` query behavior
|
|
394
657
|
*/
|
|
@@ -596,13 +859,36 @@ export type SimulatedTransactionAccountInfo = {
|
|
|
596
859
|
rentEpoch?: number;
|
|
597
860
|
};
|
|
598
861
|
|
|
862
|
+
export type TransactionReturnDataEncoding = 'base64';
|
|
863
|
+
|
|
864
|
+
export type TransactionReturnData = {
|
|
865
|
+
programId: string;
|
|
866
|
+
data: [string, TransactionReturnDataEncoding];
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
export type SimulateTransactionConfig = {
|
|
870
|
+
/** Optional parameter used to enable signature verification before simulation */
|
|
871
|
+
sigVerify?: boolean;
|
|
872
|
+
/** Optional parameter used to replace the simulated transaction's recent blockhash with the latest blockhash */
|
|
873
|
+
replaceRecentBlockhash?: boolean;
|
|
874
|
+
/** Optional parameter used to set the commitment level when selecting the latest block */
|
|
875
|
+
commitment?: Commitment;
|
|
876
|
+
/** Optional parameter used to specify a list of account addresses to return post simulation state for */
|
|
877
|
+
accounts?: {
|
|
878
|
+
encoding: 'base64';
|
|
879
|
+
addresses: string[];
|
|
880
|
+
};
|
|
881
|
+
/** Optional parameter used to specify the minimum block slot that can be used for simulation */
|
|
882
|
+
minContextSlot?: number;
|
|
883
|
+
};
|
|
884
|
+
|
|
599
885
|
export type SimulatedTransactionResponse = {
|
|
600
886
|
err: TransactionError | string | null;
|
|
601
887
|
logs: Array<string> | null;
|
|
602
888
|
accounts?: (SimulatedTransactionAccountInfo | null)[] | null;
|
|
603
889
|
unitsConsumed?: number;
|
|
890
|
+
returnData?: TransactionReturnData | null;
|
|
604
891
|
};
|
|
605
|
-
|
|
606
892
|
const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(
|
|
607
893
|
pick({
|
|
608
894
|
err: nullable(union([pick({}), string()])),
|
|
@@ -623,6 +909,14 @@ const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(
|
|
|
623
909
|
),
|
|
624
910
|
),
|
|
625
911
|
unitsConsumed: optional(number()),
|
|
912
|
+
returnData: optional(
|
|
913
|
+
nullable(
|
|
914
|
+
pick({
|
|
915
|
+
programId: string(),
|
|
916
|
+
data: tuple([string(), literal('base64')]),
|
|
917
|
+
}),
|
|
918
|
+
),
|
|
919
|
+
),
|
|
626
920
|
}),
|
|
627
921
|
);
|
|
628
922
|
|
|
@@ -645,6 +939,14 @@ export type TokenBalance = {
|
|
|
645
939
|
*/
|
|
646
940
|
export type ParsedConfirmedTransactionMeta = ParsedTransactionMeta;
|
|
647
941
|
|
|
942
|
+
/**
|
|
943
|
+
* Collection of addresses loaded by a transaction using address table lookups
|
|
944
|
+
*/
|
|
945
|
+
export type LoadedAddresses = {
|
|
946
|
+
writable: Array<PublicKey>;
|
|
947
|
+
readonly: Array<PublicKey>;
|
|
948
|
+
};
|
|
949
|
+
|
|
648
950
|
/**
|
|
649
951
|
* Metadata for a parsed transaction on the ledger
|
|
650
952
|
*/
|
|
@@ -665,6 +967,10 @@ export type ParsedTransactionMeta = {
|
|
|
665
967
|
postTokenBalances?: Array<TokenBalance> | null;
|
|
666
968
|
/** The error result of transaction processing */
|
|
667
969
|
err: TransactionError | null;
|
|
970
|
+
/** The collection of addresses loaded using address lookup tables */
|
|
971
|
+
loadedAddresses?: LoadedAddresses;
|
|
972
|
+
/** The compute units consumed after processing the transaction */
|
|
973
|
+
computeUnitsConsumed?: number;
|
|
668
974
|
};
|
|
669
975
|
|
|
670
976
|
export type CompiledInnerInstruction = {
|
|
@@ -692,6 +998,10 @@ export type ConfirmedTransactionMeta = {
|
|
|
692
998
|
postTokenBalances?: Array<TokenBalance> | null;
|
|
693
999
|
/** The error result of transaction processing */
|
|
694
1000
|
err: TransactionError | null;
|
|
1001
|
+
/** The collection of addresses loaded using address lookup tables */
|
|
1002
|
+
loadedAddresses?: LoadedAddresses;
|
|
1003
|
+
/** The compute units consumed after processing the transaction */
|
|
1004
|
+
computeUnitsConsumed?: number;
|
|
695
1005
|
};
|
|
696
1006
|
|
|
697
1007
|
/**
|
|
@@ -713,8 +1023,42 @@ export type TransactionResponse = {
|
|
|
713
1023
|
blockTime?: number | null;
|
|
714
1024
|
};
|
|
715
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* A processed transaction from the RPC API
|
|
1028
|
+
*/
|
|
1029
|
+
export type VersionedTransactionResponse = {
|
|
1030
|
+
/** The slot during which the transaction was processed */
|
|
1031
|
+
slot: number;
|
|
1032
|
+
/** The transaction */
|
|
1033
|
+
transaction: {
|
|
1034
|
+
/** The transaction message */
|
|
1035
|
+
message: VersionedMessage;
|
|
1036
|
+
/** The transaction signatures */
|
|
1037
|
+
signatures: string[];
|
|
1038
|
+
};
|
|
1039
|
+
/** Metadata produced from the transaction */
|
|
1040
|
+
meta: ConfirmedTransactionMeta | null;
|
|
1041
|
+
/** The unix timestamp of when the transaction was processed */
|
|
1042
|
+
blockTime?: number | null;
|
|
1043
|
+
/** The transaction version */
|
|
1044
|
+
version?: TransactionVersion;
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* A processed transaction message from the RPC API
|
|
1049
|
+
*/
|
|
1050
|
+
type MessageResponse = {
|
|
1051
|
+
accountKeys: string[];
|
|
1052
|
+
header: MessageHeader;
|
|
1053
|
+
instructions: CompiledInstruction[];
|
|
1054
|
+
recentBlockhash: string;
|
|
1055
|
+
addressTableLookups?: ParsedAddressTableLookup[];
|
|
1056
|
+
};
|
|
1057
|
+
|
|
716
1058
|
/**
|
|
717
1059
|
* A confirmed transaction on the ledger
|
|
1060
|
+
*
|
|
1061
|
+
* @deprecated Deprecated since Solana v1.8.0.
|
|
718
1062
|
*/
|
|
719
1063
|
export type ConfirmedTransaction = {
|
|
720
1064
|
/** The slot during which the transaction was processed */
|
|
@@ -749,6 +1093,8 @@ export type ParsedMessageAccount = {
|
|
|
749
1093
|
signer: boolean;
|
|
750
1094
|
/** Indicates if the account is writable for this transaction */
|
|
751
1095
|
writable: boolean;
|
|
1096
|
+
/** Indicates if the account key came from the transaction or a lookup table */
|
|
1097
|
+
source?: 'transaction' | 'lookupTable';
|
|
752
1098
|
};
|
|
753
1099
|
|
|
754
1100
|
/**
|
|
@@ -763,6 +1109,18 @@ export type ParsedInstruction = {
|
|
|
763
1109
|
parsed: any;
|
|
764
1110
|
};
|
|
765
1111
|
|
|
1112
|
+
/**
|
|
1113
|
+
* A parsed address table lookup
|
|
1114
|
+
*/
|
|
1115
|
+
export type ParsedAddressTableLookup = {
|
|
1116
|
+
/** Address lookup table account key */
|
|
1117
|
+
accountKey: PublicKey;
|
|
1118
|
+
/** Parsed instruction info */
|
|
1119
|
+
writableIndexes: number[];
|
|
1120
|
+
/** Parsed instruction info */
|
|
1121
|
+
readonlyIndexes: number[];
|
|
1122
|
+
};
|
|
1123
|
+
|
|
766
1124
|
/**
|
|
767
1125
|
* A parsed transaction message
|
|
768
1126
|
*/
|
|
@@ -773,6 +1131,8 @@ export type ParsedMessage = {
|
|
|
773
1131
|
instructions: (ParsedInstruction | PartiallyDecodedInstruction)[];
|
|
774
1132
|
/** Recent blockhash */
|
|
775
1133
|
recentBlockhash: string;
|
|
1134
|
+
/** Address table lookups used to load additional accounts */
|
|
1135
|
+
addressTableLookups?: ParsedAddressTableLookup[] | null;
|
|
776
1136
|
};
|
|
777
1137
|
|
|
778
1138
|
/**
|
|
@@ -804,6 +1164,8 @@ export type ParsedTransactionWithMeta = {
|
|
|
804
1164
|
meta: ParsedTransactionMeta | null;
|
|
805
1165
|
/** The unix timestamp of when the transaction was processed */
|
|
806
1166
|
blockTime?: number | null;
|
|
1167
|
+
/** The version of the transaction message */
|
|
1168
|
+
version?: TransactionVersion;
|
|
807
1169
|
};
|
|
808
1170
|
|
|
809
1171
|
/**
|
|
@@ -827,6 +1189,8 @@ export type BlockResponse = {
|
|
|
827
1189
|
};
|
|
828
1190
|
/** Metadata produced from the transaction */
|
|
829
1191
|
meta: ConfirmedTransactionMeta | null;
|
|
1192
|
+
/** The transaction version */
|
|
1193
|
+
version?: TransactionVersion;
|
|
830
1194
|
}>;
|
|
831
1195
|
/** Vector of block rewards */
|
|
832
1196
|
rewards?: Array<{
|
|
@@ -844,86 +1208,227 @@ export type BlockResponse = {
|
|
|
844
1208
|
};
|
|
845
1209
|
|
|
846
1210
|
/**
|
|
847
|
-
* A
|
|
1211
|
+
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
|
848
1212
|
*/
|
|
849
|
-
export type
|
|
1213
|
+
export type AccountsModeBlockResponse = VersionedAccountsModeBlockResponse;
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
|
1217
|
+
*/
|
|
1218
|
+
export type NoneModeBlockResponse = VersionedNoneModeBlockResponse;
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* A block with parsed transactions
|
|
1222
|
+
*/
|
|
1223
|
+
export type ParsedBlockResponse = {
|
|
850
1224
|
/** Blockhash of this block */
|
|
851
1225
|
blockhash: Blockhash;
|
|
852
1226
|
/** Blockhash of this block's parent */
|
|
853
1227
|
previousBlockhash: Blockhash;
|
|
854
1228
|
/** Slot index of this block's parent */
|
|
855
1229
|
parentSlot: number;
|
|
856
|
-
/** Vector of transactions
|
|
1230
|
+
/** Vector of transactions with status meta and original message */
|
|
857
1231
|
transactions: Array<{
|
|
858
|
-
transaction
|
|
859
|
-
|
|
1232
|
+
/** The details of the transaction */
|
|
1233
|
+
transaction: ParsedTransaction;
|
|
1234
|
+
/** Metadata produced from the transaction */
|
|
1235
|
+
meta: ParsedTransactionMeta | null;
|
|
1236
|
+
/** The transaction version */
|
|
1237
|
+
version?: TransactionVersion;
|
|
860
1238
|
}>;
|
|
861
1239
|
/** Vector of block rewards */
|
|
862
1240
|
rewards?: Array<{
|
|
1241
|
+
/** Public key of reward recipient */
|
|
863
1242
|
pubkey: string;
|
|
1243
|
+
/** Reward value in lamports */
|
|
864
1244
|
lamports: number;
|
|
1245
|
+
/** Account balance after reward is applied */
|
|
865
1246
|
postBalance: number | null;
|
|
1247
|
+
/** Type of reward received */
|
|
866
1248
|
rewardType: string | null;
|
|
867
1249
|
}>;
|
|
868
1250
|
/** The unix timestamp of when the block was processed */
|
|
869
1251
|
blockTime: number | null;
|
|
1252
|
+
/** The number of blocks beneath this block */
|
|
1253
|
+
blockHeight: number | null;
|
|
870
1254
|
};
|
|
871
1255
|
|
|
872
1256
|
/**
|
|
873
|
-
* A
|
|
1257
|
+
* A block with parsed transactions where the `transactionDetails` mode is `accounts`
|
|
874
1258
|
*/
|
|
875
|
-
export type
|
|
1259
|
+
export type ParsedAccountsModeBlockResponse = Omit<
|
|
1260
|
+
ParsedBlockResponse,
|
|
1261
|
+
'transactions'
|
|
1262
|
+
> & {
|
|
1263
|
+
transactions: Array<
|
|
1264
|
+
Omit<ParsedBlockResponse['transactions'][number], 'transaction'> & {
|
|
1265
|
+
transaction: Pick<
|
|
1266
|
+
ParsedBlockResponse['transactions'][number]['transaction'],
|
|
1267
|
+
'signatures'
|
|
1268
|
+
> & {
|
|
1269
|
+
accountKeys: ParsedMessageAccount[];
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
>;
|
|
1273
|
+
};
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* A block with parsed transactions where the `transactionDetails` mode is `none`
|
|
1277
|
+
*/
|
|
1278
|
+
export type ParsedNoneModeBlockResponse = Omit<
|
|
1279
|
+
ParsedBlockResponse,
|
|
1280
|
+
'transactions'
|
|
1281
|
+
>;
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* A processed block fetched from the RPC API
|
|
1285
|
+
*/
|
|
1286
|
+
export type VersionedBlockResponse = {
|
|
876
1287
|
/** Blockhash of this block */
|
|
877
1288
|
blockhash: Blockhash;
|
|
878
1289
|
/** Blockhash of this block's parent */
|
|
879
1290
|
previousBlockhash: Blockhash;
|
|
880
1291
|
/** Slot index of this block's parent */
|
|
881
1292
|
parentSlot: number;
|
|
882
|
-
/** Vector of
|
|
883
|
-
|
|
1293
|
+
/** Vector of transactions with status meta and original message */
|
|
1294
|
+
transactions: Array<{
|
|
1295
|
+
/** The transaction */
|
|
1296
|
+
transaction: {
|
|
1297
|
+
/** The transaction message */
|
|
1298
|
+
message: VersionedMessage;
|
|
1299
|
+
/** The transaction signatures */
|
|
1300
|
+
signatures: string[];
|
|
1301
|
+
};
|
|
1302
|
+
/** Metadata produced from the transaction */
|
|
1303
|
+
meta: ConfirmedTransactionMeta | null;
|
|
1304
|
+
/** The transaction version */
|
|
1305
|
+
version?: TransactionVersion;
|
|
1306
|
+
}>;
|
|
1307
|
+
/** Vector of block rewards */
|
|
1308
|
+
rewards?: Array<{
|
|
1309
|
+
/** Public key of reward recipient */
|
|
1310
|
+
pubkey: string;
|
|
1311
|
+
/** Reward value in lamports */
|
|
1312
|
+
lamports: number;
|
|
1313
|
+
/** Account balance after reward is applied */
|
|
1314
|
+
postBalance: number | null;
|
|
1315
|
+
/** Type of reward received */
|
|
1316
|
+
rewardType: string | null;
|
|
1317
|
+
}>;
|
|
884
1318
|
/** The unix timestamp of when the block was processed */
|
|
885
1319
|
blockTime: number | null;
|
|
886
1320
|
};
|
|
887
1321
|
|
|
888
1322
|
/**
|
|
889
|
-
*
|
|
1323
|
+
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
|
|
890
1324
|
*/
|
|
891
|
-
export type
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
commitment?: Commitment;
|
|
906
|
-
/** Slot range to return block production for. If parameter not provided, defaults to current epoch. */
|
|
907
|
-
range?: {
|
|
908
|
-
/** first slot to return block production information for (inclusive) */
|
|
909
|
-
firstSlot: number;
|
|
910
|
-
/** last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot */
|
|
911
|
-
lastSlot?: number;
|
|
912
|
-
};
|
|
913
|
-
/** Only return results for this validator identity (base-58 encoded) */
|
|
914
|
-
identity?: string;
|
|
1325
|
+
export type VersionedAccountsModeBlockResponse = Omit<
|
|
1326
|
+
VersionedBlockResponse,
|
|
1327
|
+
'transactions'
|
|
1328
|
+
> & {
|
|
1329
|
+
transactions: Array<
|
|
1330
|
+
Omit<VersionedBlockResponse['transactions'][number], 'transaction'> & {
|
|
1331
|
+
transaction: Pick<
|
|
1332
|
+
VersionedBlockResponse['transactions'][number]['transaction'],
|
|
1333
|
+
'signatures'
|
|
1334
|
+
> & {
|
|
1335
|
+
accountKeys: ParsedMessageAccount[];
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
>;
|
|
915
1339
|
};
|
|
916
1340
|
|
|
917
1341
|
/**
|
|
918
|
-
*
|
|
1342
|
+
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
|
|
919
1343
|
*/
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1344
|
+
export type VersionedNoneModeBlockResponse = Omit<
|
|
1345
|
+
VersionedBlockResponse,
|
|
1346
|
+
'transactions'
|
|
1347
|
+
>;
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* A confirmed block on the ledger
|
|
1351
|
+
*
|
|
1352
|
+
* @deprecated Deprecated since Solana v1.8.0.
|
|
1353
|
+
*/
|
|
1354
|
+
export type ConfirmedBlock = {
|
|
1355
|
+
/** Blockhash of this block */
|
|
1356
|
+
blockhash: Blockhash;
|
|
1357
|
+
/** Blockhash of this block's parent */
|
|
1358
|
+
previousBlockhash: Blockhash;
|
|
1359
|
+
/** Slot index of this block's parent */
|
|
1360
|
+
parentSlot: number;
|
|
1361
|
+
/** Vector of transactions and status metas */
|
|
1362
|
+
transactions: Array<{
|
|
1363
|
+
transaction: Transaction;
|
|
1364
|
+
meta: ConfirmedTransactionMeta | null;
|
|
1365
|
+
}>;
|
|
1366
|
+
/** Vector of block rewards */
|
|
1367
|
+
rewards?: Array<{
|
|
1368
|
+
pubkey: string;
|
|
1369
|
+
lamports: number;
|
|
1370
|
+
postBalance: number | null;
|
|
1371
|
+
rewardType: string | null;
|
|
1372
|
+
}>;
|
|
1373
|
+
/** The unix timestamp of when the block was processed */
|
|
1374
|
+
blockTime: number | null;
|
|
1375
|
+
};
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* A Block on the ledger with signatures only
|
|
1379
|
+
*/
|
|
1380
|
+
export type BlockSignatures = {
|
|
1381
|
+
/** Blockhash of this block */
|
|
1382
|
+
blockhash: Blockhash;
|
|
1383
|
+
/** Blockhash of this block's parent */
|
|
1384
|
+
previousBlockhash: Blockhash;
|
|
1385
|
+
/** Slot index of this block's parent */
|
|
1386
|
+
parentSlot: number;
|
|
1387
|
+
/** Vector of signatures */
|
|
1388
|
+
signatures: Array<string>;
|
|
1389
|
+
/** The unix timestamp of when the block was processed */
|
|
1390
|
+
blockTime: number | null;
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* recent block production information
|
|
1395
|
+
*/
|
|
1396
|
+
export type BlockProduction = Readonly<{
|
|
1397
|
+
/** a dictionary of validator identities, as base-58 encoded strings. Value is a two element array containing the number of leader slots and the number of blocks produced */
|
|
1398
|
+
byIdentity: Readonly<Record<string, ReadonlyArray<number>>>;
|
|
1399
|
+
/** Block production slot range */
|
|
1400
|
+
range: Readonly<{
|
|
1401
|
+
/** first slot of the block production information (inclusive) */
|
|
1402
|
+
firstSlot: number;
|
|
1403
|
+
/** last slot of block production information (inclusive) */
|
|
1404
|
+
lastSlot: number;
|
|
1405
|
+
}>;
|
|
1406
|
+
}>;
|
|
1407
|
+
|
|
1408
|
+
export type GetBlockProductionConfig = {
|
|
1409
|
+
/** Optional commitment level */
|
|
1410
|
+
commitment?: Commitment;
|
|
1411
|
+
/** Slot range to return block production for. If parameter not provided, defaults to current epoch. */
|
|
1412
|
+
range?: {
|
|
1413
|
+
/** first slot to return block production information for (inclusive) */
|
|
1414
|
+
firstSlot: number;
|
|
1415
|
+
/** last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot */
|
|
1416
|
+
lastSlot?: number;
|
|
1417
|
+
};
|
|
1418
|
+
/** Only return results for this validator identity (base-58 encoded) */
|
|
1419
|
+
identity?: string;
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Expected JSON RPC response for the "getBlockProduction" message
|
|
1424
|
+
*/
|
|
1425
|
+
const BlockProductionResponseStruct = jsonRpcResultAndContext(
|
|
1426
|
+
pick({
|
|
1427
|
+
byIdentity: record(string(), array(number())),
|
|
1428
|
+
range: pick({
|
|
1429
|
+
firstSlot: number(),
|
|
1430
|
+
lastSlot: number(),
|
|
1431
|
+
}),
|
|
927
1432
|
}),
|
|
928
1433
|
);
|
|
929
1434
|
|
|
@@ -943,29 +1448,64 @@ export type PerfSample = {
|
|
|
943
1448
|
|
|
944
1449
|
function createRpcClient(
|
|
945
1450
|
url: string,
|
|
946
|
-
useHttps: boolean,
|
|
947
1451
|
httpHeaders?: HttpHeaders,
|
|
948
|
-
customFetch?:
|
|
1452
|
+
customFetch?: FetchFn,
|
|
949
1453
|
fetchMiddleware?: FetchMiddleware,
|
|
950
1454
|
disableRetryOnRateLimit?: boolean,
|
|
1455
|
+
httpAgent?: HttpAgent | HttpsAgent | false,
|
|
951
1456
|
): RpcClient {
|
|
952
|
-
const fetch = customFetch ? customFetch :
|
|
953
|
-
let
|
|
954
|
-
if (
|
|
955
|
-
|
|
1457
|
+
const fetch = customFetch ? customFetch : fetchImpl;
|
|
1458
|
+
let agent: HttpAgent | HttpsAgent | undefined;
|
|
1459
|
+
if (process.env.BROWSER) {
|
|
1460
|
+
if (httpAgent != null) {
|
|
1461
|
+
console.warn(
|
|
1462
|
+
'You have supplied an `httpAgent` when creating a `Connection` in a browser environment.' +
|
|
1463
|
+
'It has been ignored; `httpAgent` is only used in Node environments.',
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
} else {
|
|
1467
|
+
if (httpAgent == null) {
|
|
1468
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
1469
|
+
agent = new Agent({
|
|
1470
|
+
// One second fewer than the Solana RPC's keepalive timeout.
|
|
1471
|
+
// Read more: https://github.com/solana-labs/solana/issues/27859#issuecomment-1340097889
|
|
1472
|
+
freeSocketTimeout: 19000,
|
|
1473
|
+
keepAlive: true,
|
|
1474
|
+
maxSockets: 25,
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
} else {
|
|
1478
|
+
if (httpAgent !== false) {
|
|
1479
|
+
const isHttps = url.startsWith('https:');
|
|
1480
|
+
if (isHttps && !(httpAgent instanceof HttpsAgent)) {
|
|
1481
|
+
throw new Error(
|
|
1482
|
+
'The endpoint `' +
|
|
1483
|
+
url +
|
|
1484
|
+
'` can only be paired with an `https.Agent`. You have, instead, supplied an ' +
|
|
1485
|
+
'`http.Agent` through `httpAgent`.',
|
|
1486
|
+
);
|
|
1487
|
+
} else if (!isHttps && httpAgent instanceof HttpsAgent) {
|
|
1488
|
+
throw new Error(
|
|
1489
|
+
'The endpoint `' +
|
|
1490
|
+
url +
|
|
1491
|
+
'` can only be paired with an `http.Agent`. You have, instead, supplied an ' +
|
|
1492
|
+
'`https.Agent` through `httpAgent`.',
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1495
|
+
agent = httpAgent;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
956
1498
|
}
|
|
957
1499
|
|
|
958
|
-
let fetchWithMiddleware:
|
|
959
|
-
| ((url: string, options: any) => Promise<Response>)
|
|
960
|
-
| undefined;
|
|
1500
|
+
let fetchWithMiddleware: FetchFn | undefined;
|
|
961
1501
|
|
|
962
1502
|
if (fetchMiddleware) {
|
|
963
|
-
fetchWithMiddleware = async (
|
|
964
|
-
const modifiedFetchArgs = await new Promise<
|
|
1503
|
+
fetchWithMiddleware = async (info, init) => {
|
|
1504
|
+
const modifiedFetchArgs = await new Promise<Parameters<FetchFn>>(
|
|
965
1505
|
(resolve, reject) => {
|
|
966
1506
|
try {
|
|
967
|
-
fetchMiddleware(
|
|
968
|
-
resolve([
|
|
1507
|
+
fetchMiddleware(info, init, (modifiedInfo, modifiedInit) =>
|
|
1508
|
+
resolve([modifiedInfo, modifiedInit]),
|
|
969
1509
|
);
|
|
970
1510
|
} catch (error) {
|
|
971
1511
|
reject(error);
|
|
@@ -977,7 +1517,6 @@ function createRpcClient(
|
|
|
977
1517
|
}
|
|
978
1518
|
|
|
979
1519
|
const clientBrowser = new RpcClient(async (request, callback) => {
|
|
980
|
-
const agent = agentManager ? agentManager.requestStart() : undefined;
|
|
981
1520
|
const options = {
|
|
982
1521
|
method: 'POST',
|
|
983
1522
|
body: request,
|
|
@@ -987,6 +1526,7 @@ function createRpcClient(
|
|
|
987
1526
|
'Content-Type': 'application/json',
|
|
988
1527
|
},
|
|
989
1528
|
httpHeaders || {},
|
|
1529
|
+
COMMON_HTTP_HEADERS,
|
|
990
1530
|
),
|
|
991
1531
|
};
|
|
992
1532
|
|
|
@@ -1026,8 +1566,6 @@ function createRpcClient(
|
|
|
1026
1566
|
}
|
|
1027
1567
|
} catch (err) {
|
|
1028
1568
|
if (err instanceof Error) callback(err);
|
|
1029
|
-
} finally {
|
|
1030
|
-
agentManager && agentManager.requestEnd();
|
|
1031
1569
|
}
|
|
1032
1570
|
}, {});
|
|
1033
1571
|
|
|
@@ -1549,6 +2087,12 @@ const GetSignatureStatusesRpcResult = jsonRpcResultAndContext(
|
|
|
1549
2087
|
*/
|
|
1550
2088
|
const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult(number());
|
|
1551
2089
|
|
|
2090
|
+
const AddressTableLookupStruct = pick({
|
|
2091
|
+
accountKey: PublicKeyFromString,
|
|
2092
|
+
writableIndexes: array(number()),
|
|
2093
|
+
readonlyIndexes: array(number()),
|
|
2094
|
+
});
|
|
2095
|
+
|
|
1552
2096
|
const ConfirmedTransactionResult = pick({
|
|
1553
2097
|
signatures: array(string()),
|
|
1554
2098
|
message: pick({
|
|
@@ -1566,9 +2110,22 @@ const ConfirmedTransactionResult = pick({
|
|
|
1566
2110
|
}),
|
|
1567
2111
|
),
|
|
1568
2112
|
recentBlockhash: string(),
|
|
2113
|
+
addressTableLookups: optional(array(AddressTableLookupStruct)),
|
|
1569
2114
|
}),
|
|
1570
2115
|
});
|
|
1571
2116
|
|
|
2117
|
+
const AnnotatedAccountKey = pick({
|
|
2118
|
+
pubkey: PublicKeyFromString,
|
|
2119
|
+
signer: boolean(),
|
|
2120
|
+
writable: boolean(),
|
|
2121
|
+
source: optional(union([literal('transaction'), literal('lookupTable')])),
|
|
2122
|
+
});
|
|
2123
|
+
|
|
2124
|
+
const ConfirmedTransactionAccountsModeResult = pick({
|
|
2125
|
+
accountKeys: array(AnnotatedAccountKey),
|
|
2126
|
+
signatures: array(string()),
|
|
2127
|
+
});
|
|
2128
|
+
|
|
1572
2129
|
const ParsedInstructionResult = pick({
|
|
1573
2130
|
parsed: unknown(),
|
|
1574
2131
|
program: string(),
|
|
@@ -1617,15 +2174,10 @@ const ParsedOrRawInstruction = coerce(
|
|
|
1617
2174
|
const ParsedConfirmedTransactionResult = pick({
|
|
1618
2175
|
signatures: array(string()),
|
|
1619
2176
|
message: pick({
|
|
1620
|
-
accountKeys: array(
|
|
1621
|
-
pick({
|
|
1622
|
-
pubkey: PublicKeyFromString,
|
|
1623
|
-
signer: boolean(),
|
|
1624
|
-
writable: boolean(),
|
|
1625
|
-
}),
|
|
1626
|
-
),
|
|
2177
|
+
accountKeys: array(AnnotatedAccountKey),
|
|
1627
2178
|
instructions: array(ParsedOrRawInstruction),
|
|
1628
2179
|
recentBlockhash: string(),
|
|
2180
|
+
addressTableLookups: optional(nullable(array(AddressTableLookupStruct))),
|
|
1629
2181
|
}),
|
|
1630
2182
|
});
|
|
1631
2183
|
|
|
@@ -1636,6 +2188,11 @@ const TokenBalanceResult = pick({
|
|
|
1636
2188
|
uiTokenAmount: TokenAmountResult,
|
|
1637
2189
|
});
|
|
1638
2190
|
|
|
2191
|
+
const LoadedAddressesResult = pick({
|
|
2192
|
+
writable: array(PublicKeyFromString),
|
|
2193
|
+
readonly: array(PublicKeyFromString),
|
|
2194
|
+
});
|
|
2195
|
+
|
|
1639
2196
|
/**
|
|
1640
2197
|
* @internal
|
|
1641
2198
|
*/
|
|
@@ -1663,6 +2220,8 @@ const ConfirmedTransactionMetaResult = pick({
|
|
|
1663
2220
|
logMessages: optional(nullable(array(string()))),
|
|
1664
2221
|
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
1665
2222
|
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
2223
|
+
loadedAddresses: optional(LoadedAddressesResult),
|
|
2224
|
+
computeUnitsConsumed: optional(number()),
|
|
1666
2225
|
});
|
|
1667
2226
|
|
|
1668
2227
|
/**
|
|
@@ -1686,6 +2245,18 @@ const ParsedConfirmedTransactionMetaResult = pick({
|
|
|
1686
2245
|
logMessages: optional(nullable(array(string()))),
|
|
1687
2246
|
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
1688
2247
|
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
|
|
2248
|
+
loadedAddresses: optional(LoadedAddressesResult),
|
|
2249
|
+
computeUnitsConsumed: optional(number()),
|
|
2250
|
+
});
|
|
2251
|
+
|
|
2252
|
+
const TransactionVersionStruct = union([literal(0), literal('legacy')]);
|
|
2253
|
+
|
|
2254
|
+
/** @internal */
|
|
2255
|
+
const RewardsResult = pick({
|
|
2256
|
+
pubkey: string(),
|
|
2257
|
+
lamports: number(),
|
|
2258
|
+
postBalance: nullable(number()),
|
|
2259
|
+
rewardType: nullable(string()),
|
|
1689
2260
|
});
|
|
1690
2261
|
|
|
1691
2262
|
/**
|
|
@@ -1701,18 +2272,111 @@ const GetBlockRpcResult = jsonRpcResult(
|
|
|
1701
2272
|
pick({
|
|
1702
2273
|
transaction: ConfirmedTransactionResult,
|
|
1703
2274
|
meta: nullable(ConfirmedTransactionMetaResult),
|
|
2275
|
+
version: optional(TransactionVersionStruct),
|
|
1704
2276
|
}),
|
|
1705
2277
|
),
|
|
1706
|
-
rewards: optional(
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
2278
|
+
rewards: optional(array(RewardsResult)),
|
|
2279
|
+
blockTime: nullable(number()),
|
|
2280
|
+
blockHeight: nullable(number()),
|
|
2281
|
+
}),
|
|
2282
|
+
),
|
|
2283
|
+
);
|
|
2284
|
+
|
|
2285
|
+
/**
|
|
2286
|
+
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
|
2287
|
+
*/
|
|
2288
|
+
const GetNoneModeBlockRpcResult = jsonRpcResult(
|
|
2289
|
+
nullable(
|
|
2290
|
+
pick({
|
|
2291
|
+
blockhash: string(),
|
|
2292
|
+
previousBlockhash: string(),
|
|
2293
|
+
parentSlot: number(),
|
|
2294
|
+
rewards: optional(array(RewardsResult)),
|
|
2295
|
+
blockTime: nullable(number()),
|
|
2296
|
+
blockHeight: nullable(number()),
|
|
2297
|
+
}),
|
|
2298
|
+
),
|
|
2299
|
+
);
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
|
2303
|
+
*/
|
|
2304
|
+
const GetAccountsModeBlockRpcResult = jsonRpcResult(
|
|
2305
|
+
nullable(
|
|
2306
|
+
pick({
|
|
2307
|
+
blockhash: string(),
|
|
2308
|
+
previousBlockhash: string(),
|
|
2309
|
+
parentSlot: number(),
|
|
2310
|
+
transactions: array(
|
|
2311
|
+
pick({
|
|
2312
|
+
transaction: ConfirmedTransactionAccountsModeResult,
|
|
2313
|
+
meta: nullable(ConfirmedTransactionMetaResult),
|
|
2314
|
+
version: optional(TransactionVersionStruct),
|
|
2315
|
+
}),
|
|
2316
|
+
),
|
|
2317
|
+
rewards: optional(array(RewardsResult)),
|
|
2318
|
+
blockTime: nullable(number()),
|
|
2319
|
+
blockHeight: nullable(number()),
|
|
2320
|
+
}),
|
|
2321
|
+
),
|
|
2322
|
+
);
|
|
2323
|
+
|
|
2324
|
+
/**
|
|
2325
|
+
* Expected parsed JSON RPC response for the "getBlock" message
|
|
2326
|
+
*/
|
|
2327
|
+
const GetParsedBlockRpcResult = jsonRpcResult(
|
|
2328
|
+
nullable(
|
|
2329
|
+
pick({
|
|
2330
|
+
blockhash: string(),
|
|
2331
|
+
previousBlockhash: string(),
|
|
2332
|
+
parentSlot: number(),
|
|
2333
|
+
transactions: array(
|
|
2334
|
+
pick({
|
|
2335
|
+
transaction: ParsedConfirmedTransactionResult,
|
|
2336
|
+
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
|
2337
|
+
version: optional(TransactionVersionStruct),
|
|
2338
|
+
}),
|
|
2339
|
+
),
|
|
2340
|
+
rewards: optional(array(RewardsResult)),
|
|
2341
|
+
blockTime: nullable(number()),
|
|
2342
|
+
blockHeight: nullable(number()),
|
|
2343
|
+
}),
|
|
2344
|
+
),
|
|
2345
|
+
);
|
|
2346
|
+
|
|
2347
|
+
/**
|
|
2348
|
+
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
|
|
2349
|
+
*/
|
|
2350
|
+
const GetParsedAccountsModeBlockRpcResult = jsonRpcResult(
|
|
2351
|
+
nullable(
|
|
2352
|
+
pick({
|
|
2353
|
+
blockhash: string(),
|
|
2354
|
+
previousBlockhash: string(),
|
|
2355
|
+
parentSlot: number(),
|
|
2356
|
+
transactions: array(
|
|
2357
|
+
pick({
|
|
2358
|
+
transaction: ConfirmedTransactionAccountsModeResult,
|
|
2359
|
+
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
|
2360
|
+
version: optional(TransactionVersionStruct),
|
|
2361
|
+
}),
|
|
1715
2362
|
),
|
|
2363
|
+
rewards: optional(array(RewardsResult)),
|
|
2364
|
+
blockTime: nullable(number()),
|
|
2365
|
+
blockHeight: nullable(number()),
|
|
2366
|
+
}),
|
|
2367
|
+
),
|
|
2368
|
+
);
|
|
2369
|
+
|
|
2370
|
+
/**
|
|
2371
|
+
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
|
|
2372
|
+
*/
|
|
2373
|
+
const GetParsedNoneModeBlockRpcResult = jsonRpcResult(
|
|
2374
|
+
nullable(
|
|
2375
|
+
pick({
|
|
2376
|
+
blockhash: string(),
|
|
2377
|
+
previousBlockhash: string(),
|
|
2378
|
+
parentSlot: number(),
|
|
2379
|
+
rewards: optional(array(RewardsResult)),
|
|
1716
2380
|
blockTime: nullable(number()),
|
|
1717
2381
|
blockHeight: nullable(number()),
|
|
1718
2382
|
}),
|
|
@@ -1736,16 +2400,7 @@ const GetConfirmedBlockRpcResult = jsonRpcResult(
|
|
|
1736
2400
|
meta: nullable(ConfirmedTransactionMetaResult),
|
|
1737
2401
|
}),
|
|
1738
2402
|
),
|
|
1739
|
-
rewards: optional(
|
|
1740
|
-
array(
|
|
1741
|
-
pick({
|
|
1742
|
-
pubkey: string(),
|
|
1743
|
-
lamports: number(),
|
|
1744
|
-
postBalance: nullable(number()),
|
|
1745
|
-
rewardType: nullable(string()),
|
|
1746
|
-
}),
|
|
1747
|
-
),
|
|
1748
|
-
),
|
|
2403
|
+
rewards: optional(array(RewardsResult)),
|
|
1749
2404
|
blockTime: nullable(number()),
|
|
1750
2405
|
}),
|
|
1751
2406
|
),
|
|
@@ -1776,6 +2431,7 @@ const GetTransactionRpcResult = jsonRpcResult(
|
|
|
1776
2431
|
meta: ConfirmedTransactionMetaResult,
|
|
1777
2432
|
blockTime: optional(nullable(number())),
|
|
1778
2433
|
transaction: ConfirmedTransactionResult,
|
|
2434
|
+
version: optional(TransactionVersionStruct),
|
|
1779
2435
|
}),
|
|
1780
2436
|
),
|
|
1781
2437
|
);
|
|
@@ -1790,6 +2446,7 @@ const GetParsedTransactionRpcResult = jsonRpcResult(
|
|
|
1790
2446
|
transaction: ParsedConfirmedTransactionResult,
|
|
1791
2447
|
meta: nullable(ParsedConfirmedTransactionMetaResult),
|
|
1792
2448
|
blockTime: optional(nullable(number())),
|
|
2449
|
+
version: optional(TransactionVersionStruct),
|
|
1793
2450
|
}),
|
|
1794
2451
|
),
|
|
1795
2452
|
);
|
|
@@ -1940,6 +2597,8 @@ export type GetProgramAccountsConfig = {
|
|
|
1940
2597
|
dataSlice?: DataSlice;
|
|
1941
2598
|
/** Optional array of filters to apply to accounts */
|
|
1942
2599
|
filters?: GetProgramAccountsFilter[];
|
|
2600
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2601
|
+
minContextSlot?: number;
|
|
1943
2602
|
};
|
|
1944
2603
|
|
|
1945
2604
|
/**
|
|
@@ -1950,6 +2609,8 @@ export type GetParsedProgramAccountsConfig = {
|
|
|
1950
2609
|
commitment?: Commitment;
|
|
1951
2610
|
/** Optional array of filters to apply to accounts */
|
|
1952
2611
|
filters?: GetProgramAccountsFilter[];
|
|
2612
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2613
|
+
minContextSlot?: number;
|
|
1953
2614
|
};
|
|
1954
2615
|
|
|
1955
2616
|
/**
|
|
@@ -1958,8 +2619,62 @@ export type GetParsedProgramAccountsConfig = {
|
|
|
1958
2619
|
export type GetMultipleAccountsConfig = {
|
|
1959
2620
|
/** Optional commitment level */
|
|
1960
2621
|
commitment?: Commitment;
|
|
1961
|
-
/**
|
|
1962
|
-
|
|
2622
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2623
|
+
minContextSlot?: number;
|
|
2624
|
+
/** Optional data slice to limit the returned account data */
|
|
2625
|
+
dataSlice?: DataSlice;
|
|
2626
|
+
};
|
|
2627
|
+
|
|
2628
|
+
/**
|
|
2629
|
+
* Configuration object for `getStakeActivation`
|
|
2630
|
+
*/
|
|
2631
|
+
export type GetStakeActivationConfig = {
|
|
2632
|
+
/** Optional commitment level */
|
|
2633
|
+
commitment?: Commitment;
|
|
2634
|
+
/** Epoch for which to calculate activation details. If parameter not provided, defaults to current epoch */
|
|
2635
|
+
epoch?: number;
|
|
2636
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2637
|
+
minContextSlot?: number;
|
|
2638
|
+
};
|
|
2639
|
+
|
|
2640
|
+
/**
|
|
2641
|
+
* Configuration object for `getStakeActivation`
|
|
2642
|
+
*/
|
|
2643
|
+
export type GetTokenAccountsByOwnerConfig = {
|
|
2644
|
+
/** Optional commitment level */
|
|
2645
|
+
commitment?: Commitment;
|
|
2646
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2647
|
+
minContextSlot?: number;
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2650
|
+
/**
|
|
2651
|
+
* Configuration object for `getStakeActivation`
|
|
2652
|
+
*/
|
|
2653
|
+
export type GetTransactionCountConfig = {
|
|
2654
|
+
/** Optional commitment level */
|
|
2655
|
+
commitment?: Commitment;
|
|
2656
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2657
|
+
minContextSlot?: number;
|
|
2658
|
+
};
|
|
2659
|
+
|
|
2660
|
+
/**
|
|
2661
|
+
* Configuration object for `getNonce`
|
|
2662
|
+
*/
|
|
2663
|
+
export type GetNonceConfig = {
|
|
2664
|
+
/** Optional commitment level */
|
|
2665
|
+
commitment?: Commitment;
|
|
2666
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2667
|
+
minContextSlot?: number;
|
|
2668
|
+
};
|
|
2669
|
+
|
|
2670
|
+
/**
|
|
2671
|
+
* Configuration object for `getNonceAndContext`
|
|
2672
|
+
*/
|
|
2673
|
+
export type GetNonceAndContextConfig = {
|
|
2674
|
+
/** Optional commitment level */
|
|
2675
|
+
commitment?: Commitment;
|
|
2676
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2677
|
+
minContextSlot?: number;
|
|
1963
2678
|
};
|
|
1964
2679
|
|
|
1965
2680
|
/**
|
|
@@ -2047,7 +2762,7 @@ export type SignatureSubscriptionCallback = (
|
|
|
2047
2762
|
* Signature subscription options
|
|
2048
2763
|
*/
|
|
2049
2764
|
export type SignatureSubscriptionOptions = {
|
|
2050
|
-
commitment?: Commitment;
|
|
2765
|
+
commitment?: Commitment;
|
|
2051
2766
|
enableReceivedNotification?: boolean;
|
|
2052
2767
|
};
|
|
2053
2768
|
|
|
@@ -2145,26 +2860,44 @@ export type ConfirmedSignatureInfo = {
|
|
|
2145
2860
|
memo: string | null;
|
|
2146
2861
|
/** The unix timestamp of when the transaction was processed */
|
|
2147
2862
|
blockTime?: number | null;
|
|
2863
|
+
/** Cluster confirmation status, if available. Possible values: `processed`, `confirmed`, `finalized` */
|
|
2864
|
+
confirmationStatus?: TransactionConfirmationStatus;
|
|
2148
2865
|
};
|
|
2149
2866
|
|
|
2150
2867
|
/**
|
|
2151
2868
|
* An object defining headers to be passed to the RPC server
|
|
2152
2869
|
*/
|
|
2153
|
-
export type HttpHeaders = {
|
|
2870
|
+
export type HttpHeaders = {
|
|
2871
|
+
[header: string]: string;
|
|
2872
|
+
} & {
|
|
2873
|
+
// Prohibited headers; for internal use only.
|
|
2874
|
+
'solana-client'?: never;
|
|
2875
|
+
};
|
|
2876
|
+
|
|
2877
|
+
/**
|
|
2878
|
+
* The type of the JavaScript `fetch()` API
|
|
2879
|
+
*/
|
|
2880
|
+
export type FetchFn = typeof fetchImpl;
|
|
2154
2881
|
|
|
2155
2882
|
/**
|
|
2156
2883
|
* A callback used to augment the outgoing HTTP request
|
|
2157
2884
|
*/
|
|
2158
2885
|
export type FetchMiddleware = (
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
fetch: (
|
|
2886
|
+
info: Parameters<FetchFn>[0],
|
|
2887
|
+
init: Parameters<FetchFn>[1],
|
|
2888
|
+
fetch: (...a: Parameters<FetchFn>) => void,
|
|
2162
2889
|
) => void;
|
|
2163
2890
|
|
|
2164
2891
|
/**
|
|
2165
2892
|
* Configuration for instantiating a Connection
|
|
2166
2893
|
*/
|
|
2167
2894
|
export type ConnectionConfig = {
|
|
2895
|
+
/**
|
|
2896
|
+
* An `http.Agent` that will be used to manage socket connections (eg. to implement connection
|
|
2897
|
+
* persistence). Set this to `false` to create a connection that uses no agent. This applies to
|
|
2898
|
+
* Node environments only.
|
|
2899
|
+
*/
|
|
2900
|
+
httpAgent?: HttpAgent | HttpsAgent | false;
|
|
2168
2901
|
/** Optional commitment level */
|
|
2169
2902
|
commitment?: Commitment;
|
|
2170
2903
|
/** Optional endpoint URL to the fullnode JSON RPC PubSub WebSocket Endpoint */
|
|
@@ -2172,7 +2905,7 @@ export type ConnectionConfig = {
|
|
|
2172
2905
|
/** Optional HTTP headers object */
|
|
2173
2906
|
httpHeaders?: HttpHeaders;
|
|
2174
2907
|
/** Optional custom fetch function */
|
|
2175
|
-
fetch?:
|
|
2908
|
+
fetch?: FetchFn;
|
|
2176
2909
|
/** Optional fetch middleware callback */
|
|
2177
2910
|
fetchMiddleware?: FetchMiddleware;
|
|
2178
2911
|
/** Optional Disable retrying calls when server responds with HTTP 429 (Too Many Requests) */
|
|
@@ -2181,6 +2914,11 @@ export type ConnectionConfig = {
|
|
|
2181
2914
|
confirmTransactionInitialTimeout?: number;
|
|
2182
2915
|
};
|
|
2183
2916
|
|
|
2917
|
+
/** @internal */
|
|
2918
|
+
const COMMON_HTTP_HEADERS = {
|
|
2919
|
+
'solana-client': `js/${process.env.npm_package_version ?? 'UNKNOWN'}`,
|
|
2920
|
+
};
|
|
2921
|
+
|
|
2184
2922
|
/**
|
|
2185
2923
|
* A connection to a fullnode JSON RPC endpoint
|
|
2186
2924
|
*/
|
|
@@ -2200,33 +2938,50 @@ export class Connection {
|
|
|
2200
2938
|
/** @internal */ _rpcWebSocketIdleTimeout: ReturnType<
|
|
2201
2939
|
typeof setTimeout
|
|
2202
2940
|
> | null = null;
|
|
2941
|
+
/** @internal
|
|
2942
|
+
* A number that we increment every time an active connection closes.
|
|
2943
|
+
* Used to determine whether the same socket connection that was open
|
|
2944
|
+
* when an async operation started is the same one that's active when
|
|
2945
|
+
* its continuation fires.
|
|
2946
|
+
*
|
|
2947
|
+
*/ private _rpcWebSocketGeneration: number = 0;
|
|
2203
2948
|
|
|
2204
2949
|
/** @internal */ _disableBlockhashCaching: boolean = false;
|
|
2205
2950
|
/** @internal */ _pollingBlockhash: boolean = false;
|
|
2206
2951
|
/** @internal */ _blockhashInfo: {
|
|
2207
|
-
|
|
2952
|
+
latestBlockhash: BlockhashWithExpiryBlockHeight | null;
|
|
2208
2953
|
lastFetch: number;
|
|
2209
2954
|
simulatedSignatures: Array<string>;
|
|
2210
2955
|
transactionSignatures: Array<string>;
|
|
2211
2956
|
} = {
|
|
2212
|
-
|
|
2957
|
+
latestBlockhash: null,
|
|
2213
2958
|
lastFetch: 0,
|
|
2214
2959
|
transactionSignatures: [],
|
|
2215
2960
|
simulatedSignatures: [],
|
|
2216
2961
|
};
|
|
2217
2962
|
|
|
2218
|
-
/** @internal */ _nextClientSubscriptionId: ClientSubscriptionId = 0;
|
|
2219
|
-
/** @internal */ _subscriptionDisposeFunctionsByClientSubscriptionId: {
|
|
2963
|
+
/** @internal */ private _nextClientSubscriptionId: ClientSubscriptionId = 0;
|
|
2964
|
+
/** @internal */ private _subscriptionDisposeFunctionsByClientSubscriptionId: {
|
|
2220
2965
|
[clientSubscriptionId: ClientSubscriptionId]:
|
|
2221
2966
|
| SubscriptionDisposeFn
|
|
2222
2967
|
| undefined;
|
|
2223
2968
|
} = {};
|
|
2224
|
-
/** @internal */
|
|
2969
|
+
/** @internal */ private _subscriptionHashByClientSubscriptionId: {
|
|
2970
|
+
[clientSubscriptionId: ClientSubscriptionId]:
|
|
2971
|
+
| SubscriptionConfigHash
|
|
2972
|
+
| undefined;
|
|
2973
|
+
} = {};
|
|
2974
|
+
/** @internal */ private _subscriptionStateChangeCallbacksByHash: {
|
|
2975
|
+
[hash: SubscriptionConfigHash]:
|
|
2976
|
+
| Set<SubscriptionStateChangeCallback>
|
|
2977
|
+
| undefined;
|
|
2978
|
+
} = {};
|
|
2979
|
+
/** @internal */ private _subscriptionCallbacksByServerSubscriptionId: {
|
|
2225
2980
|
[serverSubscriptionId: ServerSubscriptionId]:
|
|
2226
2981
|
| Set<SubscriptionConfig['callback']>
|
|
2227
2982
|
| undefined;
|
|
2228
2983
|
} = {};
|
|
2229
|
-
/** @internal */ _subscriptionsByHash: {
|
|
2984
|
+
/** @internal */ private _subscriptionsByHash: {
|
|
2230
2985
|
[hash: SubscriptionConfigHash]: Subscription | undefined;
|
|
2231
2986
|
} = {};
|
|
2232
2987
|
/**
|
|
@@ -2242,7 +2997,7 @@ export class Connection {
|
|
|
2242
2997
|
* NOTE: There is a proposal to eliminate this special case, here:
|
|
2243
2998
|
* https://github.com/solana-labs/solana/issues/18892
|
|
2244
2999
|
*/
|
|
2245
|
-
/** @internal */ _subscriptionsAutoDisposedByRpc: Set<ServerSubscriptionId> =
|
|
3000
|
+
/** @internal */ private _subscriptionsAutoDisposedByRpc: Set<ServerSubscriptionId> =
|
|
2246
3001
|
new Set();
|
|
2247
3002
|
|
|
2248
3003
|
/**
|
|
@@ -2255,14 +3010,12 @@ export class Connection {
|
|
|
2255
3010
|
endpoint: string,
|
|
2256
3011
|
commitmentOrConfig?: Commitment | ConnectionConfig,
|
|
2257
3012
|
) {
|
|
2258
|
-
let url = new URL(endpoint);
|
|
2259
|
-
const useHttps = url.protocol === 'https:';
|
|
2260
|
-
|
|
2261
3013
|
let wsEndpoint;
|
|
2262
3014
|
let httpHeaders;
|
|
2263
3015
|
let fetch;
|
|
2264
3016
|
let fetchMiddleware;
|
|
2265
3017
|
let disableRetryOnRateLimit;
|
|
3018
|
+
let httpAgent;
|
|
2266
3019
|
if (commitmentOrConfig && typeof commitmentOrConfig === 'string') {
|
|
2267
3020
|
this._commitment = commitmentOrConfig;
|
|
2268
3021
|
} else if (commitmentOrConfig) {
|
|
@@ -2274,18 +3027,19 @@ export class Connection {
|
|
|
2274
3027
|
fetch = commitmentOrConfig.fetch;
|
|
2275
3028
|
fetchMiddleware = commitmentOrConfig.fetchMiddleware;
|
|
2276
3029
|
disableRetryOnRateLimit = commitmentOrConfig.disableRetryOnRateLimit;
|
|
3030
|
+
httpAgent = commitmentOrConfig.httpAgent;
|
|
2277
3031
|
}
|
|
2278
3032
|
|
|
2279
|
-
this._rpcEndpoint = endpoint;
|
|
3033
|
+
this._rpcEndpoint = assertEndpointUrl(endpoint);
|
|
2280
3034
|
this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
|
|
2281
3035
|
|
|
2282
3036
|
this._rpcClient = createRpcClient(
|
|
2283
|
-
|
|
2284
|
-
useHttps,
|
|
3037
|
+
endpoint,
|
|
2285
3038
|
httpHeaders,
|
|
2286
3039
|
fetch,
|
|
2287
3040
|
fetchMiddleware,
|
|
2288
3041
|
disableRetryOnRateLimit,
|
|
3042
|
+
httpAgent,
|
|
2289
3043
|
);
|
|
2290
3044
|
this._rpcRequest = createRpcRequest(this._rpcClient);
|
|
2291
3045
|
this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient);
|
|
@@ -2346,17 +3100,23 @@ export class Connection {
|
|
|
2346
3100
|
*/
|
|
2347
3101
|
async getBalanceAndContext(
|
|
2348
3102
|
publicKey: PublicKey,
|
|
2349
|
-
|
|
3103
|
+
commitmentOrConfig?: Commitment | GetBalanceConfig,
|
|
2350
3104
|
): Promise<RpcResponseAndContext<number>> {
|
|
2351
|
-
|
|
3105
|
+
/** @internal */
|
|
3106
|
+
const {commitment, config} =
|
|
3107
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
3108
|
+
const args = this._buildArgs(
|
|
3109
|
+
[publicKey.toBase58()],
|
|
3110
|
+
commitment,
|
|
3111
|
+
undefined /* encoding */,
|
|
3112
|
+
config,
|
|
3113
|
+
);
|
|
2352
3114
|
const unsafeRes = await this._rpcRequest('getBalance', args);
|
|
2353
3115
|
const res = create(unsafeRes, jsonRpcResultAndContext(number()));
|
|
2354
3116
|
if ('error' in res) {
|
|
2355
|
-
throw new
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
': ' +
|
|
2359
|
-
res.error.message,
|
|
3117
|
+
throw new SolanaJSONRPCError(
|
|
3118
|
+
res.error,
|
|
3119
|
+
`failed to get balance for ${publicKey.toBase58()}`,
|
|
2360
3120
|
);
|
|
2361
3121
|
}
|
|
2362
3122
|
return res.result;
|
|
@@ -2367,9 +3127,9 @@ export class Connection {
|
|
|
2367
3127
|
*/
|
|
2368
3128
|
async getBalance(
|
|
2369
3129
|
publicKey: PublicKey,
|
|
2370
|
-
|
|
3130
|
+
commitmentOrConfig?: Commitment | GetBalanceConfig,
|
|
2371
3131
|
): Promise<number> {
|
|
2372
|
-
return await this.getBalanceAndContext(publicKey,
|
|
3132
|
+
return await this.getBalanceAndContext(publicKey, commitmentOrConfig)
|
|
2373
3133
|
.then(x => x.value)
|
|
2374
3134
|
.catch(e => {
|
|
2375
3135
|
throw new Error(
|
|
@@ -2385,8 +3145,9 @@ export class Connection {
|
|
|
2385
3145
|
const unsafeRes = await this._rpcRequest('getBlockTime', [slot]);
|
|
2386
3146
|
const res = create(unsafeRes, jsonRpcResult(nullable(number())));
|
|
2387
3147
|
if ('error' in res) {
|
|
2388
|
-
throw new
|
|
2389
|
-
|
|
3148
|
+
throw new SolanaJSONRPCError(
|
|
3149
|
+
res.error,
|
|
3150
|
+
`failed to get block time for slot ${slot}`,
|
|
2390
3151
|
);
|
|
2391
3152
|
}
|
|
2392
3153
|
return res.result;
|
|
@@ -2400,8 +3161,9 @@ export class Connection {
|
|
|
2400
3161
|
const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []);
|
|
2401
3162
|
const res = create(unsafeRes, jsonRpcResult(number()));
|
|
2402
3163
|
if ('error' in res) {
|
|
2403
|
-
throw new
|
|
2404
|
-
|
|
3164
|
+
throw new SolanaJSONRPCError(
|
|
3165
|
+
res.error,
|
|
3166
|
+
'failed to get minimum ledger slot',
|
|
2405
3167
|
);
|
|
2406
3168
|
}
|
|
2407
3169
|
return res.result;
|
|
@@ -2414,8 +3176,9 @@ export class Connection {
|
|
|
2414
3176
|
const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []);
|
|
2415
3177
|
const res = create(unsafeRes, SlotRpcResult);
|
|
2416
3178
|
if ('error' in res) {
|
|
2417
|
-
throw new
|
|
2418
|
-
|
|
3179
|
+
throw new SolanaJSONRPCError(
|
|
3180
|
+
res.error,
|
|
3181
|
+
'failed to get first available block',
|
|
2419
3182
|
);
|
|
2420
3183
|
}
|
|
2421
3184
|
return res.result;
|
|
@@ -2444,7 +3207,7 @@ export class Connection {
|
|
|
2444
3207
|
const unsafeRes = await this._rpcRequest('getSupply', [configArg]);
|
|
2445
3208
|
const res = create(unsafeRes, GetSupplyRpcResult);
|
|
2446
3209
|
if ('error' in res) {
|
|
2447
|
-
throw new
|
|
3210
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get supply');
|
|
2448
3211
|
}
|
|
2449
3212
|
return res.result;
|
|
2450
3213
|
}
|
|
@@ -2460,7 +3223,7 @@ export class Connection {
|
|
|
2460
3223
|
const unsafeRes = await this._rpcRequest('getTokenSupply', args);
|
|
2461
3224
|
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
|
|
2462
3225
|
if ('error' in res) {
|
|
2463
|
-
throw new
|
|
3226
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get token supply');
|
|
2464
3227
|
}
|
|
2465
3228
|
return res.result;
|
|
2466
3229
|
}
|
|
@@ -2476,8 +3239,9 @@ export class Connection {
|
|
|
2476
3239
|
const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args);
|
|
2477
3240
|
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
|
|
2478
3241
|
if ('error' in res) {
|
|
2479
|
-
throw new
|
|
2480
|
-
|
|
3242
|
+
throw new SolanaJSONRPCError(
|
|
3243
|
+
res.error,
|
|
3244
|
+
'failed to get token account balance',
|
|
2481
3245
|
);
|
|
2482
3246
|
}
|
|
2483
3247
|
return res.result;
|
|
@@ -2491,12 +3255,14 @@ export class Connection {
|
|
|
2491
3255
|
async getTokenAccountsByOwner(
|
|
2492
3256
|
ownerAddress: PublicKey,
|
|
2493
3257
|
filter: TokenAccountsFilter,
|
|
2494
|
-
|
|
3258
|
+
commitmentOrConfig?: Commitment | GetTokenAccountsByOwnerConfig,
|
|
2495
3259
|
): Promise<
|
|
2496
3260
|
RpcResponseAndContext<
|
|
2497
3261
|
Array<{pubkey: PublicKey; account: AccountInfo<Buffer>}>
|
|
2498
3262
|
>
|
|
2499
3263
|
> {
|
|
3264
|
+
const {commitment, config} =
|
|
3265
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
2500
3266
|
let _args: any[] = [ownerAddress.toBase58()];
|
|
2501
3267
|
if ('mint' in filter) {
|
|
2502
3268
|
_args.push({mint: filter.mint.toBase58()});
|
|
@@ -2504,15 +3270,13 @@ export class Connection {
|
|
|
2504
3270
|
_args.push({programId: filter.programId.toBase58()});
|
|
2505
3271
|
}
|
|
2506
3272
|
|
|
2507
|
-
const args = this._buildArgs(_args, commitment, 'base64');
|
|
3273
|
+
const args = this._buildArgs(_args, commitment, 'base64', config);
|
|
2508
3274
|
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
|
|
2509
3275
|
const res = create(unsafeRes, GetTokenAccountsByOwner);
|
|
2510
3276
|
if ('error' in res) {
|
|
2511
|
-
throw new
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
': ' +
|
|
2515
|
-
res.error.message,
|
|
3277
|
+
throw new SolanaJSONRPCError(
|
|
3278
|
+
res.error,
|
|
3279
|
+
`failed to get token accounts owned by account ${ownerAddress.toBase58()}`,
|
|
2516
3280
|
);
|
|
2517
3281
|
}
|
|
2518
3282
|
return res.result;
|
|
@@ -2543,11 +3307,9 @@ export class Connection {
|
|
|
2543
3307
|
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
|
|
2544
3308
|
const res = create(unsafeRes, GetParsedTokenAccountsByOwner);
|
|
2545
3309
|
if ('error' in res) {
|
|
2546
|
-
throw new
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
': ' +
|
|
2550
|
-
res.error.message,
|
|
3310
|
+
throw new SolanaJSONRPCError(
|
|
3311
|
+
res.error,
|
|
3312
|
+
`failed to get token accounts owned by account ${ownerAddress.toBase58()}`,
|
|
2551
3313
|
);
|
|
2552
3314
|
}
|
|
2553
3315
|
return res.result;
|
|
@@ -2567,7 +3329,7 @@ export class Connection {
|
|
|
2567
3329
|
const unsafeRes = await this._rpcRequest('getLargestAccounts', args);
|
|
2568
3330
|
const res = create(unsafeRes, GetLargestAccountsRpcResult);
|
|
2569
3331
|
if ('error' in res) {
|
|
2570
|
-
throw new
|
|
3332
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get largest accounts');
|
|
2571
3333
|
}
|
|
2572
3334
|
return res.result;
|
|
2573
3335
|
}
|
|
@@ -2584,8 +3346,9 @@ export class Connection {
|
|
|
2584
3346
|
const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args);
|
|
2585
3347
|
const res = create(unsafeRes, GetTokenLargestAccountsResult);
|
|
2586
3348
|
if ('error' in res) {
|
|
2587
|
-
throw new
|
|
2588
|
-
|
|
3349
|
+
throw new SolanaJSONRPCError(
|
|
3350
|
+
res.error,
|
|
3351
|
+
'failed to get token largest accounts',
|
|
2589
3352
|
);
|
|
2590
3353
|
}
|
|
2591
3354
|
return res.result;
|
|
@@ -2596,20 +3359,25 @@ export class Connection {
|
|
|
2596
3359
|
*/
|
|
2597
3360
|
async getAccountInfoAndContext(
|
|
2598
3361
|
publicKey: PublicKey,
|
|
2599
|
-
|
|
3362
|
+
commitmentOrConfig?: Commitment | GetAccountInfoConfig,
|
|
2600
3363
|
): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>> {
|
|
2601
|
-
const
|
|
3364
|
+
const {commitment, config} =
|
|
3365
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
3366
|
+
const args = this._buildArgs(
|
|
3367
|
+
[publicKey.toBase58()],
|
|
3368
|
+
commitment,
|
|
3369
|
+
'base64',
|
|
3370
|
+
config,
|
|
3371
|
+
);
|
|
2602
3372
|
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
|
|
2603
3373
|
const res = create(
|
|
2604
3374
|
unsafeRes,
|
|
2605
3375
|
jsonRpcResultAndContext(nullable(AccountInfoResult)),
|
|
2606
3376
|
);
|
|
2607
3377
|
if ('error' in res) {
|
|
2608
|
-
throw new
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
': ' +
|
|
2612
|
-
res.error.message,
|
|
3378
|
+
throw new SolanaJSONRPCError(
|
|
3379
|
+
res.error,
|
|
3380
|
+
`failed to get info about account ${publicKey.toBase58()}`,
|
|
2613
3381
|
);
|
|
2614
3382
|
}
|
|
2615
3383
|
return res.result;
|
|
@@ -2620,14 +3388,17 @@ export class Connection {
|
|
|
2620
3388
|
*/
|
|
2621
3389
|
async getParsedAccountInfo(
|
|
2622
3390
|
publicKey: PublicKey,
|
|
2623
|
-
|
|
3391
|
+
commitmentOrConfig?: Commitment | GetAccountInfoConfig,
|
|
2624
3392
|
): Promise<
|
|
2625
3393
|
RpcResponseAndContext<AccountInfo<Buffer | ParsedAccountData> | null>
|
|
2626
3394
|
> {
|
|
3395
|
+
const {commitment, config} =
|
|
3396
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
2627
3397
|
const args = this._buildArgs(
|
|
2628
3398
|
[publicKey.toBase58()],
|
|
2629
3399
|
commitment,
|
|
2630
3400
|
'jsonParsed',
|
|
3401
|
+
config,
|
|
2631
3402
|
);
|
|
2632
3403
|
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
|
|
2633
3404
|
const res = create(
|
|
@@ -2635,11 +3406,9 @@ export class Connection {
|
|
|
2635
3406
|
jsonRpcResultAndContext(nullable(ParsedAccountInfoResult)),
|
|
2636
3407
|
);
|
|
2637
3408
|
if ('error' in res) {
|
|
2638
|
-
throw new
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
': ' +
|
|
2642
|
-
res.error.message,
|
|
3409
|
+
throw new SolanaJSONRPCError(
|
|
3410
|
+
res.error,
|
|
3411
|
+
`failed to get info about account ${publicKey.toBase58()}`,
|
|
2643
3412
|
);
|
|
2644
3413
|
}
|
|
2645
3414
|
return res.result;
|
|
@@ -2650,10 +3419,13 @@ export class Connection {
|
|
|
2650
3419
|
*/
|
|
2651
3420
|
async getAccountInfo(
|
|
2652
3421
|
publicKey: PublicKey,
|
|
2653
|
-
|
|
3422
|
+
commitmentOrConfig?: Commitment | GetAccountInfoConfig,
|
|
2654
3423
|
): Promise<AccountInfo<Buffer> | null> {
|
|
2655
3424
|
try {
|
|
2656
|
-
const res = await this.getAccountInfoAndContext(
|
|
3425
|
+
const res = await this.getAccountInfoAndContext(
|
|
3426
|
+
publicKey,
|
|
3427
|
+
commitmentOrConfig,
|
|
3428
|
+
);
|
|
2657
3429
|
return res.value;
|
|
2658
3430
|
} catch (e) {
|
|
2659
3431
|
throw new Error(
|
|
@@ -2662,23 +3434,52 @@ export class Connection {
|
|
|
2662
3434
|
}
|
|
2663
3435
|
}
|
|
2664
3436
|
|
|
3437
|
+
/**
|
|
3438
|
+
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
|
|
3439
|
+
*/
|
|
3440
|
+
async getMultipleParsedAccounts(
|
|
3441
|
+
publicKeys: PublicKey[],
|
|
3442
|
+
rawConfig?: GetMultipleAccountsConfig,
|
|
3443
|
+
): Promise<
|
|
3444
|
+
RpcResponseAndContext<(AccountInfo<Buffer | ParsedAccountData> | null)[]>
|
|
3445
|
+
> {
|
|
3446
|
+
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
|
3447
|
+
const keys = publicKeys.map(key => key.toBase58());
|
|
3448
|
+
const args = this._buildArgs([keys], commitment, 'jsonParsed', config);
|
|
3449
|
+
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
|
|
3450
|
+
const res = create(
|
|
3451
|
+
unsafeRes,
|
|
3452
|
+
jsonRpcResultAndContext(array(nullable(ParsedAccountInfoResult))),
|
|
3453
|
+
);
|
|
3454
|
+
if ('error' in res) {
|
|
3455
|
+
throw new SolanaJSONRPCError(
|
|
3456
|
+
res.error,
|
|
3457
|
+
`failed to get info for accounts ${keys}`,
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
return res.result;
|
|
3461
|
+
}
|
|
3462
|
+
|
|
2665
3463
|
/**
|
|
2666
3464
|
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
|
|
2667
3465
|
*/
|
|
2668
3466
|
async getMultipleAccountsInfoAndContext(
|
|
2669
3467
|
publicKeys: PublicKey[],
|
|
2670
|
-
|
|
3468
|
+
commitmentOrConfig?: Commitment | GetMultipleAccountsConfig,
|
|
2671
3469
|
): Promise<RpcResponseAndContext<(AccountInfo<Buffer> | null)[]>> {
|
|
3470
|
+
const {commitment, config} =
|
|
3471
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
2672
3472
|
const keys = publicKeys.map(key => key.toBase58());
|
|
2673
|
-
const args = this._buildArgs([keys], commitment, 'base64');
|
|
3473
|
+
const args = this._buildArgs([keys], commitment, 'base64', config);
|
|
2674
3474
|
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
|
|
2675
3475
|
const res = create(
|
|
2676
3476
|
unsafeRes,
|
|
2677
3477
|
jsonRpcResultAndContext(array(nullable(AccountInfoResult))),
|
|
2678
3478
|
);
|
|
2679
3479
|
if ('error' in res) {
|
|
2680
|
-
throw new
|
|
2681
|
-
|
|
3480
|
+
throw new SolanaJSONRPCError(
|
|
3481
|
+
res.error,
|
|
3482
|
+
`failed to get info for accounts ${keys}`,
|
|
2682
3483
|
);
|
|
2683
3484
|
}
|
|
2684
3485
|
return res.result;
|
|
@@ -2689,11 +3490,11 @@ export class Connection {
|
|
|
2689
3490
|
*/
|
|
2690
3491
|
async getMultipleAccountsInfo(
|
|
2691
3492
|
publicKeys: PublicKey[],
|
|
2692
|
-
|
|
3493
|
+
commitmentOrConfig?: Commitment | GetMultipleAccountsConfig,
|
|
2693
3494
|
): Promise<(AccountInfo<Buffer> | null)[]> {
|
|
2694
3495
|
const res = await this.getMultipleAccountsInfoAndContext(
|
|
2695
3496
|
publicKeys,
|
|
2696
|
-
|
|
3497
|
+
commitmentOrConfig,
|
|
2697
3498
|
);
|
|
2698
3499
|
return res.value;
|
|
2699
3500
|
}
|
|
@@ -2703,23 +3504,27 @@ export class Connection {
|
|
|
2703
3504
|
*/
|
|
2704
3505
|
async getStakeActivation(
|
|
2705
3506
|
publicKey: PublicKey,
|
|
2706
|
-
|
|
3507
|
+
commitmentOrConfig?: Commitment | GetStakeActivationConfig,
|
|
2707
3508
|
epoch?: number,
|
|
2708
3509
|
): Promise<StakeActivationData> {
|
|
3510
|
+
const {commitment, config} =
|
|
3511
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
2709
3512
|
const args = this._buildArgs(
|
|
2710
3513
|
[publicKey.toBase58()],
|
|
2711
3514
|
commitment,
|
|
2712
|
-
undefined
|
|
2713
|
-
|
|
3515
|
+
undefined /* encoding */,
|
|
3516
|
+
{
|
|
3517
|
+
...config,
|
|
3518
|
+
epoch: epoch != null ? epoch : config?.epoch,
|
|
3519
|
+
},
|
|
2714
3520
|
);
|
|
2715
3521
|
|
|
2716
3522
|
const unsafeRes = await this._rpcRequest('getStakeActivation', args);
|
|
2717
3523
|
const res = create(unsafeRes, jsonRpcResult(StakeActivationResult));
|
|
2718
3524
|
if ('error' in res) {
|
|
2719
|
-
throw new
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
}`,
|
|
3525
|
+
throw new SolanaJSONRPCError(
|
|
3526
|
+
res.error,
|
|
3527
|
+
`failed to get Stake Activation ${publicKey.toBase58()}`,
|
|
2723
3528
|
);
|
|
2724
3529
|
}
|
|
2725
3530
|
return res.result;
|
|
@@ -2734,40 +3539,21 @@ export class Connection {
|
|
|
2734
3539
|
programId: PublicKey,
|
|
2735
3540
|
configOrCommitment?: GetProgramAccountsConfig | Commitment,
|
|
2736
3541
|
): Promise<Array<{pubkey: PublicKey; account: AccountInfo<Buffer>}>> {
|
|
2737
|
-
const
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
let encoding;
|
|
2741
|
-
if (configOrCommitment) {
|
|
2742
|
-
if (typeof configOrCommitment === 'string') {
|
|
2743
|
-
commitment = configOrCommitment;
|
|
2744
|
-
} else {
|
|
2745
|
-
commitment = configOrCommitment.commitment;
|
|
2746
|
-
encoding = configOrCommitment.encoding;
|
|
2747
|
-
|
|
2748
|
-
if (configOrCommitment.dataSlice) {
|
|
2749
|
-
extra.dataSlice = configOrCommitment.dataSlice;
|
|
2750
|
-
}
|
|
2751
|
-
if (configOrCommitment.filters) {
|
|
2752
|
-
extra.filters = configOrCommitment.filters;
|
|
2753
|
-
}
|
|
2754
|
-
}
|
|
2755
|
-
}
|
|
2756
|
-
|
|
3542
|
+
const {commitment, config} =
|
|
3543
|
+
extractCommitmentFromConfig(configOrCommitment);
|
|
3544
|
+
const {encoding, ...configWithoutEncoding} = config || {};
|
|
2757
3545
|
const args = this._buildArgs(
|
|
2758
3546
|
[programId.toBase58()],
|
|
2759
3547
|
commitment,
|
|
2760
3548
|
encoding || 'base64',
|
|
2761
|
-
|
|
3549
|
+
configWithoutEncoding,
|
|
2762
3550
|
);
|
|
2763
3551
|
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
|
|
2764
3552
|
const res = create(unsafeRes, jsonRpcResult(array(KeyedAccountInfoResult)));
|
|
2765
3553
|
if ('error' in res) {
|
|
2766
|
-
throw new
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
': ' +
|
|
2770
|
-
res.error.message,
|
|
3554
|
+
throw new SolanaJSONRPCError(
|
|
3555
|
+
res.error,
|
|
3556
|
+
`failed to get accounts owned by program ${programId.toBase58()}`,
|
|
2771
3557
|
);
|
|
2772
3558
|
}
|
|
2773
3559
|
return res.result;
|
|
@@ -2787,26 +3573,13 @@ export class Connection {
|
|
|
2787
3573
|
account: AccountInfo<Buffer | ParsedAccountData>;
|
|
2788
3574
|
}>
|
|
2789
3575
|
> {
|
|
2790
|
-
const
|
|
2791
|
-
|
|
2792
|
-
let commitment;
|
|
2793
|
-
if (configOrCommitment) {
|
|
2794
|
-
if (typeof configOrCommitment === 'string') {
|
|
2795
|
-
commitment = configOrCommitment;
|
|
2796
|
-
} else {
|
|
2797
|
-
commitment = configOrCommitment.commitment;
|
|
2798
|
-
|
|
2799
|
-
if (configOrCommitment.filters) {
|
|
2800
|
-
extra.filters = configOrCommitment.filters;
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
|
|
3576
|
+
const {commitment, config} =
|
|
3577
|
+
extractCommitmentFromConfig(configOrCommitment);
|
|
2805
3578
|
const args = this._buildArgs(
|
|
2806
3579
|
[programId.toBase58()],
|
|
2807
3580
|
commitment,
|
|
2808
3581
|
'jsonParsed',
|
|
2809
|
-
|
|
3582
|
+
config,
|
|
2810
3583
|
);
|
|
2811
3584
|
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
|
|
2812
3585
|
const res = create(
|
|
@@ -2814,90 +3587,460 @@ export class Connection {
|
|
|
2814
3587
|
jsonRpcResult(array(KeyedParsedAccountInfoResult)),
|
|
2815
3588
|
);
|
|
2816
3589
|
if ('error' in res) {
|
|
2817
|
-
throw new
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
': ' +
|
|
2821
|
-
res.error.message,
|
|
3590
|
+
throw new SolanaJSONRPCError(
|
|
3591
|
+
res.error,
|
|
3592
|
+
`failed to get accounts owned by program ${programId.toBase58()}`,
|
|
2822
3593
|
);
|
|
2823
3594
|
}
|
|
2824
3595
|
return res.result;
|
|
2825
3596
|
}
|
|
2826
3597
|
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
3598
|
+
confirmTransaction(
|
|
3599
|
+
strategy:
|
|
3600
|
+
| BlockheightBasedTransactionConfirmationStrategy
|
|
3601
|
+
| DurableNonceTransactionConfirmationStrategy,
|
|
3602
|
+
commitment?: Commitment,
|
|
3603
|
+
): Promise<RpcResponseAndContext<SignatureResult>>;
|
|
3604
|
+
|
|
3605
|
+
/** @deprecated Instead, call `confirmTransaction` using a `TransactionConfirmationConfig` */
|
|
3606
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
3607
|
+
confirmTransaction(
|
|
3608
|
+
strategy: TransactionSignature,
|
|
3609
|
+
commitment?: Commitment,
|
|
3610
|
+
): Promise<RpcResponseAndContext<SignatureResult>>;
|
|
3611
|
+
|
|
3612
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
2830
3613
|
async confirmTransaction(
|
|
2831
|
-
|
|
3614
|
+
strategy:
|
|
3615
|
+
| BlockheightBasedTransactionConfirmationStrategy
|
|
3616
|
+
| DurableNonceTransactionConfirmationStrategy
|
|
3617
|
+
| TransactionSignature,
|
|
2832
3618
|
commitment?: Commitment,
|
|
2833
3619
|
): Promise<RpcResponseAndContext<SignatureResult>> {
|
|
3620
|
+
let rawSignature: string;
|
|
3621
|
+
|
|
3622
|
+
if (typeof strategy == 'string') {
|
|
3623
|
+
rawSignature = strategy;
|
|
3624
|
+
} else {
|
|
3625
|
+
const config = strategy as
|
|
3626
|
+
| BlockheightBasedTransactionConfirmationStrategy
|
|
3627
|
+
| DurableNonceTransactionConfirmationStrategy;
|
|
3628
|
+
if (config.abortSignal?.aborted) {
|
|
3629
|
+
return Promise.reject(config.abortSignal.reason);
|
|
3630
|
+
}
|
|
3631
|
+
rawSignature = config.signature;
|
|
3632
|
+
}
|
|
3633
|
+
|
|
2834
3634
|
let decodedSignature;
|
|
3635
|
+
|
|
2835
3636
|
try {
|
|
2836
|
-
decodedSignature = bs58.decode(
|
|
3637
|
+
decodedSignature = bs58.decode(rawSignature);
|
|
2837
3638
|
} catch (err) {
|
|
2838
|
-
throw new Error('signature must be base58 encoded: ' +
|
|
3639
|
+
throw new Error('signature must be base58 encoded: ' + rawSignature);
|
|
2839
3640
|
}
|
|
2840
3641
|
|
|
2841
3642
|
assert(decodedSignature.length === 64, 'signature has invalid length');
|
|
2842
3643
|
|
|
2843
|
-
|
|
2844
|
-
|
|
3644
|
+
if (typeof strategy === 'string') {
|
|
3645
|
+
return await this.confirmTransactionUsingLegacyTimeoutStrategy({
|
|
3646
|
+
commitment: commitment || this.commitment,
|
|
3647
|
+
signature: rawSignature,
|
|
3648
|
+
});
|
|
3649
|
+
} else if ('lastValidBlockHeight' in strategy) {
|
|
3650
|
+
return await this.confirmTransactionUsingBlockHeightExceedanceStrategy({
|
|
3651
|
+
commitment: commitment || this.commitment,
|
|
3652
|
+
strategy,
|
|
3653
|
+
});
|
|
3654
|
+
} else {
|
|
3655
|
+
return await this.confirmTransactionUsingDurableNonceStrategy({
|
|
3656
|
+
commitment: commitment || this.commitment,
|
|
3657
|
+
strategy,
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
private getCancellationPromise(signal?: AbortSignal): Promise<never> {
|
|
3663
|
+
return new Promise<never>((_, reject) => {
|
|
3664
|
+
if (signal == null) {
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
if (signal.aborted) {
|
|
3668
|
+
reject(signal.reason);
|
|
3669
|
+
} else {
|
|
3670
|
+
signal.addEventListener('abort', () => {
|
|
3671
|
+
reject(signal.reason);
|
|
3672
|
+
});
|
|
3673
|
+
}
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
2845
3676
|
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
3677
|
+
private getTransactionConfirmationPromise({
|
|
3678
|
+
commitment,
|
|
3679
|
+
signature,
|
|
3680
|
+
}: {
|
|
3681
|
+
commitment?: Commitment;
|
|
3682
|
+
signature: string;
|
|
3683
|
+
}): {
|
|
3684
|
+
abortConfirmation(): void;
|
|
3685
|
+
confirmationPromise: Promise<{
|
|
3686
|
+
__type: TransactionStatus.PROCESSED;
|
|
3687
|
+
response: RpcResponseAndContext<SignatureResult>;
|
|
3688
|
+
}>;
|
|
3689
|
+
} {
|
|
3690
|
+
let signatureSubscriptionId: number | undefined;
|
|
3691
|
+
let disposeSignatureSubscriptionStateChangeObserver:
|
|
3692
|
+
| SubscriptionStateChangeDisposeFn
|
|
3693
|
+
| undefined;
|
|
3694
|
+
let done = false;
|
|
3695
|
+
const confirmationPromise = new Promise<{
|
|
3696
|
+
__type: TransactionStatus.PROCESSED;
|
|
3697
|
+
response: RpcResponseAndContext<SignatureResult>;
|
|
3698
|
+
}>((resolve, reject) => {
|
|
2849
3699
|
try {
|
|
2850
|
-
|
|
3700
|
+
signatureSubscriptionId = this.onSignature(
|
|
2851
3701
|
signature,
|
|
2852
3702
|
(result: SignatureResult, context: Context) => {
|
|
2853
|
-
|
|
2854
|
-
response = {
|
|
3703
|
+
signatureSubscriptionId = undefined;
|
|
3704
|
+
const response = {
|
|
2855
3705
|
context,
|
|
2856
3706
|
value: result,
|
|
2857
3707
|
};
|
|
2858
|
-
resolve(
|
|
3708
|
+
resolve({__type: TransactionStatus.PROCESSED, response});
|
|
3709
|
+
},
|
|
3710
|
+
commitment,
|
|
3711
|
+
);
|
|
3712
|
+
const subscriptionSetupPromise = new Promise<void>(
|
|
3713
|
+
resolveSubscriptionSetup => {
|
|
3714
|
+
if (signatureSubscriptionId == null) {
|
|
3715
|
+
resolveSubscriptionSetup();
|
|
3716
|
+
} else {
|
|
3717
|
+
disposeSignatureSubscriptionStateChangeObserver =
|
|
3718
|
+
this._onSubscriptionStateChange(
|
|
3719
|
+
signatureSubscriptionId,
|
|
3720
|
+
nextState => {
|
|
3721
|
+
if (nextState === 'subscribed') {
|
|
3722
|
+
resolveSubscriptionSetup();
|
|
3723
|
+
}
|
|
3724
|
+
},
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
2859
3727
|
},
|
|
2860
|
-
subscriptionCommitment,
|
|
2861
3728
|
);
|
|
3729
|
+
(async () => {
|
|
3730
|
+
await subscriptionSetupPromise;
|
|
3731
|
+
if (done) return;
|
|
3732
|
+
const response = await this.getSignatureStatus(signature);
|
|
3733
|
+
if (done) return;
|
|
3734
|
+
if (response == null) {
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
const {context, value} = response;
|
|
3738
|
+
if (value == null) {
|
|
3739
|
+
return;
|
|
3740
|
+
}
|
|
3741
|
+
if (value?.err) {
|
|
3742
|
+
reject(value.err);
|
|
3743
|
+
} else {
|
|
3744
|
+
switch (commitment) {
|
|
3745
|
+
case 'confirmed':
|
|
3746
|
+
case 'single':
|
|
3747
|
+
case 'singleGossip': {
|
|
3748
|
+
if (value.confirmationStatus === 'processed') {
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3751
|
+
break;
|
|
3752
|
+
}
|
|
3753
|
+
case 'finalized':
|
|
3754
|
+
case 'max':
|
|
3755
|
+
case 'root': {
|
|
3756
|
+
if (
|
|
3757
|
+
value.confirmationStatus === 'processed' ||
|
|
3758
|
+
value.confirmationStatus === 'confirmed'
|
|
3759
|
+
) {
|
|
3760
|
+
return;
|
|
3761
|
+
}
|
|
3762
|
+
break;
|
|
3763
|
+
}
|
|
3764
|
+
// exhaust enums to ensure full coverage
|
|
3765
|
+
case 'processed':
|
|
3766
|
+
case 'recent':
|
|
3767
|
+
}
|
|
3768
|
+
done = true;
|
|
3769
|
+
resolve({
|
|
3770
|
+
__type: TransactionStatus.PROCESSED,
|
|
3771
|
+
response: {
|
|
3772
|
+
context,
|
|
3773
|
+
value,
|
|
3774
|
+
},
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
})();
|
|
2862
3778
|
} catch (err) {
|
|
2863
3779
|
reject(err);
|
|
2864
3780
|
}
|
|
2865
3781
|
});
|
|
3782
|
+
const abortConfirmation = () => {
|
|
3783
|
+
if (disposeSignatureSubscriptionStateChangeObserver) {
|
|
3784
|
+
disposeSignatureSubscriptionStateChangeObserver();
|
|
3785
|
+
disposeSignatureSubscriptionStateChangeObserver = undefined;
|
|
3786
|
+
}
|
|
3787
|
+
if (signatureSubscriptionId != null) {
|
|
3788
|
+
this.removeSignatureListener(signatureSubscriptionId);
|
|
3789
|
+
signatureSubscriptionId = undefined;
|
|
3790
|
+
}
|
|
3791
|
+
};
|
|
3792
|
+
return {abortConfirmation, confirmationPromise};
|
|
3793
|
+
}
|
|
2866
3794
|
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
3795
|
+
private async confirmTransactionUsingBlockHeightExceedanceStrategy({
|
|
3796
|
+
commitment,
|
|
3797
|
+
strategy: {abortSignal, lastValidBlockHeight, signature},
|
|
3798
|
+
}: {
|
|
3799
|
+
commitment?: Commitment;
|
|
3800
|
+
strategy: BlockheightBasedTransactionConfirmationStrategy;
|
|
3801
|
+
}) {
|
|
3802
|
+
let done: boolean = false;
|
|
3803
|
+
const expiryPromise = new Promise<{
|
|
3804
|
+
__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED;
|
|
3805
|
+
}>(resolve => {
|
|
3806
|
+
const checkBlockHeight = async () => {
|
|
3807
|
+
try {
|
|
3808
|
+
const blockHeight = await this.getBlockHeight(commitment);
|
|
3809
|
+
return blockHeight;
|
|
3810
|
+
} catch (_e) {
|
|
3811
|
+
return -1;
|
|
3812
|
+
}
|
|
3813
|
+
};
|
|
3814
|
+
(async () => {
|
|
3815
|
+
let currentBlockHeight = await checkBlockHeight();
|
|
3816
|
+
if (done) return;
|
|
3817
|
+
while (currentBlockHeight <= lastValidBlockHeight) {
|
|
3818
|
+
await sleep(1000);
|
|
3819
|
+
if (done) return;
|
|
3820
|
+
currentBlockHeight = await checkBlockHeight();
|
|
3821
|
+
if (done) return;
|
|
3822
|
+
}
|
|
3823
|
+
resolve({__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED});
|
|
3824
|
+
})();
|
|
3825
|
+
});
|
|
3826
|
+
const {abortConfirmation, confirmationPromise} =
|
|
3827
|
+
this.getTransactionConfirmationPromise({commitment, signature});
|
|
3828
|
+
const cancellationPromise = this.getCancellationPromise(abortSignal);
|
|
3829
|
+
let result: RpcResponseAndContext<SignatureResult>;
|
|
3830
|
+
try {
|
|
3831
|
+
const outcome = await Promise.race([
|
|
3832
|
+
cancellationPromise,
|
|
3833
|
+
confirmationPromise,
|
|
3834
|
+
expiryPromise,
|
|
3835
|
+
]);
|
|
3836
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
3837
|
+
result = outcome.response;
|
|
3838
|
+
} else {
|
|
3839
|
+
throw new TransactionExpiredBlockheightExceededError(signature);
|
|
2876
3840
|
}
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
case 'root':
|
|
3841
|
+
} finally {
|
|
3842
|
+
done = true;
|
|
3843
|
+
abortConfirmation();
|
|
2881
3844
|
}
|
|
3845
|
+
return result;
|
|
3846
|
+
}
|
|
2882
3847
|
|
|
3848
|
+
private async confirmTransactionUsingDurableNonceStrategy({
|
|
3849
|
+
commitment,
|
|
3850
|
+
strategy: {
|
|
3851
|
+
abortSignal,
|
|
3852
|
+
minContextSlot,
|
|
3853
|
+
nonceAccountPubkey,
|
|
3854
|
+
nonceValue,
|
|
3855
|
+
signature,
|
|
3856
|
+
},
|
|
3857
|
+
}: {
|
|
3858
|
+
commitment?: Commitment;
|
|
3859
|
+
strategy: DurableNonceTransactionConfirmationStrategy;
|
|
3860
|
+
}) {
|
|
3861
|
+
let done: boolean = false;
|
|
3862
|
+
const expiryPromise = new Promise<{
|
|
3863
|
+
__type: TransactionStatus.NONCE_INVALID;
|
|
3864
|
+
slotInWhichNonceDidAdvance: number | null;
|
|
3865
|
+
}>(resolve => {
|
|
3866
|
+
let currentNonceValue: string | undefined = nonceValue;
|
|
3867
|
+
let lastCheckedSlot: number | null = null;
|
|
3868
|
+
const getCurrentNonceValue = async () => {
|
|
3869
|
+
try {
|
|
3870
|
+
const {context, value: nonceAccount} = await this.getNonceAndContext(
|
|
3871
|
+
nonceAccountPubkey,
|
|
3872
|
+
{
|
|
3873
|
+
commitment,
|
|
3874
|
+
minContextSlot,
|
|
3875
|
+
},
|
|
3876
|
+
);
|
|
3877
|
+
lastCheckedSlot = context.slot;
|
|
3878
|
+
return nonceAccount?.nonce;
|
|
3879
|
+
} catch (e) {
|
|
3880
|
+
// If for whatever reason we can't reach/read the nonce
|
|
3881
|
+
// account, just keep using the last-known value.
|
|
3882
|
+
return currentNonceValue;
|
|
3883
|
+
}
|
|
3884
|
+
};
|
|
3885
|
+
(async () => {
|
|
3886
|
+
currentNonceValue = await getCurrentNonceValue();
|
|
3887
|
+
if (done) return;
|
|
3888
|
+
while (
|
|
3889
|
+
true // eslint-disable-line no-constant-condition
|
|
3890
|
+
) {
|
|
3891
|
+
if (nonceValue !== currentNonceValue) {
|
|
3892
|
+
resolve({
|
|
3893
|
+
__type: TransactionStatus.NONCE_INVALID,
|
|
3894
|
+
slotInWhichNonceDidAdvance: lastCheckedSlot,
|
|
3895
|
+
});
|
|
3896
|
+
return;
|
|
3897
|
+
}
|
|
3898
|
+
await sleep(2000);
|
|
3899
|
+
if (done) return;
|
|
3900
|
+
currentNonceValue = await getCurrentNonceValue();
|
|
3901
|
+
if (done) return;
|
|
3902
|
+
}
|
|
3903
|
+
})();
|
|
3904
|
+
});
|
|
3905
|
+
const {abortConfirmation, confirmationPromise} =
|
|
3906
|
+
this.getTransactionConfirmationPromise({commitment, signature});
|
|
3907
|
+
const cancellationPromise = this.getCancellationPromise(abortSignal);
|
|
3908
|
+
let result: RpcResponseAndContext<SignatureResult>;
|
|
2883
3909
|
try {
|
|
2884
|
-
await
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3910
|
+
const outcome = await Promise.race([
|
|
3911
|
+
cancellationPromise,
|
|
3912
|
+
confirmationPromise,
|
|
3913
|
+
expiryPromise,
|
|
3914
|
+
]);
|
|
3915
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
3916
|
+
result = outcome.response;
|
|
3917
|
+
} else {
|
|
3918
|
+
// Double check that the transaction is indeed unconfirmed.
|
|
3919
|
+
let signatureStatus:
|
|
3920
|
+
| RpcResponseAndContext<SignatureStatus | null>
|
|
3921
|
+
| null
|
|
3922
|
+
| undefined;
|
|
3923
|
+
while (
|
|
3924
|
+
true // eslint-disable-line no-constant-condition
|
|
3925
|
+
) {
|
|
3926
|
+
const status = await this.getSignatureStatus(signature);
|
|
3927
|
+
if (status == null) {
|
|
3928
|
+
break;
|
|
3929
|
+
}
|
|
3930
|
+
if (
|
|
3931
|
+
status.context.slot <
|
|
3932
|
+
(outcome.slotInWhichNonceDidAdvance ?? minContextSlot)
|
|
3933
|
+
) {
|
|
3934
|
+
await sleep(400);
|
|
3935
|
+
continue;
|
|
3936
|
+
}
|
|
3937
|
+
signatureStatus = status;
|
|
3938
|
+
break;
|
|
3939
|
+
}
|
|
3940
|
+
if (signatureStatus?.value) {
|
|
3941
|
+
const commitmentForStatus = commitment || 'finalized';
|
|
3942
|
+
const {confirmationStatus} = signatureStatus.value;
|
|
3943
|
+
switch (commitmentForStatus) {
|
|
3944
|
+
case 'processed':
|
|
3945
|
+
case 'recent':
|
|
3946
|
+
if (
|
|
3947
|
+
confirmationStatus !== 'processed' &&
|
|
3948
|
+
confirmationStatus !== 'confirmed' &&
|
|
3949
|
+
confirmationStatus !== 'finalized'
|
|
3950
|
+
) {
|
|
3951
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3952
|
+
}
|
|
3953
|
+
break;
|
|
3954
|
+
case 'confirmed':
|
|
3955
|
+
case 'single':
|
|
3956
|
+
case 'singleGossip':
|
|
3957
|
+
if (
|
|
3958
|
+
confirmationStatus !== 'confirmed' &&
|
|
3959
|
+
confirmationStatus !== 'finalized'
|
|
3960
|
+
) {
|
|
3961
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3962
|
+
}
|
|
3963
|
+
break;
|
|
3964
|
+
case 'finalized':
|
|
3965
|
+
case 'max':
|
|
3966
|
+
case 'root':
|
|
3967
|
+
if (confirmationStatus !== 'finalized') {
|
|
3968
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3969
|
+
}
|
|
3970
|
+
break;
|
|
3971
|
+
default:
|
|
3972
|
+
// Exhaustive switch.
|
|
3973
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3974
|
+
((_: never) => {})(commitmentForStatus);
|
|
3975
|
+
}
|
|
3976
|
+
result = {
|
|
3977
|
+
context: signatureStatus.context,
|
|
3978
|
+
value: {err: signatureStatus.value.err},
|
|
3979
|
+
};
|
|
3980
|
+
} else {
|
|
3981
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3982
|
+
}
|
|
2888
3983
|
}
|
|
3984
|
+
} finally {
|
|
3985
|
+
done = true;
|
|
3986
|
+
abortConfirmation();
|
|
2889
3987
|
}
|
|
3988
|
+
return result;
|
|
3989
|
+
}
|
|
2890
3990
|
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3991
|
+
private async confirmTransactionUsingLegacyTimeoutStrategy({
|
|
3992
|
+
commitment,
|
|
3993
|
+
signature,
|
|
3994
|
+
}: {
|
|
3995
|
+
commitment?: Commitment;
|
|
3996
|
+
signature: string;
|
|
3997
|
+
}) {
|
|
3998
|
+
let timeoutId;
|
|
3999
|
+
const expiryPromise = new Promise<{
|
|
4000
|
+
__type: TransactionStatus.TIMED_OUT;
|
|
4001
|
+
timeoutMs: number;
|
|
4002
|
+
}>(resolve => {
|
|
4003
|
+
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
|
4004
|
+
switch (commitment) {
|
|
4005
|
+
case 'processed':
|
|
4006
|
+
case 'recent':
|
|
4007
|
+
case 'single':
|
|
4008
|
+
case 'confirmed':
|
|
4009
|
+
case 'singleGossip': {
|
|
4010
|
+
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
|
4011
|
+
break;
|
|
4012
|
+
}
|
|
4013
|
+
// exhaust enums to ensure full coverage
|
|
4014
|
+
case 'finalized':
|
|
4015
|
+
case 'max':
|
|
4016
|
+
case 'root':
|
|
4017
|
+
}
|
|
4018
|
+
timeoutId = setTimeout(
|
|
4019
|
+
() => resolve({__type: TransactionStatus.TIMED_OUT, timeoutMs}),
|
|
4020
|
+
timeoutMs,
|
|
2897
4021
|
);
|
|
4022
|
+
});
|
|
4023
|
+
const {abortConfirmation, confirmationPromise} =
|
|
4024
|
+
this.getTransactionConfirmationPromise({
|
|
4025
|
+
commitment,
|
|
4026
|
+
signature,
|
|
4027
|
+
});
|
|
4028
|
+
let result: RpcResponseAndContext<SignatureResult>;
|
|
4029
|
+
try {
|
|
4030
|
+
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
4031
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
4032
|
+
result = outcome.response;
|
|
4033
|
+
} else {
|
|
4034
|
+
throw new TransactionExpiredTimeoutError(
|
|
4035
|
+
signature,
|
|
4036
|
+
outcome.timeoutMs / 1000,
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
} finally {
|
|
4040
|
+
clearTimeout(timeoutId);
|
|
4041
|
+
abortConfirmation();
|
|
2898
4042
|
}
|
|
2899
|
-
|
|
2900
|
-
return response;
|
|
4043
|
+
return result;
|
|
2901
4044
|
}
|
|
2902
4045
|
|
|
2903
4046
|
/**
|
|
@@ -2907,7 +4050,7 @@ export class Connection {
|
|
|
2907
4050
|
const unsafeRes = await this._rpcRequest('getClusterNodes', []);
|
|
2908
4051
|
const res = create(unsafeRes, jsonRpcResult(array(ContactInfoResult)));
|
|
2909
4052
|
if ('error' in res) {
|
|
2910
|
-
throw new
|
|
4053
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get cluster nodes');
|
|
2911
4054
|
}
|
|
2912
4055
|
return res.result;
|
|
2913
4056
|
}
|
|
@@ -2920,7 +4063,7 @@ export class Connection {
|
|
|
2920
4063
|
const unsafeRes = await this._rpcRequest('getVoteAccounts', args);
|
|
2921
4064
|
const res = create(unsafeRes, GetVoteAccounts);
|
|
2922
4065
|
if ('error' in res) {
|
|
2923
|
-
throw new
|
|
4066
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get vote accounts');
|
|
2924
4067
|
}
|
|
2925
4068
|
return res.result;
|
|
2926
4069
|
}
|
|
@@ -2928,12 +4071,21 @@ export class Connection {
|
|
|
2928
4071
|
/**
|
|
2929
4072
|
* Fetch the current slot that the node is processing
|
|
2930
4073
|
*/
|
|
2931
|
-
async getSlot(
|
|
2932
|
-
|
|
4074
|
+
async getSlot(
|
|
4075
|
+
commitmentOrConfig?: Commitment | GetSlotConfig,
|
|
4076
|
+
): Promise<number> {
|
|
4077
|
+
const {commitment, config} =
|
|
4078
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4079
|
+
const args = this._buildArgs(
|
|
4080
|
+
[],
|
|
4081
|
+
commitment,
|
|
4082
|
+
undefined /* encoding */,
|
|
4083
|
+
config,
|
|
4084
|
+
);
|
|
2933
4085
|
const unsafeRes = await this._rpcRequest('getSlot', args);
|
|
2934
4086
|
const res = create(unsafeRes, jsonRpcResult(number()));
|
|
2935
4087
|
if ('error' in res) {
|
|
2936
|
-
throw new
|
|
4088
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get slot');
|
|
2937
4089
|
}
|
|
2938
4090
|
return res.result;
|
|
2939
4091
|
}
|
|
@@ -2941,12 +4093,21 @@ export class Connection {
|
|
|
2941
4093
|
/**
|
|
2942
4094
|
* Fetch the current slot leader of the cluster
|
|
2943
4095
|
*/
|
|
2944
|
-
async getSlotLeader(
|
|
2945
|
-
|
|
4096
|
+
async getSlotLeader(
|
|
4097
|
+
commitmentOrConfig?: Commitment | GetSlotLeaderConfig,
|
|
4098
|
+
): Promise<string> {
|
|
4099
|
+
const {commitment, config} =
|
|
4100
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4101
|
+
const args = this._buildArgs(
|
|
4102
|
+
[],
|
|
4103
|
+
commitment,
|
|
4104
|
+
undefined /* encoding */,
|
|
4105
|
+
config,
|
|
4106
|
+
);
|
|
2946
4107
|
const unsafeRes = await this._rpcRequest('getSlotLeader', args);
|
|
2947
4108
|
const res = create(unsafeRes, jsonRpcResult(string()));
|
|
2948
4109
|
if ('error' in res) {
|
|
2949
|
-
throw new
|
|
4110
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get slot leader');
|
|
2950
4111
|
}
|
|
2951
4112
|
return res.result;
|
|
2952
4113
|
}
|
|
@@ -2965,7 +4126,7 @@ export class Connection {
|
|
|
2965
4126
|
const unsafeRes = await this._rpcRequest('getSlotLeaders', args);
|
|
2966
4127
|
const res = create(unsafeRes, jsonRpcResult(array(PublicKeyFromString)));
|
|
2967
4128
|
if ('error' in res) {
|
|
2968
|
-
throw new
|
|
4129
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get slot leaders');
|
|
2969
4130
|
}
|
|
2970
4131
|
return res.result;
|
|
2971
4132
|
}
|
|
@@ -3000,7 +4161,7 @@ export class Connection {
|
|
|
3000
4161
|
const unsafeRes = await this._rpcRequest('getSignatureStatuses', params);
|
|
3001
4162
|
const res = create(unsafeRes, GetSignatureStatusesRpcResult);
|
|
3002
4163
|
if ('error' in res) {
|
|
3003
|
-
throw new
|
|
4164
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get signature status');
|
|
3004
4165
|
}
|
|
3005
4166
|
return res.result;
|
|
3006
4167
|
}
|
|
@@ -3008,12 +4169,24 @@ export class Connection {
|
|
|
3008
4169
|
/**
|
|
3009
4170
|
* Fetch the current transaction count of the cluster
|
|
3010
4171
|
*/
|
|
3011
|
-
async getTransactionCount(
|
|
3012
|
-
|
|
4172
|
+
async getTransactionCount(
|
|
4173
|
+
commitmentOrConfig?: Commitment | GetTransactionCountConfig,
|
|
4174
|
+
): Promise<number> {
|
|
4175
|
+
const {commitment, config} =
|
|
4176
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4177
|
+
const args = this._buildArgs(
|
|
4178
|
+
[],
|
|
4179
|
+
commitment,
|
|
4180
|
+
undefined /* encoding */,
|
|
4181
|
+
config,
|
|
4182
|
+
);
|
|
3013
4183
|
const unsafeRes = await this._rpcRequest('getTransactionCount', args);
|
|
3014
4184
|
const res = create(unsafeRes, jsonRpcResult(number()));
|
|
3015
4185
|
if ('error' in res) {
|
|
3016
|
-
throw new
|
|
4186
|
+
throw new SolanaJSONRPCError(
|
|
4187
|
+
res.error,
|
|
4188
|
+
'failed to get transaction count',
|
|
4189
|
+
);
|
|
3017
4190
|
}
|
|
3018
4191
|
return res.result;
|
|
3019
4192
|
}
|
|
@@ -3041,7 +4214,7 @@ export class Connection {
|
|
|
3041
4214
|
const unsafeRes = await this._rpcRequest('getInflationGovernor', args);
|
|
3042
4215
|
const res = create(unsafeRes, GetInflationGovernorRpcResult);
|
|
3043
4216
|
if ('error' in res) {
|
|
3044
|
-
throw new
|
|
4217
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get inflation');
|
|
3045
4218
|
}
|
|
3046
4219
|
return res.result;
|
|
3047
4220
|
}
|
|
@@ -3052,20 +4225,23 @@ export class Connection {
|
|
|
3052
4225
|
async getInflationReward(
|
|
3053
4226
|
addresses: PublicKey[],
|
|
3054
4227
|
epoch?: number,
|
|
3055
|
-
|
|
4228
|
+
commitmentOrConfig?: Commitment | GetInflationRewardConfig,
|
|
3056
4229
|
): Promise<(InflationReward | null)[]> {
|
|
4230
|
+
const {commitment, config} =
|
|
4231
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
3057
4232
|
const args = this._buildArgs(
|
|
3058
4233
|
[addresses.map(pubkey => pubkey.toBase58())],
|
|
3059
4234
|
commitment,
|
|
3060
|
-
undefined
|
|
4235
|
+
undefined /* encoding */,
|
|
3061
4236
|
{
|
|
3062
|
-
|
|
4237
|
+
...config,
|
|
4238
|
+
epoch: epoch != null ? epoch : config?.epoch,
|
|
3063
4239
|
},
|
|
3064
4240
|
);
|
|
3065
4241
|
const unsafeRes = await this._rpcRequest('getInflationReward', args);
|
|
3066
4242
|
const res = create(unsafeRes, GetInflationRewardResult);
|
|
3067
4243
|
if ('error' in res) {
|
|
3068
|
-
throw new
|
|
4244
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get inflation reward');
|
|
3069
4245
|
}
|
|
3070
4246
|
return res.result;
|
|
3071
4247
|
}
|
|
@@ -3073,12 +4249,21 @@ export class Connection {
|
|
|
3073
4249
|
/**
|
|
3074
4250
|
* Fetch the Epoch Info parameters
|
|
3075
4251
|
*/
|
|
3076
|
-
async getEpochInfo(
|
|
3077
|
-
|
|
4252
|
+
async getEpochInfo(
|
|
4253
|
+
commitmentOrConfig?: Commitment | GetEpochInfoConfig,
|
|
4254
|
+
): Promise<EpochInfo> {
|
|
4255
|
+
const {commitment, config} =
|
|
4256
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4257
|
+
const args = this._buildArgs(
|
|
4258
|
+
[],
|
|
4259
|
+
commitment,
|
|
4260
|
+
undefined /* encoding */,
|
|
4261
|
+
config,
|
|
4262
|
+
);
|
|
3078
4263
|
const unsafeRes = await this._rpcRequest('getEpochInfo', args);
|
|
3079
4264
|
const res = create(unsafeRes, GetEpochInfoRpcResult);
|
|
3080
4265
|
if ('error' in res) {
|
|
3081
|
-
throw new
|
|
4266
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get epoch info');
|
|
3082
4267
|
}
|
|
3083
4268
|
return res.result;
|
|
3084
4269
|
}
|
|
@@ -3090,7 +4275,7 @@ export class Connection {
|
|
|
3090
4275
|
const unsafeRes = await this._rpcRequest('getEpochSchedule', []);
|
|
3091
4276
|
const res = create(unsafeRes, GetEpochScheduleRpcResult);
|
|
3092
4277
|
if ('error' in res) {
|
|
3093
|
-
throw new
|
|
4278
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get epoch schedule');
|
|
3094
4279
|
}
|
|
3095
4280
|
const epochSchedule = res.result;
|
|
3096
4281
|
return new EpochSchedule(
|
|
@@ -3110,7 +4295,7 @@ export class Connection {
|
|
|
3110
4295
|
const unsafeRes = await this._rpcRequest('getLeaderSchedule', []);
|
|
3111
4296
|
const res = create(unsafeRes, GetLeaderScheduleRpcResult);
|
|
3112
4297
|
if ('error' in res) {
|
|
3113
|
-
throw new
|
|
4298
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get leader schedule');
|
|
3114
4299
|
}
|
|
3115
4300
|
return res.result;
|
|
3116
4301
|
}
|
|
@@ -3151,7 +4336,7 @@ export class Connection {
|
|
|
3151
4336
|
const unsafeRes = await this._rpcRequest('getRecentBlockhash', args);
|
|
3152
4337
|
const res = create(unsafeRes, GetRecentBlockhashAndContextRpcResult);
|
|
3153
4338
|
if ('error' in res) {
|
|
3154
|
-
throw new
|
|
4339
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get recent blockhash');
|
|
3155
4340
|
}
|
|
3156
4341
|
return res.result;
|
|
3157
4342
|
}
|
|
@@ -3163,15 +4348,15 @@ export class Connection {
|
|
|
3163
4348
|
async getRecentPerformanceSamples(
|
|
3164
4349
|
limit?: number,
|
|
3165
4350
|
): Promise<Array<PerfSample>> {
|
|
3166
|
-
const args = this._buildArgs(limit ? [limit] : []);
|
|
3167
4351
|
const unsafeRes = await this._rpcRequest(
|
|
3168
4352
|
'getRecentPerformanceSamples',
|
|
3169
|
-
|
|
4353
|
+
limit ? [limit] : [],
|
|
3170
4354
|
);
|
|
3171
4355
|
const res = create(unsafeRes, GetRecentPerformanceSamplesRpcResult);
|
|
3172
4356
|
if ('error' in res) {
|
|
3173
|
-
throw new
|
|
3174
|
-
|
|
4357
|
+
throw new SolanaJSONRPCError(
|
|
4358
|
+
res.error,
|
|
4359
|
+
'failed to get recent performance samples',
|
|
3175
4360
|
);
|
|
3176
4361
|
}
|
|
3177
4362
|
|
|
@@ -3195,7 +4380,7 @@ export class Connection {
|
|
|
3195
4380
|
|
|
3196
4381
|
const res = create(unsafeRes, GetFeeCalculatorRpcResult);
|
|
3197
4382
|
if ('error' in res) {
|
|
3198
|
-
throw new
|
|
4383
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get fee calculator');
|
|
3199
4384
|
}
|
|
3200
4385
|
const {context, value} = res.result;
|
|
3201
4386
|
return {
|
|
@@ -3208,16 +4393,16 @@ export class Connection {
|
|
|
3208
4393
|
* Fetch the fee for a message from the cluster, return with context
|
|
3209
4394
|
*/
|
|
3210
4395
|
async getFeeForMessage(
|
|
3211
|
-
message:
|
|
4396
|
+
message: VersionedMessage,
|
|
3212
4397
|
commitment?: Commitment,
|
|
3213
4398
|
): Promise<RpcResponseAndContext<number>> {
|
|
3214
|
-
const wireMessage = message.serialize().toString('base64');
|
|
4399
|
+
const wireMessage = toBuffer(message.serialize()).toString('base64');
|
|
3215
4400
|
const args = this._buildArgs([wireMessage], commitment);
|
|
3216
4401
|
const unsafeRes = await this._rpcRequest('getFeeForMessage', args);
|
|
3217
4402
|
|
|
3218
4403
|
const res = create(unsafeRes, jsonRpcResultAndContext(nullable(number())));
|
|
3219
4404
|
if ('error' in res) {
|
|
3220
|
-
throw new
|
|
4405
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get fee for message');
|
|
3221
4406
|
}
|
|
3222
4407
|
if (res.result === null) {
|
|
3223
4408
|
throw new Error('invalid blockhash');
|
|
@@ -3244,13 +4429,13 @@ export class Connection {
|
|
|
3244
4429
|
|
|
3245
4430
|
/**
|
|
3246
4431
|
* Fetch the latest blockhash from the cluster
|
|
3247
|
-
* @return {Promise<
|
|
4432
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
3248
4433
|
*/
|
|
3249
4434
|
async getLatestBlockhash(
|
|
3250
|
-
|
|
3251
|
-
): Promise<
|
|
4435
|
+
commitmentOrConfig?: Commitment | GetLatestBlockhashConfig,
|
|
4436
|
+
): Promise<BlockhashWithExpiryBlockHeight> {
|
|
3252
4437
|
try {
|
|
3253
|
-
const res = await this.getLatestBlockhashAndContext(
|
|
4438
|
+
const res = await this.getLatestBlockhashAndContext(commitmentOrConfig);
|
|
3254
4439
|
return res.value;
|
|
3255
4440
|
} catch (e) {
|
|
3256
4441
|
throw new Error('failed to get recent blockhash: ' + e);
|
|
@@ -3259,18 +4444,23 @@ export class Connection {
|
|
|
3259
4444
|
|
|
3260
4445
|
/**
|
|
3261
4446
|
* Fetch the latest blockhash from the cluster
|
|
3262
|
-
* @return {Promise<
|
|
4447
|
+
* @return {Promise<BlockhashWithExpiryBlockHeight>}
|
|
3263
4448
|
*/
|
|
3264
4449
|
async getLatestBlockhashAndContext(
|
|
3265
|
-
|
|
3266
|
-
): Promise<
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
const args = this._buildArgs(
|
|
4450
|
+
commitmentOrConfig?: Commitment | GetLatestBlockhashConfig,
|
|
4451
|
+
): Promise<RpcResponseAndContext<BlockhashWithExpiryBlockHeight>> {
|
|
4452
|
+
const {commitment, config} =
|
|
4453
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4454
|
+
const args = this._buildArgs(
|
|
4455
|
+
[],
|
|
4456
|
+
commitment,
|
|
4457
|
+
undefined /* encoding */,
|
|
4458
|
+
config,
|
|
4459
|
+
);
|
|
3270
4460
|
const unsafeRes = await this._rpcRequest('getLatestBlockhash', args);
|
|
3271
4461
|
const res = create(unsafeRes, GetLatestBlockhashRpcResult);
|
|
3272
4462
|
if ('error' in res) {
|
|
3273
|
-
throw new
|
|
4463
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get latest blockhash');
|
|
3274
4464
|
}
|
|
3275
4465
|
return res.result;
|
|
3276
4466
|
}
|
|
@@ -3282,7 +4472,7 @@ export class Connection {
|
|
|
3282
4472
|
const unsafeRes = await this._rpcRequest('getVersion', []);
|
|
3283
4473
|
const res = create(unsafeRes, jsonRpcResult(VersionResult));
|
|
3284
4474
|
if ('error' in res) {
|
|
3285
|
-
throw new
|
|
4475
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get version');
|
|
3286
4476
|
}
|
|
3287
4477
|
return res.result;
|
|
3288
4478
|
}
|
|
@@ -3294,57 +4484,220 @@ export class Connection {
|
|
|
3294
4484
|
const unsafeRes = await this._rpcRequest('getGenesisHash', []);
|
|
3295
4485
|
const res = create(unsafeRes, jsonRpcResult(string()));
|
|
3296
4486
|
if ('error' in res) {
|
|
3297
|
-
throw new
|
|
4487
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get genesis hash');
|
|
3298
4488
|
}
|
|
3299
4489
|
return res.result;
|
|
3300
4490
|
}
|
|
3301
4491
|
|
|
4492
|
+
/**
|
|
4493
|
+
* Fetch a processed block from the cluster.
|
|
4494
|
+
*
|
|
4495
|
+
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
|
4496
|
+
* setting the `maxSupportedTransactionVersion` property.
|
|
4497
|
+
*/
|
|
4498
|
+
async getBlock(
|
|
4499
|
+
slot: number,
|
|
4500
|
+
rawConfig?: GetBlockConfig,
|
|
4501
|
+
): Promise<BlockResponse | null>;
|
|
4502
|
+
|
|
4503
|
+
/**
|
|
4504
|
+
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
|
4505
|
+
* setting the `maxSupportedTransactionVersion` property.
|
|
4506
|
+
*/
|
|
4507
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4508
|
+
async getBlock(
|
|
4509
|
+
slot: number,
|
|
4510
|
+
rawConfig: GetBlockConfig & {transactionDetails: 'accounts'},
|
|
4511
|
+
): Promise<AccountsModeBlockResponse | null>;
|
|
4512
|
+
|
|
4513
|
+
/**
|
|
4514
|
+
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
|
|
4515
|
+
* setting the `maxSupportedTransactionVersion` property.
|
|
4516
|
+
*/
|
|
4517
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4518
|
+
async getBlock(
|
|
4519
|
+
slot: number,
|
|
4520
|
+
rawConfig: GetBlockConfig & {transactionDetails: 'none'},
|
|
4521
|
+
): Promise<NoneModeBlockResponse | null>;
|
|
4522
|
+
|
|
3302
4523
|
/**
|
|
3303
4524
|
* Fetch a processed block from the cluster.
|
|
3304
4525
|
*/
|
|
4526
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4527
|
+
async getBlock(
|
|
4528
|
+
slot: number,
|
|
4529
|
+
rawConfig?: GetVersionedBlockConfig,
|
|
4530
|
+
): Promise<VersionedBlockResponse | null>;
|
|
4531
|
+
|
|
4532
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4533
|
+
async getBlock(
|
|
4534
|
+
slot: number,
|
|
4535
|
+
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'},
|
|
4536
|
+
): Promise<VersionedAccountsModeBlockResponse | null>;
|
|
4537
|
+
|
|
4538
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
3305
4539
|
async getBlock(
|
|
3306
4540
|
slot: number,
|
|
3307
|
-
|
|
3308
|
-
): Promise<
|
|
4541
|
+
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'},
|
|
4542
|
+
): Promise<VersionedNoneModeBlockResponse | null>;
|
|
4543
|
+
|
|
4544
|
+
/**
|
|
4545
|
+
* Fetch a processed block from the cluster.
|
|
4546
|
+
*/
|
|
4547
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4548
|
+
async getBlock(
|
|
4549
|
+
slot: number,
|
|
4550
|
+
rawConfig?: GetVersionedBlockConfig,
|
|
4551
|
+
): Promise<
|
|
4552
|
+
| VersionedBlockResponse
|
|
4553
|
+
| VersionedAccountsModeBlockResponse
|
|
4554
|
+
| VersionedNoneModeBlockResponse
|
|
4555
|
+
| null
|
|
4556
|
+
> {
|
|
4557
|
+
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
|
3309
4558
|
const args = this._buildArgsAtLeastConfirmed(
|
|
3310
4559
|
[slot],
|
|
3311
|
-
|
|
4560
|
+
commitment as Finality,
|
|
4561
|
+
undefined /* encoding */,
|
|
4562
|
+
config,
|
|
3312
4563
|
);
|
|
3313
4564
|
const unsafeRes = await this._rpcRequest('getBlock', args);
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
4565
|
+
try {
|
|
4566
|
+
switch (config?.transactionDetails) {
|
|
4567
|
+
case 'accounts': {
|
|
4568
|
+
const res = create(unsafeRes, GetAccountsModeBlockRpcResult);
|
|
4569
|
+
if ('error' in res) {
|
|
4570
|
+
throw res.error;
|
|
4571
|
+
}
|
|
4572
|
+
return res.result;
|
|
4573
|
+
}
|
|
4574
|
+
case 'none': {
|
|
4575
|
+
const res = create(unsafeRes, GetNoneModeBlockRpcResult);
|
|
4576
|
+
if ('error' in res) {
|
|
4577
|
+
throw res.error;
|
|
4578
|
+
}
|
|
4579
|
+
return res.result;
|
|
4580
|
+
}
|
|
4581
|
+
default: {
|
|
4582
|
+
const res = create(unsafeRes, GetBlockRpcResult);
|
|
4583
|
+
if ('error' in res) {
|
|
4584
|
+
throw res.error;
|
|
4585
|
+
}
|
|
4586
|
+
const {result} = res;
|
|
4587
|
+
return result
|
|
4588
|
+
? {
|
|
4589
|
+
...result,
|
|
4590
|
+
transactions: result.transactions.map(
|
|
4591
|
+
({transaction, meta, version}) => ({
|
|
4592
|
+
meta,
|
|
4593
|
+
transaction: {
|
|
4594
|
+
...transaction,
|
|
4595
|
+
message: versionedMessageFromResponse(
|
|
4596
|
+
version,
|
|
4597
|
+
transaction.message,
|
|
4598
|
+
),
|
|
4599
|
+
},
|
|
4600
|
+
version,
|
|
4601
|
+
}),
|
|
4602
|
+
),
|
|
4603
|
+
}
|
|
4604
|
+
: null;
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
} catch (e) {
|
|
4608
|
+
throw new SolanaJSONRPCError(
|
|
4609
|
+
e as JSONRPCError,
|
|
4610
|
+
'failed to get confirmed block',
|
|
4611
|
+
);
|
|
3318
4612
|
}
|
|
4613
|
+
}
|
|
3319
4614
|
|
|
3320
|
-
|
|
3321
|
-
|
|
4615
|
+
/**
|
|
4616
|
+
* Fetch parsed transaction details for a confirmed or finalized block
|
|
4617
|
+
*/
|
|
4618
|
+
async getParsedBlock(
|
|
4619
|
+
slot: number,
|
|
4620
|
+
rawConfig?: GetVersionedBlockConfig,
|
|
4621
|
+
): Promise<ParsedAccountsModeBlockResponse>;
|
|
3322
4622
|
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
4623
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4624
|
+
async getParsedBlock(
|
|
4625
|
+
slot: number,
|
|
4626
|
+
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'},
|
|
4627
|
+
): Promise<ParsedAccountsModeBlockResponse>;
|
|
4628
|
+
|
|
4629
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4630
|
+
async getParsedBlock(
|
|
4631
|
+
slot: number,
|
|
4632
|
+
rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'},
|
|
4633
|
+
): Promise<ParsedNoneModeBlockResponse>;
|
|
4634
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4635
|
+
async getParsedBlock(
|
|
4636
|
+
slot: number,
|
|
4637
|
+
rawConfig?: GetVersionedBlockConfig,
|
|
4638
|
+
): Promise<
|
|
4639
|
+
| ParsedBlockResponse
|
|
4640
|
+
| ParsedAccountsModeBlockResponse
|
|
4641
|
+
| ParsedNoneModeBlockResponse
|
|
4642
|
+
| null
|
|
4643
|
+
> {
|
|
4644
|
+
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
|
4645
|
+
const args = this._buildArgsAtLeastConfirmed(
|
|
4646
|
+
[slot],
|
|
4647
|
+
commitment as Finality,
|
|
4648
|
+
'jsonParsed',
|
|
4649
|
+
config,
|
|
4650
|
+
);
|
|
4651
|
+
const unsafeRes = await this._rpcRequest('getBlock', args);
|
|
4652
|
+
try {
|
|
4653
|
+
switch (config?.transactionDetails) {
|
|
4654
|
+
case 'accounts': {
|
|
4655
|
+
const res = create(unsafeRes, GetParsedAccountsModeBlockRpcResult);
|
|
4656
|
+
if ('error' in res) {
|
|
4657
|
+
throw res.error;
|
|
4658
|
+
}
|
|
4659
|
+
return res.result;
|
|
4660
|
+
}
|
|
4661
|
+
case 'none': {
|
|
4662
|
+
const res = create(unsafeRes, GetParsedNoneModeBlockRpcResult);
|
|
4663
|
+
if ('error' in res) {
|
|
4664
|
+
throw res.error;
|
|
4665
|
+
}
|
|
4666
|
+
return res.result;
|
|
4667
|
+
}
|
|
4668
|
+
default: {
|
|
4669
|
+
const res = create(unsafeRes, GetParsedBlockRpcResult);
|
|
4670
|
+
if ('error' in res) {
|
|
4671
|
+
throw res.error;
|
|
4672
|
+
}
|
|
4673
|
+
return res.result;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
} catch (e) {
|
|
4677
|
+
throw new SolanaJSONRPCError(e as JSONRPCError, 'failed to get block');
|
|
4678
|
+
}
|
|
3336
4679
|
}
|
|
3337
4680
|
|
|
3338
4681
|
/*
|
|
3339
4682
|
* Returns the current block height of the node
|
|
3340
4683
|
*/
|
|
3341
|
-
async getBlockHeight(
|
|
3342
|
-
|
|
4684
|
+
async getBlockHeight(
|
|
4685
|
+
commitmentOrConfig?: Commitment | GetBlockHeightConfig,
|
|
4686
|
+
): Promise<number> {
|
|
4687
|
+
const {commitment, config} =
|
|
4688
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4689
|
+
const args = this._buildArgs(
|
|
4690
|
+
[],
|
|
4691
|
+
commitment,
|
|
4692
|
+
undefined /* encoding */,
|
|
4693
|
+
config,
|
|
4694
|
+
);
|
|
3343
4695
|
const unsafeRes = await this._rpcRequest('getBlockHeight', args);
|
|
3344
4696
|
const res = create(unsafeRes, jsonRpcResult(number()));
|
|
3345
4697
|
if ('error' in res) {
|
|
3346
|
-
throw new
|
|
3347
|
-
|
|
4698
|
+
throw new SolanaJSONRPCError(
|
|
4699
|
+
res.error,
|
|
4700
|
+
'failed to get block height information',
|
|
3348
4701
|
);
|
|
3349
4702
|
}
|
|
3350
4703
|
|
|
@@ -3372,8 +4725,9 @@ export class Connection {
|
|
|
3372
4725
|
const unsafeRes = await this._rpcRequest('getBlockProduction', args);
|
|
3373
4726
|
const res = create(unsafeRes, BlockProductionResponseStruct);
|
|
3374
4727
|
if ('error' in res) {
|
|
3375
|
-
throw new
|
|
3376
|
-
|
|
4728
|
+
throw new SolanaJSONRPCError(
|
|
4729
|
+
res.error,
|
|
4730
|
+
'failed to get block production information',
|
|
3377
4731
|
);
|
|
3378
4732
|
}
|
|
3379
4733
|
|
|
@@ -3382,19 +4736,44 @@ export class Connection {
|
|
|
3382
4736
|
|
|
3383
4737
|
/**
|
|
3384
4738
|
* Fetch a confirmed or finalized transaction from the cluster.
|
|
4739
|
+
*
|
|
4740
|
+
* @deprecated Instead, call `getTransaction` using a
|
|
4741
|
+
* `GetVersionedTransactionConfig` by setting the
|
|
4742
|
+
* `maxSupportedTransactionVersion` property.
|
|
3385
4743
|
*/
|
|
3386
4744
|
async getTransaction(
|
|
3387
4745
|
signature: string,
|
|
3388
|
-
|
|
3389
|
-
): Promise<TransactionResponse | null
|
|
4746
|
+
rawConfig?: GetTransactionConfig,
|
|
4747
|
+
): Promise<TransactionResponse | null>;
|
|
4748
|
+
|
|
4749
|
+
/**
|
|
4750
|
+
* Fetch a confirmed or finalized transaction from the cluster.
|
|
4751
|
+
*/
|
|
4752
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4753
|
+
async getTransaction(
|
|
4754
|
+
signature: string,
|
|
4755
|
+
rawConfig: GetVersionedTransactionConfig,
|
|
4756
|
+
): Promise<VersionedTransactionResponse | null>;
|
|
4757
|
+
|
|
4758
|
+
/**
|
|
4759
|
+
* Fetch a confirmed or finalized transaction from the cluster.
|
|
4760
|
+
*/
|
|
4761
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4762
|
+
async getTransaction(
|
|
4763
|
+
signature: string,
|
|
4764
|
+
rawConfig?: GetVersionedTransactionConfig,
|
|
4765
|
+
): Promise<VersionedTransactionResponse | null> {
|
|
4766
|
+
const {commitment, config} = extractCommitmentFromConfig(rawConfig);
|
|
3390
4767
|
const args = this._buildArgsAtLeastConfirmed(
|
|
3391
4768
|
[signature],
|
|
3392
|
-
|
|
4769
|
+
commitment as Finality,
|
|
4770
|
+
undefined /* encoding */,
|
|
4771
|
+
config,
|
|
3393
4772
|
);
|
|
3394
4773
|
const unsafeRes = await this._rpcRequest('getTransaction', args);
|
|
3395
4774
|
const res = create(unsafeRes, GetTransactionRpcResult);
|
|
3396
4775
|
if ('error' in res) {
|
|
3397
|
-
throw new
|
|
4776
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
|
3398
4777
|
}
|
|
3399
4778
|
|
|
3400
4779
|
const result = res.result;
|
|
@@ -3404,7 +4783,10 @@ export class Connection {
|
|
|
3404
4783
|
...result,
|
|
3405
4784
|
transaction: {
|
|
3406
4785
|
...result.transaction,
|
|
3407
|
-
message:
|
|
4786
|
+
message: versionedMessageFromResponse(
|
|
4787
|
+
result.version,
|
|
4788
|
+
result.transaction.message,
|
|
4789
|
+
),
|
|
3408
4790
|
},
|
|
3409
4791
|
};
|
|
3410
4792
|
}
|
|
@@ -3414,17 +4796,20 @@ export class Connection {
|
|
|
3414
4796
|
*/
|
|
3415
4797
|
async getParsedTransaction(
|
|
3416
4798
|
signature: TransactionSignature,
|
|
3417
|
-
|
|
3418
|
-
): Promise<
|
|
4799
|
+
commitmentOrConfig?: GetVersionedTransactionConfig | Finality,
|
|
4800
|
+
): Promise<ParsedTransactionWithMeta | null> {
|
|
4801
|
+
const {commitment, config} =
|
|
4802
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
3419
4803
|
const args = this._buildArgsAtLeastConfirmed(
|
|
3420
4804
|
[signature],
|
|
3421
|
-
commitment,
|
|
4805
|
+
commitment as Finality,
|
|
3422
4806
|
'jsonParsed',
|
|
4807
|
+
config,
|
|
3423
4808
|
);
|
|
3424
4809
|
const unsafeRes = await this._rpcRequest('getTransaction', args);
|
|
3425
4810
|
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
|
3426
4811
|
if ('error' in res) {
|
|
3427
|
-
throw new
|
|
4812
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
|
3428
4813
|
}
|
|
3429
4814
|
return res.result;
|
|
3430
4815
|
}
|
|
@@ -3434,13 +4819,16 @@ export class Connection {
|
|
|
3434
4819
|
*/
|
|
3435
4820
|
async getParsedTransactions(
|
|
3436
4821
|
signatures: TransactionSignature[],
|
|
3437
|
-
|
|
3438
|
-
): Promise<(
|
|
4822
|
+
commitmentOrConfig?: GetVersionedTransactionConfig | Finality,
|
|
4823
|
+
): Promise<(ParsedTransactionWithMeta | null)[]> {
|
|
4824
|
+
const {commitment, config} =
|
|
4825
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
3439
4826
|
const batch = signatures.map(signature => {
|
|
3440
4827
|
const args = this._buildArgsAtLeastConfirmed(
|
|
3441
4828
|
[signature],
|
|
3442
|
-
commitment,
|
|
4829
|
+
commitment as Finality,
|
|
3443
4830
|
'jsonParsed',
|
|
4831
|
+
config,
|
|
3444
4832
|
);
|
|
3445
4833
|
return {
|
|
3446
4834
|
methodName: 'getTransaction',
|
|
@@ -3452,7 +4840,7 @@ export class Connection {
|
|
|
3452
4840
|
const res = unsafeRes.map((unsafeRes: any) => {
|
|
3453
4841
|
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
|
3454
4842
|
if ('error' in res) {
|
|
3455
|
-
throw new
|
|
4843
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
|
|
3456
4844
|
}
|
|
3457
4845
|
return res.result;
|
|
3458
4846
|
});
|
|
@@ -3460,6 +4848,79 @@ export class Connection {
|
|
|
3460
4848
|
return res;
|
|
3461
4849
|
}
|
|
3462
4850
|
|
|
4851
|
+
/**
|
|
4852
|
+
* Fetch transaction details for a batch of confirmed transactions.
|
|
4853
|
+
* Similar to {@link getParsedTransactions} but returns a {@link TransactionResponse}.
|
|
4854
|
+
*
|
|
4855
|
+
* @deprecated Instead, call `getTransactions` using a
|
|
4856
|
+
* `GetVersionedTransactionConfig` by setting the
|
|
4857
|
+
* `maxSupportedTransactionVersion` property.
|
|
4858
|
+
*/
|
|
4859
|
+
async getTransactions(
|
|
4860
|
+
signatures: TransactionSignature[],
|
|
4861
|
+
commitmentOrConfig?: GetTransactionConfig | Finality,
|
|
4862
|
+
): Promise<(TransactionResponse | null)[]>;
|
|
4863
|
+
|
|
4864
|
+
/**
|
|
4865
|
+
* Fetch transaction details for a batch of confirmed transactions.
|
|
4866
|
+
* Similar to {@link getParsedTransactions} but returns a {@link
|
|
4867
|
+
* VersionedTransactionResponse}.
|
|
4868
|
+
*/
|
|
4869
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4870
|
+
async getTransactions(
|
|
4871
|
+
signatures: TransactionSignature[],
|
|
4872
|
+
commitmentOrConfig: GetVersionedTransactionConfig | Finality,
|
|
4873
|
+
): Promise<(VersionedTransactionResponse | null)[]>;
|
|
4874
|
+
|
|
4875
|
+
/**
|
|
4876
|
+
* Fetch transaction details for a batch of confirmed transactions.
|
|
4877
|
+
* Similar to {@link getParsedTransactions} but returns a {@link
|
|
4878
|
+
* VersionedTransactionResponse}.
|
|
4879
|
+
*/
|
|
4880
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
4881
|
+
async getTransactions(
|
|
4882
|
+
signatures: TransactionSignature[],
|
|
4883
|
+
commitmentOrConfig: GetVersionedTransactionConfig | Finality,
|
|
4884
|
+
): Promise<(VersionedTransactionResponse | null)[]> {
|
|
4885
|
+
const {commitment, config} =
|
|
4886
|
+
extractCommitmentFromConfig(commitmentOrConfig);
|
|
4887
|
+
const batch = signatures.map(signature => {
|
|
4888
|
+
const args = this._buildArgsAtLeastConfirmed(
|
|
4889
|
+
[signature],
|
|
4890
|
+
commitment as Finality,
|
|
4891
|
+
undefined /* encoding */,
|
|
4892
|
+
config,
|
|
4893
|
+
);
|
|
4894
|
+
return {
|
|
4895
|
+
methodName: 'getTransaction',
|
|
4896
|
+
args,
|
|
4897
|
+
};
|
|
4898
|
+
});
|
|
4899
|
+
|
|
4900
|
+
const unsafeRes = await this._rpcBatchRequest(batch);
|
|
4901
|
+
const res = unsafeRes.map((unsafeRes: any) => {
|
|
4902
|
+
const res = create(unsafeRes, GetTransactionRpcResult);
|
|
4903
|
+
if ('error' in res) {
|
|
4904
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
|
|
4905
|
+
}
|
|
4906
|
+
const result = res.result;
|
|
4907
|
+
if (!result) return result;
|
|
4908
|
+
|
|
4909
|
+
return {
|
|
4910
|
+
...result,
|
|
4911
|
+
transaction: {
|
|
4912
|
+
...result.transaction,
|
|
4913
|
+
message: versionedMessageFromResponse(
|
|
4914
|
+
result.version,
|
|
4915
|
+
result.transaction.message,
|
|
4916
|
+
),
|
|
4917
|
+
},
|
|
4918
|
+
};
|
|
4919
|
+
});
|
|
4920
|
+
|
|
4921
|
+
return res;
|
|
4922
|
+
}
|
|
4923
|
+
|
|
3463
4924
|
/**
|
|
3464
4925
|
* Fetch a list of Transactions and transaction statuses from the cluster
|
|
3465
4926
|
* for a confirmed block.
|
|
@@ -3475,7 +4936,7 @@ export class Connection {
|
|
|
3475
4936
|
const res = create(unsafeRes, GetConfirmedBlockRpcResult);
|
|
3476
4937
|
|
|
3477
4938
|
if ('error' in res) {
|
|
3478
|
-
throw new
|
|
4939
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
|
|
3479
4940
|
}
|
|
3480
4941
|
|
|
3481
4942
|
const result = res.result;
|
|
@@ -3526,7 +4987,7 @@ export class Connection {
|
|
|
3526
4987
|
const unsafeRes = await this._rpcRequest('getBlocks', args);
|
|
3527
4988
|
const res = create(unsafeRes, jsonRpcResult(array(number())));
|
|
3528
4989
|
if ('error' in res) {
|
|
3529
|
-
throw new
|
|
4990
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get blocks');
|
|
3530
4991
|
}
|
|
3531
4992
|
return res.result;
|
|
3532
4993
|
}
|
|
@@ -3550,7 +5011,7 @@ export class Connection {
|
|
|
3550
5011
|
const unsafeRes = await this._rpcRequest('getBlock', args);
|
|
3551
5012
|
const res = create(unsafeRes, GetBlockSignaturesRpcResult);
|
|
3552
5013
|
if ('error' in res) {
|
|
3553
|
-
throw new
|
|
5014
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get block');
|
|
3554
5015
|
}
|
|
3555
5016
|
const result = res.result;
|
|
3556
5017
|
if (!result) {
|
|
@@ -3580,7 +5041,7 @@ export class Connection {
|
|
|
3580
5041
|
const unsafeRes = await this._rpcRequest('getConfirmedBlock', args);
|
|
3581
5042
|
const res = create(unsafeRes, GetBlockSignaturesRpcResult);
|
|
3582
5043
|
if ('error' in res) {
|
|
3583
|
-
throw new
|
|
5044
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
|
|
3584
5045
|
}
|
|
3585
5046
|
const result = res.result;
|
|
3586
5047
|
if (!result) {
|
|
@@ -3602,7 +5063,7 @@ export class Connection {
|
|
|
3602
5063
|
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
|
|
3603
5064
|
const res = create(unsafeRes, GetTransactionRpcResult);
|
|
3604
5065
|
if ('error' in res) {
|
|
3605
|
-
throw new
|
|
5066
|
+
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
|
|
3606
5067
|
}
|
|
3607
5068
|
|
|
3608
5069
|
const result = res.result;
|
|
@@ -3633,8 +5094,9 @@ export class Connection {
|
|
|
3633
5094
|
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
|
|
3634
5095
|
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
|
3635
5096
|
if ('error' in res) {
|
|
3636
|
-
throw new
|
|
3637
|
-
|
|
5097
|
+
throw new SolanaJSONRPCError(
|
|
5098
|
+
res.error,
|
|
5099
|
+
'failed to get confirmed transaction',
|
|
3638
5100
|
);
|
|
3639
5101
|
}
|
|
3640
5102
|
return res.result;
|
|
@@ -3665,8 +5127,9 @@ export class Connection {
|
|
|
3665
5127
|
const res = unsafeRes.map((unsafeRes: any) => {
|
|
3666
5128
|
const res = create(unsafeRes, GetParsedTransactionRpcResult);
|
|
3667
5129
|
if ('error' in res) {
|
|
3668
|
-
throw new
|
|
3669
|
-
|
|
5130
|
+
throw new SolanaJSONRPCError(
|
|
5131
|
+
res.error,
|
|
5132
|
+
'failed to get confirmed transactions',
|
|
3670
5133
|
);
|
|
3671
5134
|
}
|
|
3672
5135
|
return res.result;
|
|
@@ -3771,8 +5234,9 @@ export class Connection {
|
|
|
3771
5234
|
);
|
|
3772
5235
|
const res = create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult);
|
|
3773
5236
|
if ('error' in res) {
|
|
3774
|
-
throw new
|
|
3775
|
-
|
|
5237
|
+
throw new SolanaJSONRPCError(
|
|
5238
|
+
res.error,
|
|
5239
|
+
'failed to get confirmed signatures for address',
|
|
3776
5240
|
);
|
|
3777
5241
|
}
|
|
3778
5242
|
return res.result;
|
|
@@ -3800,23 +5264,47 @@ export class Connection {
|
|
|
3800
5264
|
const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args);
|
|
3801
5265
|
const res = create(unsafeRes, GetSignaturesForAddressRpcResult);
|
|
3802
5266
|
if ('error' in res) {
|
|
3803
|
-
throw new
|
|
3804
|
-
|
|
5267
|
+
throw new SolanaJSONRPCError(
|
|
5268
|
+
res.error,
|
|
5269
|
+
'failed to get signatures for address',
|
|
3805
5270
|
);
|
|
3806
5271
|
}
|
|
3807
5272
|
return res.result;
|
|
3808
5273
|
}
|
|
3809
5274
|
|
|
5275
|
+
async getAddressLookupTable(
|
|
5276
|
+
accountKey: PublicKey,
|
|
5277
|
+
config?: GetAccountInfoConfig,
|
|
5278
|
+
): Promise<RpcResponseAndContext<AddressLookupTableAccount | null>> {
|
|
5279
|
+
const {context, value: accountInfo} = await this.getAccountInfoAndContext(
|
|
5280
|
+
accountKey,
|
|
5281
|
+
config,
|
|
5282
|
+
);
|
|
5283
|
+
|
|
5284
|
+
let value = null;
|
|
5285
|
+
if (accountInfo !== null) {
|
|
5286
|
+
value = new AddressLookupTableAccount({
|
|
5287
|
+
key: accountKey,
|
|
5288
|
+
state: AddressLookupTableAccount.deserialize(accountInfo.data),
|
|
5289
|
+
});
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
return {
|
|
5293
|
+
context,
|
|
5294
|
+
value,
|
|
5295
|
+
};
|
|
5296
|
+
}
|
|
5297
|
+
|
|
3810
5298
|
/**
|
|
3811
5299
|
* Fetch the contents of a Nonce account from the cluster, return with context
|
|
3812
5300
|
*/
|
|
3813
5301
|
async getNonceAndContext(
|
|
3814
5302
|
nonceAccount: PublicKey,
|
|
3815
|
-
|
|
5303
|
+
commitmentOrConfig?: Commitment | GetNonceAndContextConfig,
|
|
3816
5304
|
): Promise<RpcResponseAndContext<NonceAccount | null>> {
|
|
3817
5305
|
const {context, value: accountInfo} = await this.getAccountInfoAndContext(
|
|
3818
5306
|
nonceAccount,
|
|
3819
|
-
|
|
5307
|
+
commitmentOrConfig,
|
|
3820
5308
|
);
|
|
3821
5309
|
|
|
3822
5310
|
let value = null;
|
|
@@ -3835,9 +5323,9 @@ export class Connection {
|
|
|
3835
5323
|
*/
|
|
3836
5324
|
async getNonce(
|
|
3837
5325
|
nonceAccount: PublicKey,
|
|
3838
|
-
|
|
5326
|
+
commitmentOrConfig?: Commitment | GetNonceConfig,
|
|
3839
5327
|
): Promise<NonceAccount | null> {
|
|
3840
|
-
return await this.getNonceAndContext(nonceAccount,
|
|
5328
|
+
return await this.getNonceAndContext(nonceAccount, commitmentOrConfig)
|
|
3841
5329
|
.then(x => x.value)
|
|
3842
5330
|
.catch(e => {
|
|
3843
5331
|
throw new Error(
|
|
@@ -3873,8 +5361,9 @@ export class Connection {
|
|
|
3873
5361
|
]);
|
|
3874
5362
|
const res = create(unsafeRes, RequestAirdropRpcResult);
|
|
3875
5363
|
if ('error' in res) {
|
|
3876
|
-
throw new
|
|
3877
|
-
|
|
5364
|
+
throw new SolanaJSONRPCError(
|
|
5365
|
+
res.error,
|
|
5366
|
+
`airdrop to ${to.toBase58()} failed`,
|
|
3878
5367
|
);
|
|
3879
5368
|
}
|
|
3880
5369
|
return res.result;
|
|
@@ -3883,7 +5372,9 @@ export class Connection {
|
|
|
3883
5372
|
/**
|
|
3884
5373
|
* @internal
|
|
3885
5374
|
*/
|
|
3886
|
-
async
|
|
5375
|
+
async _blockhashWithExpiryBlockHeight(
|
|
5376
|
+
disableCache: boolean,
|
|
5377
|
+
): Promise<BlockhashWithExpiryBlockHeight> {
|
|
3887
5378
|
if (!disableCache) {
|
|
3888
5379
|
// Wait for polling to finish
|
|
3889
5380
|
while (this._pollingBlockhash) {
|
|
@@ -3891,8 +5382,8 @@ export class Connection {
|
|
|
3891
5382
|
}
|
|
3892
5383
|
const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch;
|
|
3893
5384
|
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
|
|
3894
|
-
if (this._blockhashInfo.
|
|
3895
|
-
return this._blockhashInfo.
|
|
5385
|
+
if (this._blockhashInfo.latestBlockhash !== null && !expired) {
|
|
5386
|
+
return this._blockhashInfo.latestBlockhash;
|
|
3896
5387
|
}
|
|
3897
5388
|
}
|
|
3898
5389
|
|
|
@@ -3902,21 +5393,25 @@ export class Connection {
|
|
|
3902
5393
|
/**
|
|
3903
5394
|
* @internal
|
|
3904
5395
|
*/
|
|
3905
|
-
async _pollNewBlockhash(): Promise<
|
|
5396
|
+
async _pollNewBlockhash(): Promise<BlockhashWithExpiryBlockHeight> {
|
|
3906
5397
|
this._pollingBlockhash = true;
|
|
3907
5398
|
try {
|
|
3908
5399
|
const startTime = Date.now();
|
|
5400
|
+
const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
|
|
5401
|
+
const cachedBlockhash = cachedLatestBlockhash
|
|
5402
|
+
? cachedLatestBlockhash.blockhash
|
|
5403
|
+
: null;
|
|
3909
5404
|
for (let i = 0; i < 50; i++) {
|
|
3910
|
-
const
|
|
5405
|
+
const latestBlockhash = await this.getLatestBlockhash('finalized');
|
|
3911
5406
|
|
|
3912
|
-
if (
|
|
5407
|
+
if (cachedBlockhash !== latestBlockhash.blockhash) {
|
|
3913
5408
|
this._blockhashInfo = {
|
|
3914
|
-
|
|
5409
|
+
latestBlockhash,
|
|
3915
5410
|
lastFetch: Date.now(),
|
|
3916
5411
|
transactionSignatures: [],
|
|
3917
5412
|
simulatedSignatures: [],
|
|
3918
5413
|
};
|
|
3919
|
-
return
|
|
5414
|
+
return latestBlockhash;
|
|
3920
5415
|
}
|
|
3921
5416
|
|
|
3922
5417
|
// Sleep for approximately half a slot
|
|
@@ -3931,36 +5426,108 @@ export class Connection {
|
|
|
3931
5426
|
}
|
|
3932
5427
|
}
|
|
3933
5428
|
|
|
5429
|
+
/**
|
|
5430
|
+
* get the stake minimum delegation
|
|
5431
|
+
*/
|
|
5432
|
+
async getStakeMinimumDelegation(
|
|
5433
|
+
config?: GetStakeMinimumDelegationConfig,
|
|
5434
|
+
): Promise<RpcResponseAndContext<number>> {
|
|
5435
|
+
const {commitment, config: configArg} = extractCommitmentFromConfig(config);
|
|
5436
|
+
const args = this._buildArgs([], commitment, 'base64', configArg);
|
|
5437
|
+
const unsafeRes = await this._rpcRequest('getStakeMinimumDelegation', args);
|
|
5438
|
+
const res = create(unsafeRes, jsonRpcResultAndContext(number()));
|
|
5439
|
+
if ('error' in res) {
|
|
5440
|
+
throw new SolanaJSONRPCError(
|
|
5441
|
+
res.error,
|
|
5442
|
+
`failed to get stake minimum delegation`,
|
|
5443
|
+
);
|
|
5444
|
+
}
|
|
5445
|
+
return res.result;
|
|
5446
|
+
}
|
|
5447
|
+
|
|
3934
5448
|
/**
|
|
3935
5449
|
* Simulate a transaction
|
|
5450
|
+
*
|
|
5451
|
+
* @deprecated Instead, call {@link simulateTransaction} with {@link
|
|
5452
|
+
* VersionedTransaction} and {@link SimulateTransactionConfig} parameters
|
|
3936
5453
|
*/
|
|
3937
|
-
|
|
5454
|
+
simulateTransaction(
|
|
3938
5455
|
transactionOrMessage: Transaction | Message,
|
|
3939
5456
|
signers?: Array<Signer>,
|
|
3940
5457
|
includeAccounts?: boolean | Array<PublicKey>,
|
|
5458
|
+
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>>;
|
|
5459
|
+
|
|
5460
|
+
/**
|
|
5461
|
+
* Simulate a transaction
|
|
5462
|
+
*/
|
|
5463
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
5464
|
+
simulateTransaction(
|
|
5465
|
+
transaction: VersionedTransaction,
|
|
5466
|
+
config?: SimulateTransactionConfig,
|
|
5467
|
+
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>>;
|
|
5468
|
+
|
|
5469
|
+
/**
|
|
5470
|
+
* Simulate a transaction
|
|
5471
|
+
*/
|
|
5472
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
5473
|
+
async simulateTransaction(
|
|
5474
|
+
transactionOrMessage: VersionedTransaction | Transaction | Message,
|
|
5475
|
+
configOrSigners?: SimulateTransactionConfig | Array<Signer>,
|
|
5476
|
+
includeAccounts?: boolean | Array<PublicKey>,
|
|
3941
5477
|
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>> {
|
|
5478
|
+
if ('message' in transactionOrMessage) {
|
|
5479
|
+
const versionedTx = transactionOrMessage;
|
|
5480
|
+
const wireTransaction = versionedTx.serialize();
|
|
5481
|
+
const encodedTransaction =
|
|
5482
|
+
Buffer.from(wireTransaction).toString('base64');
|
|
5483
|
+
if (Array.isArray(configOrSigners) || includeAccounts !== undefined) {
|
|
5484
|
+
throw new Error('Invalid arguments');
|
|
5485
|
+
}
|
|
5486
|
+
|
|
5487
|
+
const config: any = configOrSigners || {};
|
|
5488
|
+
config.encoding = 'base64';
|
|
5489
|
+
if (!('commitment' in config)) {
|
|
5490
|
+
config.commitment = this.commitment;
|
|
5491
|
+
}
|
|
5492
|
+
|
|
5493
|
+
const args = [encodedTransaction, config];
|
|
5494
|
+
const unsafeRes = await this._rpcRequest('simulateTransaction', args);
|
|
5495
|
+
const res = create(unsafeRes, SimulatedTransactionResponseStruct);
|
|
5496
|
+
if ('error' in res) {
|
|
5497
|
+
throw new Error('failed to simulate transaction: ' + res.error.message);
|
|
5498
|
+
}
|
|
5499
|
+
return res.result;
|
|
5500
|
+
}
|
|
5501
|
+
|
|
3942
5502
|
let transaction;
|
|
3943
5503
|
if (transactionOrMessage instanceof Transaction) {
|
|
3944
5504
|
let originalTx: Transaction = transactionOrMessage;
|
|
3945
|
-
transaction = new Transaction(
|
|
3946
|
-
|
|
3947
|
-
nonceInfo: originalTx.nonceInfo,
|
|
3948
|
-
feePayer: originalTx.feePayer,
|
|
3949
|
-
signatures: [...originalTx.signatures],
|
|
3950
|
-
});
|
|
5505
|
+
transaction = new Transaction();
|
|
5506
|
+
transaction.feePayer = originalTx.feePayer;
|
|
3951
5507
|
transaction.instructions = transactionOrMessage.instructions;
|
|
5508
|
+
transaction.nonceInfo = originalTx.nonceInfo;
|
|
5509
|
+
transaction.signatures = originalTx.signatures;
|
|
3952
5510
|
} else {
|
|
3953
5511
|
transaction = Transaction.populate(transactionOrMessage);
|
|
3954
5512
|
// HACK: this function relies on mutating the populated transaction
|
|
3955
5513
|
transaction._message = transaction._json = undefined;
|
|
3956
5514
|
}
|
|
3957
5515
|
|
|
5516
|
+
if (configOrSigners !== undefined && !Array.isArray(configOrSigners)) {
|
|
5517
|
+
throw new Error('Invalid arguments');
|
|
5518
|
+
}
|
|
5519
|
+
|
|
5520
|
+
const signers = configOrSigners;
|
|
3958
5521
|
if (transaction.nonceInfo && signers) {
|
|
3959
5522
|
transaction.sign(...signers);
|
|
3960
5523
|
} else {
|
|
3961
5524
|
let disableCache = this._disableBlockhashCaching;
|
|
3962
5525
|
for (;;) {
|
|
3963
|
-
|
|
5526
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(
|
|
5527
|
+
disableCache,
|
|
5528
|
+
);
|
|
5529
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
5530
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
3964
5531
|
|
|
3965
5532
|
if (!signers) break;
|
|
3966
5533
|
|
|
@@ -4037,18 +5604,58 @@ export class Connection {
|
|
|
4037
5604
|
|
|
4038
5605
|
/**
|
|
4039
5606
|
* Sign and send a transaction
|
|
5607
|
+
*
|
|
5608
|
+
* @deprecated Instead, call {@link sendTransaction} with a {@link
|
|
5609
|
+
* VersionedTransaction}
|
|
4040
5610
|
*/
|
|
4041
|
-
|
|
5611
|
+
sendTransaction(
|
|
4042
5612
|
transaction: Transaction,
|
|
4043
5613
|
signers: Array<Signer>,
|
|
4044
5614
|
options?: SendOptions,
|
|
5615
|
+
): Promise<TransactionSignature>;
|
|
5616
|
+
|
|
5617
|
+
/**
|
|
5618
|
+
* Send a signed transaction
|
|
5619
|
+
*/
|
|
5620
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
5621
|
+
sendTransaction(
|
|
5622
|
+
transaction: VersionedTransaction,
|
|
5623
|
+
options?: SendOptions,
|
|
5624
|
+
): Promise<TransactionSignature>;
|
|
5625
|
+
|
|
5626
|
+
/**
|
|
5627
|
+
* Sign and send a transaction
|
|
5628
|
+
*/
|
|
5629
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
5630
|
+
async sendTransaction(
|
|
5631
|
+
transaction: VersionedTransaction | Transaction,
|
|
5632
|
+
signersOrOptions?: Array<Signer> | SendOptions,
|
|
5633
|
+
options?: SendOptions,
|
|
4045
5634
|
): Promise<TransactionSignature> {
|
|
5635
|
+
if ('version' in transaction) {
|
|
5636
|
+
if (signersOrOptions && Array.isArray(signersOrOptions)) {
|
|
5637
|
+
throw new Error('Invalid arguments');
|
|
5638
|
+
}
|
|
5639
|
+
|
|
5640
|
+
const wireTransaction = transaction.serialize();
|
|
5641
|
+
return await this.sendRawTransaction(wireTransaction, options);
|
|
5642
|
+
}
|
|
5643
|
+
|
|
5644
|
+
if (signersOrOptions === undefined || !Array.isArray(signersOrOptions)) {
|
|
5645
|
+
throw new Error('Invalid arguments');
|
|
5646
|
+
}
|
|
5647
|
+
|
|
5648
|
+
const signers = signersOrOptions;
|
|
4046
5649
|
if (transaction.nonceInfo) {
|
|
4047
5650
|
transaction.sign(...signers);
|
|
4048
5651
|
} else {
|
|
4049
5652
|
let disableCache = this._disableBlockhashCaching;
|
|
4050
5653
|
for (;;) {
|
|
4051
|
-
|
|
5654
|
+
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(
|
|
5655
|
+
disableCache,
|
|
5656
|
+
);
|
|
5657
|
+
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
5658
|
+
transaction.recentBlockhash = latestBlockhash.blockhash;
|
|
4052
5659
|
transaction.sign(...signers);
|
|
4053
5660
|
if (!transaction.signature) {
|
|
4054
5661
|
throw new Error('!signature'); // should never happen
|
|
@@ -4103,9 +5710,12 @@ export class Connection {
|
|
|
4103
5710
|
const preflightCommitment =
|
|
4104
5711
|
(options && options.preflightCommitment) || this.commitment;
|
|
4105
5712
|
|
|
4106
|
-
if (options && options.maxRetries) {
|
|
5713
|
+
if (options && options.maxRetries != null) {
|
|
4107
5714
|
config.maxRetries = options.maxRetries;
|
|
4108
5715
|
}
|
|
5716
|
+
if (options && options.minContextSlot != null) {
|
|
5717
|
+
config.minContextSlot = options.minContextSlot;
|
|
5718
|
+
}
|
|
4109
5719
|
if (skipPreflight) {
|
|
4110
5720
|
config.skipPreflight = skipPreflight;
|
|
4111
5721
|
}
|
|
@@ -4145,6 +5755,7 @@ export class Connection {
|
|
|
4145
5755
|
* @internal
|
|
4146
5756
|
*/
|
|
4147
5757
|
_wsOnError(err: Error) {
|
|
5758
|
+
this._rpcWebSocketConnected = false;
|
|
4148
5759
|
console.error('ws error:', err.message);
|
|
4149
5760
|
}
|
|
4150
5761
|
|
|
@@ -4152,6 +5763,13 @@ export class Connection {
|
|
|
4152
5763
|
* @internal
|
|
4153
5764
|
*/
|
|
4154
5765
|
_wsOnClose(code: number) {
|
|
5766
|
+
this._rpcWebSocketConnected = false;
|
|
5767
|
+
this._rpcWebSocketGeneration =
|
|
5768
|
+
(this._rpcWebSocketGeneration + 1) % Number.MAX_SAFE_INTEGER;
|
|
5769
|
+
if (this._rpcWebSocketIdleTimeout) {
|
|
5770
|
+
clearTimeout(this._rpcWebSocketIdleTimeout);
|
|
5771
|
+
this._rpcWebSocketIdleTimeout = null;
|
|
5772
|
+
}
|
|
4155
5773
|
if (this._rpcWebSocketHeartbeat) {
|
|
4156
5774
|
clearInterval(this._rpcWebSocketHeartbeat);
|
|
4157
5775
|
this._rpcWebSocketHeartbeat = null;
|
|
@@ -4168,13 +5786,60 @@ export class Connection {
|
|
|
4168
5786
|
Object.entries(
|
|
4169
5787
|
this._subscriptionsByHash as Record<SubscriptionConfigHash, Subscription>,
|
|
4170
5788
|
).forEach(([hash, subscription]) => {
|
|
4171
|
-
this.
|
|
5789
|
+
this._setSubscription(hash, {
|
|
4172
5790
|
...subscription,
|
|
4173
5791
|
state: 'pending',
|
|
4174
|
-
};
|
|
5792
|
+
});
|
|
4175
5793
|
});
|
|
4176
5794
|
}
|
|
4177
5795
|
|
|
5796
|
+
/**
|
|
5797
|
+
* @internal
|
|
5798
|
+
*/
|
|
5799
|
+
private _setSubscription(
|
|
5800
|
+
hash: SubscriptionConfigHash,
|
|
5801
|
+
nextSubscription: Subscription,
|
|
5802
|
+
) {
|
|
5803
|
+
const prevState = this._subscriptionsByHash[hash]?.state;
|
|
5804
|
+
this._subscriptionsByHash[hash] = nextSubscription;
|
|
5805
|
+
if (prevState !== nextSubscription.state) {
|
|
5806
|
+
const stateChangeCallbacks =
|
|
5807
|
+
this._subscriptionStateChangeCallbacksByHash[hash];
|
|
5808
|
+
if (stateChangeCallbacks) {
|
|
5809
|
+
stateChangeCallbacks.forEach(cb => {
|
|
5810
|
+
try {
|
|
5811
|
+
cb(nextSubscription.state);
|
|
5812
|
+
// eslint-disable-next-line no-empty
|
|
5813
|
+
} catch {}
|
|
5814
|
+
});
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
}
|
|
5818
|
+
|
|
5819
|
+
/**
|
|
5820
|
+
* @internal
|
|
5821
|
+
*/
|
|
5822
|
+
private _onSubscriptionStateChange(
|
|
5823
|
+
clientSubscriptionId: ClientSubscriptionId,
|
|
5824
|
+
callback: SubscriptionStateChangeCallback,
|
|
5825
|
+
): SubscriptionStateChangeDisposeFn {
|
|
5826
|
+
const hash =
|
|
5827
|
+
this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
|
|
5828
|
+
if (hash == null) {
|
|
5829
|
+
return () => {};
|
|
5830
|
+
}
|
|
5831
|
+
const stateChangeCallbacks = (this._subscriptionStateChangeCallbacksByHash[
|
|
5832
|
+
hash
|
|
5833
|
+
] ||= new Set());
|
|
5834
|
+
stateChangeCallbacks.add(callback);
|
|
5835
|
+
return () => {
|
|
5836
|
+
stateChangeCallbacks.delete(callback);
|
|
5837
|
+
if (stateChangeCallbacks.size === 0) {
|
|
5838
|
+
delete this._subscriptionStateChangeCallbacksByHash[hash];
|
|
5839
|
+
}
|
|
5840
|
+
};
|
|
5841
|
+
}
|
|
5842
|
+
|
|
4178
5843
|
/**
|
|
4179
5844
|
* @internal
|
|
4180
5845
|
*/
|
|
@@ -4210,13 +5875,22 @@ export class Connection {
|
|
|
4210
5875
|
return;
|
|
4211
5876
|
}
|
|
4212
5877
|
|
|
5878
|
+
const activeWebSocketGeneration = this._rpcWebSocketGeneration;
|
|
5879
|
+
const isCurrentConnectionStillActive = () => {
|
|
5880
|
+
return activeWebSocketGeneration === this._rpcWebSocketGeneration;
|
|
5881
|
+
};
|
|
5882
|
+
|
|
4213
5883
|
await Promise.all(
|
|
4214
|
-
Object.entries
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
5884
|
+
// Don't be tempted to change this to `Object.entries`. We call
|
|
5885
|
+
// `_updateSubscriptions` recursively when processing the state,
|
|
5886
|
+
// so it's important that we look up the *current* version of
|
|
5887
|
+
// each subscription, every time we process a hash.
|
|
5888
|
+
Object.keys(this._subscriptionsByHash).map(async hash => {
|
|
5889
|
+
const subscription = this._subscriptionsByHash[hash];
|
|
5890
|
+
if (subscription === undefined) {
|
|
5891
|
+
// This entry has since been deleted. Skip.
|
|
5892
|
+
return;
|
|
5893
|
+
}
|
|
4220
5894
|
switch (subscription.state) {
|
|
4221
5895
|
case 'pending':
|
|
4222
5896
|
case 'unsubscribed':
|
|
@@ -4244,62 +5918,23 @@ export class Connection {
|
|
|
4244
5918
|
return;
|
|
4245
5919
|
}
|
|
4246
5920
|
await (async () => {
|
|
4247
|
-
const {
|
|
4248
|
-
let args: IWSRequestParams;
|
|
4249
|
-
switch (method) {
|
|
4250
|
-
case 'accountSubscribe':
|
|
4251
|
-
args = this._buildArgs(
|
|
4252
|
-
[params.publicKey],
|
|
4253
|
-
params.commitment,
|
|
4254
|
-
'base64',
|
|
4255
|
-
);
|
|
4256
|
-
break;
|
|
4257
|
-
case 'logsSubscribe':
|
|
4258
|
-
args = this._buildArgs(
|
|
4259
|
-
[
|
|
4260
|
-
typeof params.filter === 'object'
|
|
4261
|
-
? {mentions: [params.filter.toString()]}
|
|
4262
|
-
: params.filter,
|
|
4263
|
-
],
|
|
4264
|
-
params.commitment,
|
|
4265
|
-
);
|
|
4266
|
-
break;
|
|
4267
|
-
case 'programSubscribe':
|
|
4268
|
-
args = this._buildArgs(
|
|
4269
|
-
[params.programId],
|
|
4270
|
-
params.commitment,
|
|
4271
|
-
'base64',
|
|
4272
|
-
params.filters
|
|
4273
|
-
? {
|
|
4274
|
-
filters: params.filters,
|
|
4275
|
-
}
|
|
4276
|
-
: undefined,
|
|
4277
|
-
);
|
|
4278
|
-
break;
|
|
4279
|
-
case 'signatureSubscribe':
|
|
4280
|
-
args = [params.signature, params.options].filter(Boolean);
|
|
4281
|
-
break;
|
|
4282
|
-
case 'rootSubscribe':
|
|
4283
|
-
case 'slotSubscribe':
|
|
4284
|
-
case 'slotsUpdatesSubscribe':
|
|
4285
|
-
args = [];
|
|
4286
|
-
break;
|
|
4287
|
-
}
|
|
5921
|
+
const {args, method} = subscription;
|
|
4288
5922
|
try {
|
|
4289
|
-
this.
|
|
5923
|
+
this._setSubscription(hash, {
|
|
4290
5924
|
...subscription,
|
|
4291
5925
|
state: 'subscribing',
|
|
4292
|
-
};
|
|
5926
|
+
});
|
|
4293
5927
|
const serverSubscriptionId: ServerSubscriptionId =
|
|
4294
5928
|
(await this._rpcWebSocket.call(method, args)) as number;
|
|
4295
|
-
this.
|
|
5929
|
+
this._setSubscription(hash, {
|
|
4296
5930
|
...subscription,
|
|
4297
5931
|
serverSubscriptionId,
|
|
4298
5932
|
state: 'subscribed',
|
|
4299
|
-
};
|
|
5933
|
+
});
|
|
4300
5934
|
this._subscriptionCallbacksByServerSubscriptionId[
|
|
4301
5935
|
serverSubscriptionId
|
|
4302
5936
|
] = subscription.callbacks;
|
|
5937
|
+
await this._updateSubscriptions();
|
|
4303
5938
|
} catch (e) {
|
|
4304
5939
|
if (e instanceof Error) {
|
|
4305
5940
|
console.error(
|
|
@@ -4308,12 +5943,14 @@ export class Connection {
|
|
|
4308
5943
|
e.message,
|
|
4309
5944
|
);
|
|
4310
5945
|
}
|
|
5946
|
+
if (!isCurrentConnectionStillActive()) {
|
|
5947
|
+
return;
|
|
5948
|
+
}
|
|
4311
5949
|
// TODO: Maybe add an 'errored' state or a retry limit?
|
|
4312
|
-
this.
|
|
5950
|
+
this._setSubscription(hash, {
|
|
4313
5951
|
...subscription,
|
|
4314
5952
|
state: 'pending',
|
|
4315
|
-
};
|
|
4316
|
-
} finally {
|
|
5953
|
+
});
|
|
4317
5954
|
await this._updateSubscriptions();
|
|
4318
5955
|
}
|
|
4319
5956
|
})();
|
|
@@ -4341,10 +5978,14 @@ export class Connection {
|
|
|
4341
5978
|
serverSubscriptionId,
|
|
4342
5979
|
);
|
|
4343
5980
|
} else {
|
|
4344
|
-
this.
|
|
5981
|
+
this._setSubscription(hash, {
|
|
5982
|
+
...subscription,
|
|
5983
|
+
state: 'unsubscribing',
|
|
5984
|
+
});
|
|
5985
|
+
this._setSubscription(hash, {
|
|
4345
5986
|
...subscription,
|
|
4346
5987
|
state: 'unsubscribing',
|
|
4347
|
-
};
|
|
5988
|
+
});
|
|
4348
5989
|
try {
|
|
4349
5990
|
await this._rpcWebSocket.call(unsubscribeMethod, [
|
|
4350
5991
|
serverSubscriptionId,
|
|
@@ -4353,19 +5994,22 @@ export class Connection {
|
|
|
4353
5994
|
if (e instanceof Error) {
|
|
4354
5995
|
console.error(`${unsubscribeMethod} error:`, e.message);
|
|
4355
5996
|
}
|
|
5997
|
+
if (!isCurrentConnectionStillActive()) {
|
|
5998
|
+
return;
|
|
5999
|
+
}
|
|
4356
6000
|
// TODO: Maybe add an 'errored' state or a retry limit?
|
|
4357
|
-
this.
|
|
6001
|
+
this._setSubscription(hash, {
|
|
4358
6002
|
...subscription,
|
|
4359
6003
|
state: 'subscribed',
|
|
4360
|
-
};
|
|
6004
|
+
});
|
|
4361
6005
|
await this._updateSubscriptions();
|
|
4362
6006
|
return;
|
|
4363
6007
|
}
|
|
4364
6008
|
}
|
|
4365
|
-
this.
|
|
6009
|
+
this._setSubscription(hash, {
|
|
4366
6010
|
...subscription,
|
|
4367
6011
|
state: 'unsubscribed',
|
|
4368
|
-
};
|
|
6012
|
+
});
|
|
4369
6013
|
await this._updateSubscriptions();
|
|
4370
6014
|
})();
|
|
4371
6015
|
}
|
|
@@ -4379,21 +6023,28 @@ export class Connection {
|
|
|
4379
6023
|
}
|
|
4380
6024
|
|
|
4381
6025
|
/**
|
|
4382
|
-
*
|
|
4383
6026
|
* @internal
|
|
4384
6027
|
*/
|
|
4385
|
-
|
|
6028
|
+
private _handleServerNotification<
|
|
6029
|
+
TCallback extends SubscriptionConfig['callback'],
|
|
6030
|
+
>(
|
|
4386
6031
|
serverSubscriptionId: ServerSubscriptionId,
|
|
4387
|
-
|
|
6032
|
+
callbackArgs: Parameters<TCallback>,
|
|
4388
6033
|
): void {
|
|
4389
6034
|
const callbacks =
|
|
4390
6035
|
this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId];
|
|
4391
|
-
if (callbacks
|
|
6036
|
+
if (callbacks === undefined) {
|
|
4392
6037
|
return;
|
|
4393
6038
|
}
|
|
4394
6039
|
callbacks.forEach(cb => {
|
|
4395
6040
|
try {
|
|
4396
|
-
cb(
|
|
6041
|
+
cb(
|
|
6042
|
+
// I failed to find a way to convince TypeScript that `cb` is of type
|
|
6043
|
+
// `TCallback` which is certainly compatible with `Parameters<TCallback>`.
|
|
6044
|
+
// See https://github.com/microsoft/TypeScript/issues/47615
|
|
6045
|
+
// @ts-ignore
|
|
6046
|
+
...callbackArgs,
|
|
6047
|
+
);
|
|
4397
6048
|
} catch (e) {
|
|
4398
6049
|
console.error(e);
|
|
4399
6050
|
}
|
|
@@ -4408,85 +6059,70 @@ export class Connection {
|
|
|
4408
6059
|
notification,
|
|
4409
6060
|
AccountNotificationResult,
|
|
4410
6061
|
);
|
|
4411
|
-
this.
|
|
6062
|
+
this._handleServerNotification<AccountChangeCallback>(subscription, [
|
|
4412
6063
|
result.value,
|
|
4413
6064
|
result.context,
|
|
4414
6065
|
]);
|
|
4415
6066
|
}
|
|
4416
6067
|
|
|
4417
6068
|
/**
|
|
4418
|
-
* @
|
|
6069
|
+
* @internal
|
|
4419
6070
|
*/
|
|
4420
|
-
_makeSubscription(
|
|
4421
|
-
|
|
4422
|
-
|
|
6071
|
+
private _makeSubscription(
|
|
6072
|
+
subscriptionConfig: SubscriptionConfig,
|
|
6073
|
+
/**
|
|
6074
|
+
* When preparing `args` for a call to `_makeSubscription`, be sure
|
|
6075
|
+
* to carefully apply a default `commitment` property, if necessary.
|
|
6076
|
+
*
|
|
6077
|
+
* - If the user supplied a `commitment` use that.
|
|
6078
|
+
* - Otherwise, if the `Connection::commitment` is set, use that.
|
|
6079
|
+
* - Otherwise, set it to the RPC server default: `finalized`.
|
|
6080
|
+
*
|
|
6081
|
+
* This is extremely important to ensure that these two fundamentally
|
|
6082
|
+
* identical subscriptions produce the same identifying hash:
|
|
6083
|
+
*
|
|
6084
|
+
* - A subscription made without specifying a commitment.
|
|
6085
|
+
* - A subscription made where the commitment specified is the same
|
|
6086
|
+
* as the default applied to the subscription above.
|
|
6087
|
+
*
|
|
6088
|
+
* Example; these two subscriptions must produce the same hash:
|
|
6089
|
+
*
|
|
6090
|
+
* - An `accountSubscribe` subscription for `'PUBKEY'`
|
|
6091
|
+
* - An `accountSubscribe` subscription for `'PUBKEY'` with commitment
|
|
6092
|
+
* `'finalized'`.
|
|
6093
|
+
*
|
|
6094
|
+
* See the 'making a subscription with defaulted params omitted' test
|
|
6095
|
+
* in `connection-subscriptions.ts` for more.
|
|
6096
|
+
*/
|
|
6097
|
+
args: IWSRequestParams,
|
|
4423
6098
|
): ClientSubscriptionId {
|
|
4424
6099
|
const clientSubscriptionId = this._nextClientSubscriptionId++;
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
case 'logsSubscribe':
|
|
4430
|
-
case 'programSubscribe':
|
|
4431
|
-
if (rawConfig.params.commitment === undefined) {
|
|
4432
|
-
subscriptionConfig = {
|
|
4433
|
-
...rawConfig,
|
|
4434
|
-
params: {
|
|
4435
|
-
...rawConfig.params,
|
|
4436
|
-
commitment: 'finalized',
|
|
4437
|
-
},
|
|
4438
|
-
} as SubscriptionConfig;
|
|
4439
|
-
} else {
|
|
4440
|
-
subscriptionConfig = rawConfig;
|
|
4441
|
-
}
|
|
4442
|
-
break;
|
|
4443
|
-
case 'signatureSubscribe':
|
|
4444
|
-
if (
|
|
4445
|
-
rawConfig.params.options &&
|
|
4446
|
-
rawConfig.params.options.commitment === undefined
|
|
4447
|
-
) {
|
|
4448
|
-
subscriptionConfig = {
|
|
4449
|
-
...rawConfig,
|
|
4450
|
-
params: {
|
|
4451
|
-
...rawConfig.params,
|
|
4452
|
-
options: {
|
|
4453
|
-
...rawConfig.params.options,
|
|
4454
|
-
commitment: 'finalized',
|
|
4455
|
-
},
|
|
4456
|
-
},
|
|
4457
|
-
};
|
|
4458
|
-
} else {
|
|
4459
|
-
subscriptionConfig = rawConfig;
|
|
4460
|
-
}
|
|
4461
|
-
break;
|
|
4462
|
-
default:
|
|
4463
|
-
subscriptionConfig = rawConfig;
|
|
4464
|
-
}
|
|
4465
|
-
const hash = hashSubscriptionConfig(subscriptionConfig);
|
|
6100
|
+
const hash = fastStableStringify(
|
|
6101
|
+
[subscriptionConfig.method, args],
|
|
6102
|
+
true /* isArrayProp */,
|
|
6103
|
+
);
|
|
4466
6104
|
const existingSubscription = this._subscriptionsByHash[hash];
|
|
4467
|
-
if (existingSubscription
|
|
6105
|
+
if (existingSubscription === undefined) {
|
|
4468
6106
|
this._subscriptionsByHash[hash] = {
|
|
4469
6107
|
...subscriptionConfig,
|
|
6108
|
+
args,
|
|
4470
6109
|
callbacks: new Set([subscriptionConfig.callback]),
|
|
4471
6110
|
state: 'pending',
|
|
4472
6111
|
};
|
|
4473
6112
|
} else {
|
|
4474
6113
|
existingSubscription.callbacks.add(subscriptionConfig.callback);
|
|
4475
6114
|
}
|
|
4476
|
-
|
|
6115
|
+
this._subscriptionHashByClientSubscriptionId[clientSubscriptionId] = hash;
|
|
4477
6116
|
this._subscriptionDisposeFunctionsByClientSubscriptionId[
|
|
4478
6117
|
clientSubscriptionId
|
|
4479
6118
|
] = async () => {
|
|
4480
|
-
if (unsubscribed) {
|
|
4481
|
-
return;
|
|
4482
|
-
}
|
|
4483
|
-
unsubscribed = true;
|
|
4484
6119
|
delete this._subscriptionDisposeFunctionsByClientSubscriptionId[
|
|
4485
6120
|
clientSubscriptionId
|
|
4486
6121
|
];
|
|
6122
|
+
delete this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
|
|
4487
6123
|
const subscription = this._subscriptionsByHash[hash];
|
|
4488
6124
|
assert(
|
|
4489
|
-
subscription,
|
|
6125
|
+
subscription !== undefined,
|
|
4490
6126
|
`Could not find a \`Subscription\` when tearing down client subscription #${clientSubscriptionId}`,
|
|
4491
6127
|
);
|
|
4492
6128
|
subscription.callbacks.delete(subscriptionConfig.callback);
|
|
@@ -4509,15 +6145,19 @@ export class Connection {
|
|
|
4509
6145
|
callback: AccountChangeCallback,
|
|
4510
6146
|
commitment?: Commitment,
|
|
4511
6147
|
): ClientSubscriptionId {
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
6148
|
+
const args = this._buildArgs(
|
|
6149
|
+
[publicKey.toBase58()],
|
|
6150
|
+
commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
6151
|
+
'base64',
|
|
6152
|
+
);
|
|
6153
|
+
return this._makeSubscription(
|
|
6154
|
+
{
|
|
6155
|
+
callback,
|
|
6156
|
+
method: 'accountSubscribe',
|
|
6157
|
+
unsubscribeMethod: 'accountUnsubscribe',
|
|
4518
6158
|
},
|
|
4519
|
-
|
|
4520
|
-
|
|
6159
|
+
args,
|
|
6160
|
+
);
|
|
4521
6161
|
}
|
|
4522
6162
|
|
|
4523
6163
|
/**
|
|
@@ -4542,7 +6182,7 @@ export class Connection {
|
|
|
4542
6182
|
notification,
|
|
4543
6183
|
ProgramAccountNotificationResult,
|
|
4544
6184
|
);
|
|
4545
|
-
this.
|
|
6185
|
+
this._handleServerNotification<ProgramAccountChangeCallback>(subscription, [
|
|
4546
6186
|
{
|
|
4547
6187
|
accountId: result.value.pubkey,
|
|
4548
6188
|
accountInfo: result.value.account,
|
|
@@ -4567,16 +6207,20 @@ export class Connection {
|
|
|
4567
6207
|
commitment?: Commitment,
|
|
4568
6208
|
filters?: GetProgramAccountsFilter[],
|
|
4569
6209
|
): ClientSubscriptionId {
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
6210
|
+
const args = this._buildArgs(
|
|
6211
|
+
[programId.toBase58()],
|
|
6212
|
+
commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
6213
|
+
'base64' /* encoding */,
|
|
6214
|
+
filters ? {filters: filters} : undefined /* extra */,
|
|
6215
|
+
);
|
|
6216
|
+
return this._makeSubscription(
|
|
6217
|
+
{
|
|
6218
|
+
callback,
|
|
6219
|
+
method: 'programSubscribe',
|
|
6220
|
+
unsubscribeMethod: 'programUnsubscribe',
|
|
4577
6221
|
},
|
|
4578
|
-
|
|
4579
|
-
|
|
6222
|
+
args,
|
|
6223
|
+
);
|
|
4580
6224
|
}
|
|
4581
6225
|
|
|
4582
6226
|
/**
|
|
@@ -4601,15 +6245,18 @@ export class Connection {
|
|
|
4601
6245
|
callback: LogsCallback,
|
|
4602
6246
|
commitment?: Commitment,
|
|
4603
6247
|
): ClientSubscriptionId {
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
6248
|
+
const args = this._buildArgs(
|
|
6249
|
+
[typeof filter === 'object' ? {mentions: [filter.toString()]} : filter],
|
|
6250
|
+
commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
6251
|
+
);
|
|
6252
|
+
return this._makeSubscription(
|
|
6253
|
+
{
|
|
6254
|
+
callback,
|
|
6255
|
+
method: 'logsSubscribe',
|
|
6256
|
+
unsubscribeMethod: 'logsUnsubscribe',
|
|
4610
6257
|
},
|
|
4611
|
-
|
|
4612
|
-
|
|
6258
|
+
args,
|
|
6259
|
+
);
|
|
4613
6260
|
}
|
|
4614
6261
|
|
|
4615
6262
|
/**
|
|
@@ -4628,7 +6275,7 @@ export class Connection {
|
|
|
4628
6275
|
*/
|
|
4629
6276
|
_wsOnLogsNotification(notification: Object) {
|
|
4630
6277
|
const {result, subscription} = create(notification, LogsNotificationResult);
|
|
4631
|
-
this.
|
|
6278
|
+
this._handleServerNotification<LogsCallback>(subscription, [
|
|
4632
6279
|
result.value,
|
|
4633
6280
|
result.context,
|
|
4634
6281
|
]);
|
|
@@ -4639,7 +6286,7 @@ export class Connection {
|
|
|
4639
6286
|
*/
|
|
4640
6287
|
_wsOnSlotNotification(notification: Object) {
|
|
4641
6288
|
const {result, subscription} = create(notification, SlotNotificationResult);
|
|
4642
|
-
this.
|
|
6289
|
+
this._handleServerNotification<SlotChangeCallback>(subscription, [result]);
|
|
4643
6290
|
}
|
|
4644
6291
|
|
|
4645
6292
|
/**
|
|
@@ -4649,12 +6296,14 @@ export class Connection {
|
|
|
4649
6296
|
* @return subscription id
|
|
4650
6297
|
*/
|
|
4651
6298
|
onSlotChange(callback: SlotChangeCallback): ClientSubscriptionId {
|
|
4652
|
-
return this._makeSubscription(
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
6299
|
+
return this._makeSubscription(
|
|
6300
|
+
{
|
|
6301
|
+
callback,
|
|
6302
|
+
method: 'slotSubscribe',
|
|
6303
|
+
unsubscribeMethod: 'slotUnsubscribe',
|
|
6304
|
+
},
|
|
6305
|
+
[] /* args */,
|
|
6306
|
+
);
|
|
4658
6307
|
}
|
|
4659
6308
|
|
|
4660
6309
|
/**
|
|
@@ -4679,7 +6328,7 @@ export class Connection {
|
|
|
4679
6328
|
notification,
|
|
4680
6329
|
SlotUpdateNotificationResult,
|
|
4681
6330
|
);
|
|
4682
|
-
this.
|
|
6331
|
+
this._handleServerNotification<SlotUpdateCallback>(subscription, [result]);
|
|
4683
6332
|
}
|
|
4684
6333
|
|
|
4685
6334
|
/**
|
|
@@ -4690,12 +6339,14 @@ export class Connection {
|
|
|
4690
6339
|
* @return subscription id
|
|
4691
6340
|
*/
|
|
4692
6341
|
onSlotUpdate(callback: SlotUpdateCallback): ClientSubscriptionId {
|
|
4693
|
-
return this._makeSubscription(
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
6342
|
+
return this._makeSubscription(
|
|
6343
|
+
{
|
|
6344
|
+
callback,
|
|
6345
|
+
method: 'slotsUpdatesSubscribe',
|
|
6346
|
+
unsubscribeMethod: 'slotsUpdatesUnsubscribe',
|
|
6347
|
+
},
|
|
6348
|
+
[] /* args */,
|
|
6349
|
+
);
|
|
4699
6350
|
}
|
|
4700
6351
|
|
|
4701
6352
|
/**
|
|
@@ -4716,7 +6367,7 @@ export class Connection {
|
|
|
4716
6367
|
* @internal
|
|
4717
6368
|
*/
|
|
4718
6369
|
|
|
4719
|
-
async _unsubscribeClientSubscription(
|
|
6370
|
+
private async _unsubscribeClientSubscription(
|
|
4720
6371
|
clientSubscriptionId: ClientSubscriptionId,
|
|
4721
6372
|
subscriptionName: string,
|
|
4722
6373
|
) {
|
|
@@ -4727,8 +6378,10 @@ export class Connection {
|
|
|
4727
6378
|
if (dispose) {
|
|
4728
6379
|
await dispose();
|
|
4729
6380
|
} else {
|
|
4730
|
-
|
|
4731
|
-
|
|
6381
|
+
console.warn(
|
|
6382
|
+
'Ignored unsubscribe request because an active subscription with id ' +
|
|
6383
|
+
`\`${clientSubscriptionId}\` for '${subscriptionName}' events ` +
|
|
6384
|
+
'could not be found.',
|
|
4732
6385
|
);
|
|
4733
6386
|
}
|
|
4734
6387
|
}
|
|
@@ -4800,7 +6453,7 @@ export class Connection {
|
|
|
4800
6453
|
*/
|
|
4801
6454
|
this._subscriptionsAutoDisposedByRpc.add(subscription);
|
|
4802
6455
|
}
|
|
4803
|
-
this.
|
|
6456
|
+
this._handleServerNotification<SignatureSubscriptionCallback>(
|
|
4804
6457
|
subscription,
|
|
4805
6458
|
result.value === 'receivedSignature'
|
|
4806
6459
|
? [{type: 'received'}, result.context]
|
|
@@ -4821,27 +6474,30 @@ export class Connection {
|
|
|
4821
6474
|
callback: SignatureResultCallback,
|
|
4822
6475
|
commitment?: Commitment,
|
|
4823
6476
|
): ClientSubscriptionId {
|
|
4824
|
-
const
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
//
|
|
6477
|
+
const args = this._buildArgs(
|
|
6478
|
+
[signature],
|
|
6479
|
+
commitment || this._commitment || 'finalized', // Apply connection/server default.
|
|
6480
|
+
);
|
|
6481
|
+
const clientSubscriptionId = this._makeSubscription(
|
|
6482
|
+
{
|
|
6483
|
+
callback: (notification, context) => {
|
|
6484
|
+
if (notification.type === 'status') {
|
|
6485
|
+
callback(notification.result, context);
|
|
6486
|
+
// Signatures subscriptions are auto-removed by the RPC service
|
|
6487
|
+
// so no need to explicitly send an unsubscribe message.
|
|
6488
|
+
try {
|
|
6489
|
+
this.removeSignatureListener(clientSubscriptionId);
|
|
6490
|
+
// eslint-disable-next-line no-empty
|
|
6491
|
+
} catch (_err) {
|
|
6492
|
+
// Already removed.
|
|
6493
|
+
}
|
|
4835
6494
|
}
|
|
4836
|
-
}
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
params: {
|
|
4840
|
-
options: {commitment},
|
|
4841
|
-
signature,
|
|
6495
|
+
},
|
|
6496
|
+
method: 'signatureSubscribe',
|
|
6497
|
+
unsubscribeMethod: 'signatureUnsubscribe',
|
|
4842
6498
|
},
|
|
4843
|
-
|
|
4844
|
-
|
|
6499
|
+
args,
|
|
6500
|
+
);
|
|
4845
6501
|
return clientSubscriptionId;
|
|
4846
6502
|
}
|
|
4847
6503
|
|
|
@@ -4860,25 +6516,35 @@ export class Connection {
|
|
|
4860
6516
|
callback: SignatureSubscriptionCallback,
|
|
4861
6517
|
options?: SignatureSubscriptionOptions,
|
|
4862
6518
|
): ClientSubscriptionId {
|
|
4863
|
-
const
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
6519
|
+
const {commitment, ...extra} = {
|
|
6520
|
+
...options,
|
|
6521
|
+
commitment:
|
|
6522
|
+
(options && options.commitment) || this._commitment || 'finalized', // Apply connection/server default.
|
|
6523
|
+
};
|
|
6524
|
+
const args = this._buildArgs(
|
|
6525
|
+
[signature],
|
|
6526
|
+
commitment,
|
|
6527
|
+
undefined /* encoding */,
|
|
6528
|
+
extra,
|
|
6529
|
+
);
|
|
6530
|
+
const clientSubscriptionId = this._makeSubscription(
|
|
6531
|
+
{
|
|
6532
|
+
callback: (notification, context) => {
|
|
6533
|
+
callback(notification, context);
|
|
6534
|
+
// Signatures subscriptions are auto-removed by the RPC service
|
|
6535
|
+
// so no need to explicitly send an unsubscribe message.
|
|
6536
|
+
try {
|
|
6537
|
+
this.removeSignatureListener(clientSubscriptionId);
|
|
6538
|
+
// eslint-disable-next-line no-empty
|
|
6539
|
+
} catch (_err) {
|
|
6540
|
+
// Already removed.
|
|
6541
|
+
}
|
|
6542
|
+
},
|
|
6543
|
+
method: 'signatureSubscribe',
|
|
6544
|
+
unsubscribeMethod: 'signatureUnsubscribe',
|
|
4879
6545
|
},
|
|
4880
|
-
|
|
4881
|
-
|
|
6546
|
+
args,
|
|
6547
|
+
);
|
|
4882
6548
|
return clientSubscriptionId;
|
|
4883
6549
|
}
|
|
4884
6550
|
|
|
@@ -4901,7 +6567,7 @@ export class Connection {
|
|
|
4901
6567
|
*/
|
|
4902
6568
|
_wsOnRootNotification(notification: Object) {
|
|
4903
6569
|
const {result, subscription} = create(notification, RootNotificationResult);
|
|
4904
|
-
this.
|
|
6570
|
+
this._handleServerNotification<RootChangeCallback>(subscription, [result]);
|
|
4905
6571
|
}
|
|
4906
6572
|
|
|
4907
6573
|
/**
|
|
@@ -4911,12 +6577,14 @@ export class Connection {
|
|
|
4911
6577
|
* @return subscription id
|
|
4912
6578
|
*/
|
|
4913
6579
|
onRootChange(callback: RootChangeCallback): ClientSubscriptionId {
|
|
4914
|
-
return this._makeSubscription(
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
6580
|
+
return this._makeSubscription(
|
|
6581
|
+
{
|
|
6582
|
+
callback,
|
|
6583
|
+
method: 'rootSubscribe',
|
|
6584
|
+
unsubscribeMethod: 'rootUnsubscribe',
|
|
6585
|
+
},
|
|
6586
|
+
[] /* args */,
|
|
6587
|
+
);
|
|
4920
6588
|
}
|
|
4921
6589
|
|
|
4922
6590
|
/**
|