@solana/web3.js 2.0.0-experimental.a8f1f88 → 2.0.0-experimental.a9e6db3

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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2018 Solana Labs, Inc
1
+ Copyright (c) 2023 Solana Labs, Inc
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
package/README.md CHANGED
@@ -77,19 +77,19 @@ Unimplemented.
77
77
 
78
78
  Client applications primarily deal with addresses and public keys in the form of base58-encoded strings. Addresses and public keys returned from the RPC API conform to the type `Base58EncodedAddress`. You can use a value of that type wherever a base58-encoded address or key is expected.
79
79
 
80
- From time to time you might acquire a string, that you expect to validate as an address, from an untrusted network API or user input. To assert that such an arbitrary string is a base58-encoded address, use the `assertIsBase58EncodedAddress` function.
80
+ From time to time you might acquire a string, that you expect to validate as an address, from an untrusted network API or user input. To assert that such an arbitrary string is a base58-encoded address, use the `assertIsAddress` function.
81
81
 
82
82
  ```ts
83
- import { assertIsBase58EncodedAddress } from '@solana/web3.js`;
83
+ import { assertIsAddress } from '@solana/web3.js';
84
84
 
85
85
  // Imagine a function that fetches an account's balance when a user submits a form.
86
- function handleSubmit() {
86
+ async function handleSubmit() {
87
87
  // We know only that what the user typed conforms to the `string` type.
88
88
  const address: string = accountAddressInput.value;
89
89
  try {
90
90
  // If this type assertion function doesn't throw, then
91
91
  // Typescript will upcast `address` to `Base58EncodedAddress`.
92
- assertIsBase58EncodedAddress(address);
92
+ assertIsAddress(address);
93
93
  // At this point, `address` is a `Base58EncodedAddress` that can be used with the RPC.
94
94
  const balanceInLamports = await rpc.getBalance(address).send();
95
95
  } catch (e) {
@@ -5,14 +5,161 @@ var instructions = require('@solana/instructions');
5
5
  var keys = require('@solana/keys');
6
6
  var transactions = require('@solana/transactions');
7
7
  var rpcCore = require('@solana/rpc-core');
8
+ var functional = require('@solana/functional');
8
9
  var rpcTransport = require('@solana/rpc-transport');
9
10
  var fastStableStringify = require('fast-stable-stringify');
11
+ var umiSerializers = require('@metaplex-foundation/umi-serializers');
10
12
 
11
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
14
 
13
15
  var fastStableStringify__default = /*#__PURE__*/_interopDefault(fastStableStringify);
14
16
 
15
- // src/index.ts
17
+ // ../build-scripts/env-shim.ts
18
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
19
+
20
+ // src/transaction-confirmation-strategy-racer.ts
21
+ async function raceStrategies(signature, config, getSpecificStrategiesForRace) {
22
+ const { abortSignal: callerAbortSignal, commitment, getRecentSignatureConfirmationPromise } = config;
23
+ callerAbortSignal.throwIfAborted();
24
+ const abortController = new AbortController();
25
+ function handleAbort() {
26
+ abortController.abort();
27
+ }
28
+ callerAbortSignal.addEventListener("abort", handleAbort, { signal: abortController.signal });
29
+ try {
30
+ const specificStrategies = getSpecificStrategiesForRace({
31
+ ...config,
32
+ abortSignal: abortController.signal
33
+ });
34
+ return await Promise.race([
35
+ getRecentSignatureConfirmationPromise({
36
+ abortSignal: abortController.signal,
37
+ commitment,
38
+ signature
39
+ }),
40
+ ...specificStrategies
41
+ ]);
42
+ } finally {
43
+ abortController.abort();
44
+ }
45
+ }
46
+ function createRecentSignatureConfirmationPromiseFactory(rpc, rpcSubscriptions) {
47
+ return async function getRecentSignatureConfirmationPromise({
48
+ abortSignal: callerAbortSignal,
49
+ commitment,
50
+ signature
51
+ }) {
52
+ const abortController = new AbortController();
53
+ function handleAbort() {
54
+ abortController.abort();
55
+ }
56
+ callerAbortSignal.addEventListener("abort", handleAbort, { signal: abortController.signal });
57
+ const signatureStatusNotifications = await rpcSubscriptions.signatureNotifications(signature, { commitment }).subscribe({ abortSignal: abortController.signal });
58
+ const signatureDidCommitPromise = (async () => {
59
+ for await (const signatureStatusNotification of signatureStatusNotifications) {
60
+ if (signatureStatusNotification.value.err) {
61
+ throw new Error(`The transaction with signature \`${signature}\` failed.`, {
62
+ cause: signatureStatusNotification.value.err
63
+ });
64
+ } else {
65
+ return;
66
+ }
67
+ }
68
+ })();
69
+ const signatureStatusLookupPromise = (async () => {
70
+ const { value: signatureStatusResults } = await rpc.getSignatureStatuses([signature]).send({ abortSignal: abortController.signal });
71
+ const signatureStatus = signatureStatusResults[0];
72
+ if (signatureStatus && signatureStatus.confirmationStatus && rpcCore.commitmentComparator(signatureStatus.confirmationStatus, commitment) >= 0) {
73
+ return;
74
+ } else {
75
+ await new Promise(() => {
76
+ });
77
+ }
78
+ })();
79
+ try {
80
+ return await Promise.race([signatureDidCommitPromise, signatureStatusLookupPromise]);
81
+ } finally {
82
+ abortController.abort();
83
+ }
84
+ };
85
+ }
86
+
87
+ // src/transaction-confirmation-strategy-timeout.ts
88
+ async function getTimeoutPromise({ abortSignal: callerAbortSignal, commitment }) {
89
+ return await new Promise((_, reject) => {
90
+ const handleAbort = (e) => {
91
+ clearTimeout(timeoutId);
92
+ const abortError = new DOMException(e.target.reason, "AbortError");
93
+ reject(abortError);
94
+ };
95
+ callerAbortSignal.addEventListener("abort", handleAbort);
96
+ const timeoutMs = commitment === "processed" ? 3e4 : 6e4;
97
+ const startMs = performance.now();
98
+ const timeoutId = (
99
+ // We use `setTimeout` instead of `AbortSignal.timeout()` because we want to measure
100
+ // elapsed time instead of active time.
101
+ // See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static
102
+ setTimeout(() => {
103
+ const elapsedMs = performance.now() - startMs;
104
+ reject(new DOMException(`Timeout elapsed after ${elapsedMs} ms`, "TimeoutError"));
105
+ }, timeoutMs)
106
+ );
107
+ });
108
+ }
109
+
110
+ // src/airdrop-confirmer.ts
111
+ function createDefaultSignatureOnlyRecentTransactionConfirmer({
112
+ rpc,
113
+ rpcSubscriptions
114
+ }) {
115
+ const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory(
116
+ rpc,
117
+ rpcSubscriptions
118
+ );
119
+ return async function confirmSignatureOnlyRecentTransaction(config) {
120
+ await waitForRecentTransactionConfirmationUntilTimeout({
121
+ ...config,
122
+ getRecentSignatureConfirmationPromise,
123
+ getTimeoutPromise
124
+ });
125
+ };
126
+ }
127
+ async function waitForRecentTransactionConfirmationUntilTimeout(config) {
128
+ await raceStrategies(
129
+ config.signature,
130
+ config,
131
+ function getSpecificStrategiesForRace({ abortSignal, commitment, getTimeoutPromise: getTimeoutPromise2 }) {
132
+ return [
133
+ getTimeoutPromise2({
134
+ abortSignal,
135
+ commitment
136
+ })
137
+ ];
138
+ }
139
+ );
140
+ }
141
+
142
+ // src/airdrop.ts
143
+ async function requestAndConfirmAirdrop({
144
+ abortSignal,
145
+ commitment,
146
+ lamports,
147
+ recipientAddress,
148
+ rpc,
149
+ rpcSubscriptions
150
+ }) {
151
+ const airdropTransactionSignature = await rpc.requestAirdrop(recipientAddress, lamports, { commitment }).send({ abortSignal });
152
+ const confirmSignatureOnlyTransaction = createDefaultSignatureOnlyRecentTransactionConfirmer({
153
+ rpc,
154
+ rpcSubscriptions
155
+ });
156
+ await confirmSignatureOnlyTransaction({
157
+ abortSignal,
158
+ commitment,
159
+ signature: airdropTransactionSignature
160
+ });
161
+ return airdropTransactionSignature;
162
+ }
16
163
 
17
164
  // src/rpc-integer-overflow-error.ts
18
165
  var SolanaJsonRpcIntegerOverflowError = class extends Error {
@@ -50,6 +197,193 @@ var DEFAULT_RPC_CONFIG = {
50
197
  }
51
198
  };
52
199
 
200
+ // src/cached-abortable-iterable.ts
201
+ function registerIterableCleanup(iterable, cleanupFn) {
202
+ (async () => {
203
+ try {
204
+ for await (const _ of iterable)
205
+ ;
206
+ } catch {
207
+ } finally {
208
+ cleanupFn();
209
+ }
210
+ })();
211
+ }
212
+ function getCachedAbortableIterableFactory({
213
+ getAbortSignalFromInputArgs,
214
+ getCacheEntryMissingError,
215
+ getCacheKeyFromInputArgs,
216
+ onCacheHit,
217
+ onCreateIterable
218
+ }) {
219
+ const cache = /* @__PURE__ */ new Map();
220
+ function getCacheEntryOrThrow(cacheKey) {
221
+ const currentCacheEntry = cache.get(cacheKey);
222
+ if (!currentCacheEntry) {
223
+ throw getCacheEntryMissingError(cacheKey);
224
+ }
225
+ return currentCacheEntry;
226
+ }
227
+ return async (...args) => {
228
+ const cacheKey = getCacheKeyFromInputArgs(...args);
229
+ const signal = getAbortSignalFromInputArgs(...args);
230
+ if (cacheKey === void 0) {
231
+ return await onCreateIterable(signal, ...args);
232
+ }
233
+ const cleanup = () => {
234
+ cache.delete(cacheKey);
235
+ signal.removeEventListener("abort", handleAbort);
236
+ };
237
+ const handleAbort = () => {
238
+ const cacheEntry = getCacheEntryOrThrow(cacheKey);
239
+ if (cacheEntry.purgeScheduled !== true) {
240
+ cacheEntry.purgeScheduled = true;
241
+ globalThis.queueMicrotask(() => {
242
+ cacheEntry.purgeScheduled = false;
243
+ if (cacheEntry.referenceCount === 0) {
244
+ cacheEntry.abortController.abort();
245
+ cleanup();
246
+ }
247
+ });
248
+ }
249
+ cacheEntry.referenceCount--;
250
+ };
251
+ signal.addEventListener("abort", handleAbort);
252
+ try {
253
+ const cacheEntry = cache.get(cacheKey);
254
+ if (!cacheEntry) {
255
+ const singletonAbortController = new AbortController();
256
+ const newIterablePromise = onCreateIterable(singletonAbortController.signal, ...args);
257
+ const newCacheEntry = {
258
+ abortController: singletonAbortController,
259
+ iterable: newIterablePromise,
260
+ purgeScheduled: false,
261
+ referenceCount: 1
262
+ };
263
+ cache.set(cacheKey, newCacheEntry);
264
+ const newIterable = await newIterablePromise;
265
+ registerIterableCleanup(newIterable, cleanup);
266
+ newCacheEntry.iterable = newIterable;
267
+ return newIterable;
268
+ } else {
269
+ cacheEntry.referenceCount++;
270
+ const iterableOrIterablePromise = cacheEntry.iterable;
271
+ const cachedIterable = "then" in iterableOrIterablePromise ? await iterableOrIterablePromise : iterableOrIterablePromise;
272
+ await onCacheHit(cachedIterable, ...args);
273
+ return cachedIterable;
274
+ }
275
+ } catch (e) {
276
+ cleanup();
277
+ throw e;
278
+ }
279
+ };
280
+ }
281
+
282
+ // src/rpc-subscription-coalescer.ts
283
+ var EXPLICIT_ABORT_TOKEN = Symbol(
284
+ __DEV__ ? "This symbol is thrown from a subscription's iterator when the subscription is explicitly aborted by the user" : void 0
285
+ );
286
+ function registerIterableCleanup2(iterable, cleanupFn) {
287
+ (async () => {
288
+ try {
289
+ for await (const _ of iterable)
290
+ ;
291
+ } catch {
292
+ } finally {
293
+ cleanupFn();
294
+ }
295
+ })();
296
+ }
297
+ function getRpcSubscriptionsWithSubscriptionCoalescing({
298
+ getDeduplicationKey,
299
+ rpcSubscriptions
300
+ }) {
301
+ const cache = /* @__PURE__ */ new Map();
302
+ return new Proxy(rpcSubscriptions, {
303
+ defineProperty() {
304
+ return false;
305
+ },
306
+ deleteProperty() {
307
+ return false;
308
+ },
309
+ get(target, p, receiver) {
310
+ const subscriptionMethod = Reflect.get(target, p, receiver);
311
+ if (typeof subscriptionMethod !== "function") {
312
+ return subscriptionMethod;
313
+ }
314
+ return function(...rawParams) {
315
+ const deduplicationKey = getDeduplicationKey(p, rawParams);
316
+ if (deduplicationKey === void 0) {
317
+ return subscriptionMethod(...rawParams);
318
+ }
319
+ if (cache.has(deduplicationKey)) {
320
+ return cache.get(deduplicationKey);
321
+ }
322
+ const iterableFactory = getCachedAbortableIterableFactory({
323
+ getAbortSignalFromInputArgs: ({ abortSignal }) => abortSignal,
324
+ getCacheEntryMissingError(deduplicationKey2) {
325
+ return new Error(
326
+ `Found no cache entry for subscription with deduplication key \`${deduplicationKey2?.toString()}\``
327
+ );
328
+ },
329
+ getCacheKeyFromInputArgs: () => deduplicationKey,
330
+ async onCacheHit(_iterable, _config) {
331
+ },
332
+ async onCreateIterable(abortSignal, config) {
333
+ const pendingSubscription2 = subscriptionMethod(
334
+ ...rawParams
335
+ );
336
+ const iterable = await pendingSubscription2.subscribe({
337
+ ...config,
338
+ abortSignal
339
+ });
340
+ registerIterableCleanup2(iterable, () => {
341
+ cache.delete(deduplicationKey);
342
+ });
343
+ return iterable;
344
+ }
345
+ });
346
+ const pendingSubscription = {
347
+ async subscribe(...args) {
348
+ const iterable = await iterableFactory(...args);
349
+ const { abortSignal } = args[0];
350
+ let abortPromise;
351
+ return {
352
+ ...iterable,
353
+ async *[Symbol.asyncIterator]() {
354
+ abortPromise || (abortPromise = abortSignal.aborted ? Promise.reject(EXPLICIT_ABORT_TOKEN) : new Promise((_, reject) => {
355
+ abortSignal.addEventListener("abort", () => {
356
+ reject(EXPLICIT_ABORT_TOKEN);
357
+ });
358
+ }));
359
+ try {
360
+ const iterator = iterable[Symbol.asyncIterator]();
361
+ while (true) {
362
+ const iteratorResult = await Promise.race([iterator.next(), abortPromise]);
363
+ if (iteratorResult.done) {
364
+ return;
365
+ } else {
366
+ yield iteratorResult.value;
367
+ }
368
+ }
369
+ } catch (e) {
370
+ if (e === EXPLICIT_ABORT_TOKEN) {
371
+ return;
372
+ }
373
+ cache.delete(deduplicationKey);
374
+ throw e;
375
+ }
376
+ }
377
+ };
378
+ }
379
+ };
380
+ cache.set(deduplicationKey, pendingSubscription);
381
+ return pendingSubscription;
382
+ };
383
+ }
384
+ });
385
+ }
386
+
53
387
  // src/rpc.ts
54
388
  function createSolanaRpc(config) {
55
389
  return rpcTransport.createJsonRpc({
@@ -58,9 +392,21 @@ function createSolanaRpc(config) {
58
392
  });
59
393
  }
60
394
  function createSolanaRpcSubscriptions(config) {
395
+ return functional.pipe(
396
+ rpcTransport.createJsonSubscriptionRpc({
397
+ ...config,
398
+ api: rpcCore.createSolanaRpcSubscriptionsApi(DEFAULT_RPC_CONFIG)
399
+ }),
400
+ (rpcSubscriptions) => getRpcSubscriptionsWithSubscriptionCoalescing({
401
+ getDeduplicationKey: (...args) => fastStableStringify__default.default(args),
402
+ rpcSubscriptions
403
+ })
404
+ );
405
+ }
406
+ function createSolanaRpcSubscriptions_UNSTABLE(config) {
61
407
  return rpcTransport.createJsonSubscriptionRpc({
62
408
  ...config,
63
- api: rpcCore.createSolanaRpcSubscriptionsApi(DEFAULT_RPC_CONFIG)
409
+ api: rpcCore.createSolanaRpcSubscriptionsApi_UNSTABLE(DEFAULT_RPC_CONFIG)
64
410
  });
65
411
  }
66
412
 
@@ -115,13 +461,14 @@ function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
115
461
  }
116
462
  };
117
463
  }
118
- function getSolanaRpcPayloadDeduplicationKey(payload) {
464
+ function isJsonRpcPayload(payload) {
119
465
  if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
120
- return;
121
- }
122
- if ("jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && "params" in payload) {
123
- return fastStableStringify__default.default([payload.method, payload.params]);
466
+ return false;
124
467
  }
468
+ return "jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && typeof payload.method === "string" && "params" in payload;
469
+ }
470
+ function getSolanaRpcPayloadDeduplicationKey(payload) {
471
+ return isJsonRpcPayload(payload) ? fastStableStringify__default.default([payload.method, payload.params]) : void 0;
125
472
  }
126
473
 
127
474
  // src/rpc-transport.ts
@@ -133,7 +480,7 @@ function normalizeHeaders(headers) {
133
480
  return out;
134
481
  }
135
482
  function createDefaultRpcTransport(config) {
136
- return getRpcTransportWithRequestCoalescing(
483
+ return functional.pipe(
137
484
  rpcTransport.createHttpTransport({
138
485
  ...config,
139
486
  headers: {
@@ -144,7 +491,7 @@ function createDefaultRpcTransport(config) {
144
491
  }
145
492
  }
146
493
  }),
147
- getSolanaRpcPayloadDeduplicationKey
494
+ (transport) => getRpcTransportWithRequestCoalescing(transport, getSolanaRpcPayloadDeduplicationKey)
148
495
  );
149
496
  }
150
497
 
@@ -158,11 +505,12 @@ function getWebSocketTransportWithAutoping({ intervalMs, transport }) {
158
505
  return async (...args) => {
159
506
  const connection = await transport(...args);
160
507
  let intervalId;
508
+ function sendPing() {
509
+ connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(PING_PAYLOAD);
510
+ }
161
511
  function restartPingTimer() {
162
512
  clearInterval(intervalId);
163
- intervalId = setInterval(() => {
164
- connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(PING_PAYLOAD);
165
- }, intervalMs);
513
+ intervalId = setInterval(sendPing, intervalMs);
166
514
  }
167
515
  if (pingableConnections.has(connection) === false) {
168
516
  pingableConnections.set(connection, {
@@ -181,31 +529,237 @@ function getWebSocketTransportWithAutoping({ intervalMs, transport }) {
181
529
  } finally {
182
530
  pingableConnections.delete(connection);
183
531
  clearInterval(intervalId);
532
+ if (handleOffline) {
533
+ globalThis.window.removeEventListener("offline", handleOffline);
534
+ }
535
+ if (handleOnline) {
536
+ globalThis.window.removeEventListener("online", handleOnline);
537
+ }
184
538
  }
185
539
  })();
186
- restartPingTimer();
540
+ if (globalThis.navigator.onLine) {
541
+ restartPingTimer();
542
+ }
543
+ let handleOffline;
544
+ let handleOnline;
545
+ {
546
+ handleOffline = () => {
547
+ clearInterval(intervalId);
548
+ };
549
+ handleOnline = () => {
550
+ sendPing();
551
+ restartPingTimer();
552
+ };
553
+ globalThis.window.addEventListener("offline", handleOffline);
554
+ globalThis.window.addEventListener("online", handleOnline);
555
+ }
187
556
  }
188
557
  return pingableConnections.get(connection);
189
558
  };
190
559
  }
191
560
 
561
+ // src/rpc-websocket-connection-sharding.ts
562
+ var NULL_SHARD_CACHE_KEY = Symbol(
563
+ __DEV__ ? "Cache key to use when there is no connection sharding strategy" : void 0
564
+ );
565
+ function getWebSocketTransportWithConnectionSharding({ getShard, transport }) {
566
+ return getCachedAbortableIterableFactory({
567
+ getAbortSignalFromInputArgs: ({ signal }) => signal,
568
+ getCacheEntryMissingError(shardKey) {
569
+ return new Error(`Found no cache entry for connection with shard key \`${shardKey?.toString()}\``);
570
+ },
571
+ getCacheKeyFromInputArgs: ({ payload }) => getShard ? getShard(payload) : NULL_SHARD_CACHE_KEY,
572
+ onCacheHit: (connection, { payload }) => connection.send_DO_NOT_USE_OR_YOU_WILL_BE_FIRED(payload),
573
+ onCreateIterable: (abortSignal, config) => transport({
574
+ ...config,
575
+ signal: abortSignal
576
+ })
577
+ });
578
+ }
579
+
192
580
  // src/rpc-websocket-transport.ts
193
581
  function createDefaultRpcSubscriptionsTransport(config) {
194
- const { intervalMs, ...rest } = config;
195
- return getWebSocketTransportWithAutoping({
196
- intervalMs: intervalMs ?? 5e3,
197
- transport: rpcTransport.createWebSocketTransport({
582
+ const { getShard, intervalMs, ...rest } = config;
583
+ return functional.pipe(
584
+ rpcTransport.createWebSocketTransport({
198
585
  ...rest,
199
586
  sendBufferHighWatermark: config.sendBufferHighWatermark ?? // Let 128KB of data into the WebSocket buffer before buffering it in the app.
200
587
  131072
588
+ }),
589
+ (transport) => getWebSocketTransportWithAutoping({
590
+ intervalMs: intervalMs ?? 5e3,
591
+ transport
592
+ }),
593
+ (transport) => getWebSocketTransportWithConnectionSharding({
594
+ getShard,
595
+ transport
201
596
  })
202
- });
597
+ );
598
+ }
599
+
600
+ // src/transaction-confirmation-strategy-blockheight.ts
601
+ function createBlockHeightExceedencePromiseFactory(rpcSubscriptions) {
602
+ return async function getBlockHeightExceedencePromise({ abortSignal: callerAbortSignal, lastValidBlockHeight }) {
603
+ const abortController = new AbortController();
604
+ function handleAbort() {
605
+ abortController.abort();
606
+ }
607
+ callerAbortSignal.addEventListener("abort", handleAbort, { signal: abortController.signal });
608
+ const slotNotifications = await rpcSubscriptions.slotNotifications().subscribe({ abortSignal: abortController.signal });
609
+ try {
610
+ for await (const slotNotification of slotNotifications) {
611
+ if (slotNotification.slot > lastValidBlockHeight) {
612
+ throw new Error(
613
+ "The network has progressed past the last block for which this transaction could have committed."
614
+ );
615
+ }
616
+ }
617
+ } finally {
618
+ abortController.abort();
619
+ }
620
+ };
621
+ }
622
+ var NONCE_VALUE_OFFSET = 4 + // version(u32)
623
+ 4 + // state(u32)
624
+ 32;
625
+ function createNonceInvalidationPromiseFactory(rpc, rpcSubscriptions) {
626
+ return async function getNonceInvalidationPromise({
627
+ abortSignal: callerAbortSignal,
628
+ commitment,
629
+ currentNonceValue,
630
+ nonceAccountAddress
631
+ }) {
632
+ const abortController = new AbortController();
633
+ function handleAbort() {
634
+ abortController.abort();
635
+ }
636
+ callerAbortSignal.addEventListener("abort", handleAbort, { signal: abortController.signal });
637
+ const accountNotifications = await rpcSubscriptions.accountNotifications(nonceAccountAddress, { commitment, encoding: "base64" }).subscribe({ abortSignal: abortController.signal });
638
+ function getNonceFromAccountData([base64EncodedBytes]) {
639
+ const data = umiSerializers.base64.serialize(base64EncodedBytes);
640
+ const nonceValueBytes = data.slice(NONCE_VALUE_OFFSET, NONCE_VALUE_OFFSET + 32);
641
+ return umiSerializers.base58.deserialize(nonceValueBytes)[0];
642
+ }
643
+ const nonceAccountDidAdvancePromise = (async () => {
644
+ for await (const accountNotification of accountNotifications) {
645
+ const nonceValue = getNonceFromAccountData(accountNotification.value.data);
646
+ if (nonceValue !== currentNonceValue) {
647
+ throw new Error(
648
+ `The nonce \`${currentNonceValue}\` is no longer valid. It has advanced to \`${nonceValue}\`.`
649
+ );
650
+ }
651
+ }
652
+ })();
653
+ const nonceIsAlreadyInvalidPromise = (async () => {
654
+ const { value: nonceAccount } = await rpc.getAccountInfo(nonceAccountAddress, {
655
+ commitment,
656
+ dataSlice: { length: 32, offset: NONCE_VALUE_OFFSET },
657
+ encoding: "base58"
658
+ }).send({ abortSignal: abortController.signal });
659
+ if (!nonceAccount) {
660
+ throw new Error(`No nonce account could be found at address \`${nonceAccountAddress}\`.`);
661
+ }
662
+ const nonceValue = (
663
+ // This works because we asked for the exact slice of data representing the nonce
664
+ // value, and furthermore asked for it in `base58` encoding.
665
+ nonceAccount.data[0]
666
+ );
667
+ if (nonceValue !== currentNonceValue) {
668
+ throw new Error(
669
+ `The nonce \`${currentNonceValue}\` is no longer valid. It has advanced to \`${nonceValue}\`.`
670
+ );
671
+ } else {
672
+ await new Promise(() => {
673
+ });
674
+ }
675
+ })();
676
+ try {
677
+ return await Promise.race([nonceAccountDidAdvancePromise, nonceIsAlreadyInvalidPromise]);
678
+ } finally {
679
+ abortController.abort();
680
+ }
681
+ };
682
+ }
683
+
684
+ // src/transaction-confirmation.ts
685
+ function createDefaultDurableNonceTransactionConfirmer({
686
+ rpc,
687
+ rpcSubscriptions
688
+ }) {
689
+ const getNonceInvalidationPromise = createNonceInvalidationPromiseFactory(rpc, rpcSubscriptions);
690
+ const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory(
691
+ rpc,
692
+ rpcSubscriptions
693
+ );
694
+ return async function confirmDurableNonceTransaction(config) {
695
+ await waitForDurableNonceTransactionConfirmation({
696
+ ...config,
697
+ getNonceInvalidationPromise,
698
+ getRecentSignatureConfirmationPromise
699
+ });
700
+ };
701
+ }
702
+ function createDefaultRecentTransactionConfirmer({
703
+ rpc,
704
+ rpcSubscriptions
705
+ }) {
706
+ const getBlockHeightExceedencePromise = createBlockHeightExceedencePromiseFactory(rpcSubscriptions);
707
+ const getRecentSignatureConfirmationPromise = createRecentSignatureConfirmationPromiseFactory(
708
+ rpc,
709
+ rpcSubscriptions
710
+ );
711
+ return async function confirmRecentTransaction(config) {
712
+ await waitForRecentTransactionConfirmation({
713
+ ...config,
714
+ getBlockHeightExceedencePromise,
715
+ getRecentSignatureConfirmationPromise
716
+ });
717
+ };
718
+ }
719
+ async function waitForDurableNonceTransactionConfirmation(config) {
720
+ await raceStrategies(
721
+ transactions.getSignatureFromTransaction(config.transaction),
722
+ config,
723
+ function getSpecificStrategiesForRace({ abortSignal, commitment, getNonceInvalidationPromise, transaction }) {
724
+ return [
725
+ getNonceInvalidationPromise({
726
+ abortSignal,
727
+ commitment,
728
+ currentNonceValue: transaction.lifetimeConstraint.nonce,
729
+ nonceAccountAddress: transaction.instructions[0].accounts[0].address
730
+ })
731
+ ];
732
+ }
733
+ );
734
+ }
735
+ async function waitForRecentTransactionConfirmation(config) {
736
+ await raceStrategies(
737
+ transactions.getSignatureFromTransaction(config.transaction),
738
+ config,
739
+ function getSpecificStrategiesForRace({ abortSignal, getBlockHeightExceedencePromise, transaction }) {
740
+ return [
741
+ getBlockHeightExceedencePromise({
742
+ abortSignal,
743
+ lastValidBlockHeight: transaction.lifetimeConstraint.lastValidBlockHeight
744
+ })
745
+ ];
746
+ }
747
+ );
203
748
  }
204
749
 
750
+ exports.createBlockHeightExceedencePromiseFactory = createBlockHeightExceedencePromiseFactory;
751
+ exports.createDefaultDurableNonceTransactionConfirmer = createDefaultDurableNonceTransactionConfirmer;
752
+ exports.createDefaultRecentTransactionConfirmer = createDefaultRecentTransactionConfirmer;
205
753
  exports.createDefaultRpcSubscriptionsTransport = createDefaultRpcSubscriptionsTransport;
206
754
  exports.createDefaultRpcTransport = createDefaultRpcTransport;
755
+ exports.createNonceInvalidationPromiseFactory = createNonceInvalidationPromiseFactory;
756
+ exports.createRecentSignatureConfirmationPromiseFactory = createRecentSignatureConfirmationPromiseFactory;
207
757
  exports.createSolanaRpc = createSolanaRpc;
208
758
  exports.createSolanaRpcSubscriptions = createSolanaRpcSubscriptions;
759
+ exports.createSolanaRpcSubscriptions_UNSTABLE = createSolanaRpcSubscriptions_UNSTABLE;
760
+ exports.requestAndConfirmAirdrop = requestAndConfirmAirdrop;
761
+ exports.waitForDurableNonceTransactionConfirmation = waitForDurableNonceTransactionConfirmation;
762
+ exports.waitForRecentTransactionConfirmation = waitForRecentTransactionConfirmation;
209
763
  Object.keys(addresses).forEach(function (k) {
210
764
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
211
765
  enumerable: true,