@solana/web3.js 1.66.5 → 1.67.1
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/lib/index.browser.cjs.js +341 -72
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +341 -73
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +341 -72
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +87 -7
- package/lib/index.esm.js +341 -73
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +341 -72
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +3 -3
- package/lib/index.iife.min.js.map +1 -1
- package/lib/index.native.js +341 -72
- package/lib/index.native.js.map +1 -1
- package/package.json +1 -3
- package/src/account.ts +1 -1
- package/src/connection.ts +320 -76
- package/src/message/legacy.ts +4 -4
- package/src/nonce-account.ts +7 -3
- package/src/publickey.ts +6 -2
- package/src/transaction/expiry-custom-errors.ts +13 -0
- package/src/transaction/legacy.ts +39 -3
- package/src/transaction/message.ts +3 -1
- package/src/utils/send-and-confirm-raw-transaction.ts +13 -0
- package/src/utils/send-and-confirm-transaction.ts +39 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/web3.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.67.1",
|
|
4
4
|
"description": "Solana Javascript API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -79,7 +79,6 @@
|
|
|
79
79
|
"@babel/plugin-transform-runtime": "^7.12.10",
|
|
80
80
|
"@babel/preset-env": "^7.12.11",
|
|
81
81
|
"@babel/preset-typescript": "^7.12.16",
|
|
82
|
-
"@babel/register": "^7.12.13",
|
|
83
82
|
"@commitlint/config-conventional": "^17.0.2",
|
|
84
83
|
"@rollup/plugin-alias": "^3.1.9",
|
|
85
84
|
"@rollup/plugin-babel": "^5.2.3",
|
|
@@ -112,7 +111,6 @@
|
|
|
112
111
|
"eslint-plugin-mocha": "^10.1.0",
|
|
113
112
|
"eslint-plugin-prettier": "^4.2.1",
|
|
114
113
|
"esm": "^3.2.25",
|
|
115
|
-
"http-server": "^14.0.0",
|
|
116
114
|
"mocha": "^10.1.0",
|
|
117
115
|
"mockttp": "^2.0.1",
|
|
118
116
|
"mz": "^2.7.0",
|
package/src/account.ts
CHANGED
|
@@ -23,7 +23,7 @@ export class Account {
|
|
|
23
23
|
*
|
|
24
24
|
* @param secretKey Secret key for the account
|
|
25
25
|
*/
|
|
26
|
-
constructor(secretKey?:
|
|
26
|
+
constructor(secretKey?: Uint8Array | Array<number>) {
|
|
27
27
|
if (secretKey) {
|
|
28
28
|
const secretKeyBuffer = toBuffer(secretKey);
|
|
29
29
|
if (secretKey.length !== 64) {
|
package/src/connection.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {AgentManager} from './agent-manager';
|
|
|
28
28
|
import {EpochSchedule} from './epoch-schedule';
|
|
29
29
|
import {SendTransactionError, SolanaJSONRPCError} from './errors';
|
|
30
30
|
import fetchImpl, {Response} from './fetch-impl';
|
|
31
|
-
import {NonceAccount} from './nonce-account';
|
|
31
|
+
import {DurableNonce, NonceAccount} from './nonce-account';
|
|
32
32
|
import {PublicKey} from './publickey';
|
|
33
33
|
import {Signer} from './keypair';
|
|
34
34
|
import {MS_PER_SLOT} from './timing';
|
|
@@ -45,6 +45,7 @@ import {sleep} from './utils/sleep';
|
|
|
45
45
|
import {toBuffer} from './utils/to-buffer';
|
|
46
46
|
import {
|
|
47
47
|
TransactionExpiredBlockheightExceededError,
|
|
48
|
+
TransactionExpiredNonceInvalidError,
|
|
48
49
|
TransactionExpiredTimeoutError,
|
|
49
50
|
} from './transaction/expiry-custom-errors';
|
|
50
51
|
import {makeWebsocketUrl} from './utils/makeWebsocketUrl';
|
|
@@ -338,6 +339,28 @@ function extractCommitmentFromConfig<TConfig>(
|
|
|
338
339
|
return {commitment, config};
|
|
339
340
|
}
|
|
340
341
|
|
|
342
|
+
/**
|
|
343
|
+
* A strategy for confirming durable nonce transactions.
|
|
344
|
+
*/
|
|
345
|
+
export type DurableNonceTransactionConfirmationStrategy = {
|
|
346
|
+
/**
|
|
347
|
+
* The lowest slot at which to fetch the nonce value from the
|
|
348
|
+
* nonce account. This should be no lower than the slot at
|
|
349
|
+
* which the last-known value of the nonce was fetched.
|
|
350
|
+
*/
|
|
351
|
+
minContextSlot: number;
|
|
352
|
+
/**
|
|
353
|
+
* The account where the current value of the nonce is stored.
|
|
354
|
+
*/
|
|
355
|
+
nonceAccountPubkey: PublicKey;
|
|
356
|
+
/**
|
|
357
|
+
* The nonce value that was used to sign the transaction
|
|
358
|
+
* for which confirmation is being sought.
|
|
359
|
+
*/
|
|
360
|
+
nonceValue: DurableNonce;
|
|
361
|
+
signature: TransactionSignature;
|
|
362
|
+
};
|
|
363
|
+
|
|
341
364
|
/**
|
|
342
365
|
* @internal
|
|
343
366
|
*/
|
|
@@ -2438,6 +2461,26 @@ export type GetTransactionCountConfig = {
|
|
|
2438
2461
|
minContextSlot?: number;
|
|
2439
2462
|
};
|
|
2440
2463
|
|
|
2464
|
+
/**
|
|
2465
|
+
* Configuration object for `getNonce`
|
|
2466
|
+
*/
|
|
2467
|
+
export type GetNonceConfig = {
|
|
2468
|
+
/** Optional commitment level */
|
|
2469
|
+
commitment?: Commitment;
|
|
2470
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2471
|
+
minContextSlot?: number;
|
|
2472
|
+
};
|
|
2473
|
+
|
|
2474
|
+
/**
|
|
2475
|
+
* Configuration object for `getNonceAndContext`
|
|
2476
|
+
*/
|
|
2477
|
+
export type GetNonceAndContextConfig = {
|
|
2478
|
+
/** Optional commitment level */
|
|
2479
|
+
commitment?: Commitment;
|
|
2480
|
+
/** The minimum slot that the request can be evaluated at */
|
|
2481
|
+
minContextSlot?: number;
|
|
2482
|
+
};
|
|
2483
|
+
|
|
2441
2484
|
/**
|
|
2442
2485
|
* Information describing an account
|
|
2443
2486
|
*/
|
|
@@ -3348,7 +3391,9 @@ export class Connection {
|
|
|
3348
3391
|
}
|
|
3349
3392
|
|
|
3350
3393
|
confirmTransaction(
|
|
3351
|
-
strategy:
|
|
3394
|
+
strategy:
|
|
3395
|
+
| BlockheightBasedTransactionConfirmationStrategy
|
|
3396
|
+
| DurableNonceTransactionConfirmationStrategy,
|
|
3352
3397
|
commitment?: Commitment,
|
|
3353
3398
|
): Promise<RpcResponseAndContext<SignatureResult>>;
|
|
3354
3399
|
|
|
@@ -3363,6 +3408,7 @@ export class Connection {
|
|
|
3363
3408
|
async confirmTransaction(
|
|
3364
3409
|
strategy:
|
|
3365
3410
|
| BlockheightBasedTransactionConfirmationStrategy
|
|
3411
|
+
| DurableNonceTransactionConfirmationStrategy
|
|
3366
3412
|
| TransactionSignature,
|
|
3367
3413
|
commitment?: Commitment,
|
|
3368
3414
|
): Promise<RpcResponseAndContext<SignatureResult>> {
|
|
@@ -3371,8 +3417,9 @@ export class Connection {
|
|
|
3371
3417
|
if (typeof strategy == 'string') {
|
|
3372
3418
|
rawSignature = strategy;
|
|
3373
3419
|
} else {
|
|
3374
|
-
const config =
|
|
3375
|
-
|
|
3420
|
+
const config = strategy as
|
|
3421
|
+
| BlockheightBasedTransactionConfirmationStrategy
|
|
3422
|
+
| DurableNonceTransactionConfirmationStrategy;
|
|
3376
3423
|
rawSignature = config.signature;
|
|
3377
3424
|
}
|
|
3378
3425
|
|
|
@@ -3386,31 +3433,58 @@ export class Connection {
|
|
|
3386
3433
|
|
|
3387
3434
|
assert(decodedSignature.length === 64, 'signature has invalid length');
|
|
3388
3435
|
|
|
3389
|
-
|
|
3390
|
-
|
|
3436
|
+
if (typeof strategy === 'string') {
|
|
3437
|
+
return await this.confirmTransactionUsingLegacyTimeoutStrategy({
|
|
3438
|
+
commitment: commitment || this.commitment,
|
|
3439
|
+
signature: rawSignature,
|
|
3440
|
+
});
|
|
3441
|
+
} else if ('lastValidBlockHeight' in strategy) {
|
|
3442
|
+
return await this.confirmTransactionUsingBlockHeightExceedanceStrategy({
|
|
3443
|
+
commitment: commitment || this.commitment,
|
|
3444
|
+
strategy,
|
|
3445
|
+
});
|
|
3446
|
+
} else {
|
|
3447
|
+
return await this.confirmTransactionUsingDurableNonceStrategy({
|
|
3448
|
+
commitment: commitment || this.commitment,
|
|
3449
|
+
strategy,
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
|
|
3454
|
+
private getTransactionConfirmationPromise({
|
|
3455
|
+
commitment,
|
|
3456
|
+
signature,
|
|
3457
|
+
}: {
|
|
3458
|
+
commitment?: Commitment;
|
|
3459
|
+
signature: string;
|
|
3460
|
+
}): {
|
|
3461
|
+
abortConfirmation(): void;
|
|
3462
|
+
confirmationPromise: Promise<{
|
|
3463
|
+
__type: TransactionStatus.PROCESSED;
|
|
3464
|
+
response: RpcResponseAndContext<SignatureResult>;
|
|
3465
|
+
}>;
|
|
3466
|
+
} {
|
|
3391
3467
|
let signatureSubscriptionId: number | undefined;
|
|
3392
3468
|
let disposeSignatureSubscriptionStateChangeObserver:
|
|
3393
3469
|
| SubscriptionStateChangeDisposeFn
|
|
3394
3470
|
| undefined;
|
|
3395
3471
|
let done = false;
|
|
3396
|
-
|
|
3397
3472
|
const confirmationPromise = new Promise<{
|
|
3398
3473
|
__type: TransactionStatus.PROCESSED;
|
|
3399
3474
|
response: RpcResponseAndContext<SignatureResult>;
|
|
3400
3475
|
}>((resolve, reject) => {
|
|
3401
3476
|
try {
|
|
3402
3477
|
signatureSubscriptionId = this.onSignature(
|
|
3403
|
-
|
|
3478
|
+
signature,
|
|
3404
3479
|
(result: SignatureResult, context: Context) => {
|
|
3405
3480
|
signatureSubscriptionId = undefined;
|
|
3406
3481
|
const response = {
|
|
3407
3482
|
context,
|
|
3408
3483
|
value: result,
|
|
3409
3484
|
};
|
|
3410
|
-
done = true;
|
|
3411
3485
|
resolve({__type: TransactionStatus.PROCESSED, response});
|
|
3412
3486
|
},
|
|
3413
|
-
|
|
3487
|
+
commitment,
|
|
3414
3488
|
);
|
|
3415
3489
|
const subscriptionSetupPromise = new Promise<void>(
|
|
3416
3490
|
resolveSubscriptionSetup => {
|
|
@@ -3432,7 +3506,7 @@ export class Connection {
|
|
|
3432
3506
|
(async () => {
|
|
3433
3507
|
await subscriptionSetupPromise;
|
|
3434
3508
|
if (done) return;
|
|
3435
|
-
const response = await this.getSignatureStatus(
|
|
3509
|
+
const response = await this.getSignatureStatus(signature);
|
|
3436
3510
|
if (done) return;
|
|
3437
3511
|
if (response == null) {
|
|
3438
3512
|
return;
|
|
@@ -3444,7 +3518,7 @@ export class Connection {
|
|
|
3444
3518
|
if (value?.err) {
|
|
3445
3519
|
reject(value.err);
|
|
3446
3520
|
} else {
|
|
3447
|
-
switch (
|
|
3521
|
+
switch (commitment) {
|
|
3448
3522
|
case 'confirmed':
|
|
3449
3523
|
case 'single':
|
|
3450
3524
|
case 'singleGossip': {
|
|
@@ -3482,80 +3556,250 @@ export class Connection {
|
|
|
3482
3556
|
reject(err);
|
|
3483
3557
|
}
|
|
3484
3558
|
});
|
|
3559
|
+
const abortConfirmation = () => {
|
|
3560
|
+
if (disposeSignatureSubscriptionStateChangeObserver) {
|
|
3561
|
+
disposeSignatureSubscriptionStateChangeObserver();
|
|
3562
|
+
disposeSignatureSubscriptionStateChangeObserver = undefined;
|
|
3563
|
+
}
|
|
3564
|
+
if (signatureSubscriptionId) {
|
|
3565
|
+
this.removeSignatureListener(signatureSubscriptionId);
|
|
3566
|
+
signatureSubscriptionId = undefined;
|
|
3567
|
+
}
|
|
3568
|
+
};
|
|
3569
|
+
return {abortConfirmation, confirmationPromise};
|
|
3570
|
+
}
|
|
3485
3571
|
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
case 'max':
|
|
3504
|
-
case 'root':
|
|
3572
|
+
private async confirmTransactionUsingBlockHeightExceedanceStrategy({
|
|
3573
|
+
commitment,
|
|
3574
|
+
strategy: {lastValidBlockHeight, signature},
|
|
3575
|
+
}: {
|
|
3576
|
+
commitment?: Commitment;
|
|
3577
|
+
strategy: BlockheightBasedTransactionConfirmationStrategy;
|
|
3578
|
+
}) {
|
|
3579
|
+
let done: boolean = false;
|
|
3580
|
+
const expiryPromise = new Promise<{
|
|
3581
|
+
__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED;
|
|
3582
|
+
}>(resolve => {
|
|
3583
|
+
const checkBlockHeight = async () => {
|
|
3584
|
+
try {
|
|
3585
|
+
const blockHeight = await this.getBlockHeight(commitment);
|
|
3586
|
+
return blockHeight;
|
|
3587
|
+
} catch (_e) {
|
|
3588
|
+
return -1;
|
|
3505
3589
|
}
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
)
|
|
3590
|
+
};
|
|
3591
|
+
(async () => {
|
|
3592
|
+
let currentBlockHeight = await checkBlockHeight();
|
|
3593
|
+
if (done) return;
|
|
3594
|
+
while (currentBlockHeight <= lastValidBlockHeight) {
|
|
3595
|
+
await sleep(1000);
|
|
3596
|
+
if (done) return;
|
|
3597
|
+
currentBlockHeight = await checkBlockHeight();
|
|
3598
|
+
if (done) return;
|
|
3599
|
+
}
|
|
3600
|
+
resolve({__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED});
|
|
3601
|
+
})();
|
|
3602
|
+
});
|
|
3603
|
+
const {abortConfirmation, confirmationPromise} =
|
|
3604
|
+
this.getTransactionConfirmationPromise({commitment, signature});
|
|
3605
|
+
let result: RpcResponseAndContext<SignatureResult>;
|
|
3606
|
+
try {
|
|
3607
|
+
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
3608
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
3609
|
+
result = outcome.response;
|
|
3511
3610
|
} else {
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3611
|
+
throw new TransactionExpiredBlockheightExceededError(signature);
|
|
3612
|
+
}
|
|
3613
|
+
} finally {
|
|
3614
|
+
done = true;
|
|
3615
|
+
abortConfirmation();
|
|
3616
|
+
}
|
|
3617
|
+
return result;
|
|
3618
|
+
}
|
|
3619
|
+
|
|
3620
|
+
private async confirmTransactionUsingDurableNonceStrategy({
|
|
3621
|
+
commitment,
|
|
3622
|
+
strategy: {minContextSlot, nonceAccountPubkey, nonceValue, signature},
|
|
3623
|
+
}: {
|
|
3624
|
+
commitment?: Commitment;
|
|
3625
|
+
strategy: DurableNonceTransactionConfirmationStrategy;
|
|
3626
|
+
}) {
|
|
3627
|
+
let done: boolean = false;
|
|
3628
|
+
const expiryPromise = new Promise<{
|
|
3629
|
+
__type: TransactionStatus.NONCE_INVALID;
|
|
3630
|
+
slotInWhichNonceDidAdvance: number | null;
|
|
3631
|
+
}>(resolve => {
|
|
3632
|
+
let currentNonceValue: string | undefined = nonceValue;
|
|
3633
|
+
let lastCheckedSlot: number | null = null;
|
|
3634
|
+
const getCurrentNonceValue = async () => {
|
|
3635
|
+
try {
|
|
3636
|
+
const {context, value: nonceAccount} = await this.getNonceAndContext(
|
|
3637
|
+
nonceAccountPubkey,
|
|
3638
|
+
{
|
|
3639
|
+
commitment,
|
|
3640
|
+
minContextSlot,
|
|
3641
|
+
},
|
|
3642
|
+
);
|
|
3643
|
+
lastCheckedSlot = context.slot;
|
|
3644
|
+
return nonceAccount?.nonce;
|
|
3645
|
+
} catch (e) {
|
|
3646
|
+
// If for whatever reason we can't reach/read the nonce
|
|
3647
|
+
// account, just keep using the last-known value.
|
|
3648
|
+
return currentNonceValue;
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
(async () => {
|
|
3652
|
+
currentNonceValue = await getCurrentNonceValue();
|
|
3653
|
+
if (done) return;
|
|
3654
|
+
while (
|
|
3655
|
+
true // eslint-disable-line no-constant-condition
|
|
3656
|
+
) {
|
|
3657
|
+
if (nonceValue !== currentNonceValue) {
|
|
3658
|
+
resolve({
|
|
3659
|
+
__type: TransactionStatus.NONCE_INVALID,
|
|
3660
|
+
slotInWhichNonceDidAdvance: lastCheckedSlot,
|
|
3661
|
+
});
|
|
3662
|
+
return;
|
|
3520
3663
|
}
|
|
3521
|
-
|
|
3522
|
-
(async () => {
|
|
3523
|
-
let currentBlockHeight = await checkBlockHeight();
|
|
3664
|
+
await sleep(2000);
|
|
3524
3665
|
if (done) return;
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
if (done) return;
|
|
3530
|
-
}
|
|
3531
|
-
resolve({__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED});
|
|
3532
|
-
})();
|
|
3533
|
-
}
|
|
3666
|
+
currentNonceValue = await getCurrentNonceValue();
|
|
3667
|
+
if (done) return;
|
|
3668
|
+
}
|
|
3669
|
+
})();
|
|
3534
3670
|
});
|
|
3535
|
-
|
|
3671
|
+
const {abortConfirmation, confirmationPromise} =
|
|
3672
|
+
this.getTransactionConfirmationPromise({commitment, signature});
|
|
3536
3673
|
let result: RpcResponseAndContext<SignatureResult>;
|
|
3537
3674
|
try {
|
|
3538
3675
|
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3676
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
3677
|
+
result = outcome.response;
|
|
3678
|
+
} else {
|
|
3679
|
+
// Double check that the transaction is indeed unconfirmed.
|
|
3680
|
+
let signatureStatus:
|
|
3681
|
+
| RpcResponseAndContext<SignatureStatus | null>
|
|
3682
|
+
| null
|
|
3683
|
+
| undefined;
|
|
3684
|
+
while (
|
|
3685
|
+
true // eslint-disable-line no-constant-condition
|
|
3686
|
+
) {
|
|
3687
|
+
const status = await this.getSignatureStatus(signature);
|
|
3688
|
+
if (status == null) {
|
|
3689
|
+
break;
|
|
3690
|
+
}
|
|
3691
|
+
if (
|
|
3692
|
+
status.context.slot <
|
|
3693
|
+
(outcome.slotInWhichNonceDidAdvance ?? minContextSlot)
|
|
3694
|
+
) {
|
|
3695
|
+
await sleep(400);
|
|
3696
|
+
continue;
|
|
3697
|
+
}
|
|
3698
|
+
signatureStatus = status;
|
|
3544
3699
|
break;
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
)
|
|
3700
|
+
}
|
|
3701
|
+
if (signatureStatus?.value) {
|
|
3702
|
+
const commitmentForStatus = commitment || 'finalized';
|
|
3703
|
+
const {confirmationStatus} = signatureStatus.value;
|
|
3704
|
+
switch (commitmentForStatus) {
|
|
3705
|
+
case 'processed':
|
|
3706
|
+
case 'recent':
|
|
3707
|
+
if (
|
|
3708
|
+
confirmationStatus !== 'processed' &&
|
|
3709
|
+
confirmationStatus !== 'confirmed' &&
|
|
3710
|
+
confirmationStatus !== 'finalized'
|
|
3711
|
+
) {
|
|
3712
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3713
|
+
}
|
|
3714
|
+
break;
|
|
3715
|
+
case 'confirmed':
|
|
3716
|
+
case 'single':
|
|
3717
|
+
case 'singleGossip':
|
|
3718
|
+
if (
|
|
3719
|
+
confirmationStatus !== 'confirmed' &&
|
|
3720
|
+
confirmationStatus !== 'finalized'
|
|
3721
|
+
) {
|
|
3722
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3723
|
+
}
|
|
3724
|
+
break;
|
|
3725
|
+
case 'finalized':
|
|
3726
|
+
case 'max':
|
|
3727
|
+
case 'root':
|
|
3728
|
+
if (confirmationStatus !== 'finalized') {
|
|
3729
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3730
|
+
}
|
|
3731
|
+
break;
|
|
3732
|
+
default:
|
|
3733
|
+
// Exhaustive switch.
|
|
3734
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3735
|
+
((_: never) => {})(commitmentForStatus);
|
|
3736
|
+
}
|
|
3737
|
+
result = {
|
|
3738
|
+
context: signatureStatus.context,
|
|
3739
|
+
value: {err: signatureStatus.value.err},
|
|
3740
|
+
};
|
|
3741
|
+
} else {
|
|
3742
|
+
throw new TransactionExpiredNonceInvalidError(signature);
|
|
3743
|
+
}
|
|
3550
3744
|
}
|
|
3551
3745
|
} finally {
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3746
|
+
done = true;
|
|
3747
|
+
abortConfirmation();
|
|
3748
|
+
}
|
|
3749
|
+
return result;
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
private async confirmTransactionUsingLegacyTimeoutStrategy({
|
|
3753
|
+
commitment,
|
|
3754
|
+
signature,
|
|
3755
|
+
}: {
|
|
3756
|
+
commitment?: Commitment;
|
|
3757
|
+
signature: string;
|
|
3758
|
+
}) {
|
|
3759
|
+
let timeoutId;
|
|
3760
|
+
const expiryPromise = new Promise<{
|
|
3761
|
+
__type: TransactionStatus.TIMED_OUT;
|
|
3762
|
+
timeoutMs: number;
|
|
3763
|
+
}>(resolve => {
|
|
3764
|
+
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
|
3765
|
+
switch (commitment) {
|
|
3766
|
+
case 'processed':
|
|
3767
|
+
case 'recent':
|
|
3768
|
+
case 'single':
|
|
3769
|
+
case 'confirmed':
|
|
3770
|
+
case 'singleGossip': {
|
|
3771
|
+
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
|
3772
|
+
break;
|
|
3773
|
+
}
|
|
3774
|
+
// exhaust enums to ensure full coverage
|
|
3775
|
+
case 'finalized':
|
|
3776
|
+
case 'max':
|
|
3777
|
+
case 'root':
|
|
3555
3778
|
}
|
|
3556
|
-
|
|
3557
|
-
|
|
3779
|
+
timeoutId = setTimeout(
|
|
3780
|
+
() => resolve({__type: TransactionStatus.TIMED_OUT, timeoutMs}),
|
|
3781
|
+
timeoutMs,
|
|
3782
|
+
);
|
|
3783
|
+
});
|
|
3784
|
+
const {abortConfirmation, confirmationPromise} =
|
|
3785
|
+
this.getTransactionConfirmationPromise({
|
|
3786
|
+
commitment,
|
|
3787
|
+
signature,
|
|
3788
|
+
});
|
|
3789
|
+
let result: RpcResponseAndContext<SignatureResult>;
|
|
3790
|
+
try {
|
|
3791
|
+
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
|
|
3792
|
+
if (outcome.__type === TransactionStatus.PROCESSED) {
|
|
3793
|
+
result = outcome.response;
|
|
3794
|
+
} else {
|
|
3795
|
+
throw new TransactionExpiredTimeoutError(
|
|
3796
|
+
signature,
|
|
3797
|
+
outcome.timeoutMs / 1000,
|
|
3798
|
+
);
|
|
3558
3799
|
}
|
|
3800
|
+
} finally {
|
|
3801
|
+
clearTimeout(timeoutId);
|
|
3802
|
+
abortConfirmation();
|
|
3559
3803
|
}
|
|
3560
3804
|
return result;
|
|
3561
3805
|
}
|
|
@@ -4708,11 +4952,11 @@ export class Connection {
|
|
|
4708
4952
|
*/
|
|
4709
4953
|
async getNonceAndContext(
|
|
4710
4954
|
nonceAccount: PublicKey,
|
|
4711
|
-
|
|
4955
|
+
commitmentOrConfig?: Commitment | GetNonceAndContextConfig,
|
|
4712
4956
|
): Promise<RpcResponseAndContext<NonceAccount | null>> {
|
|
4713
4957
|
const {context, value: accountInfo} = await this.getAccountInfoAndContext(
|
|
4714
4958
|
nonceAccount,
|
|
4715
|
-
|
|
4959
|
+
commitmentOrConfig,
|
|
4716
4960
|
);
|
|
4717
4961
|
|
|
4718
4962
|
let value = null;
|
|
@@ -4731,9 +4975,9 @@ export class Connection {
|
|
|
4731
4975
|
*/
|
|
4732
4976
|
async getNonce(
|
|
4733
4977
|
nonceAccount: PublicKey,
|
|
4734
|
-
|
|
4978
|
+
commitmentOrConfig?: Commitment | GetNonceConfig,
|
|
4735
4979
|
): Promise<NonceAccount | null> {
|
|
4736
|
-
return await this.getNonceAndContext(nonceAccount,
|
|
4980
|
+
return await this.getNonceAndContext(nonceAccount, commitmentOrConfig)
|
|
4737
4981
|
.then(x => x.value)
|
|
4738
4982
|
.catch(e => {
|
|
4739
4983
|
throw new Error(
|
package/src/message/legacy.ts
CHANGED
|
@@ -268,7 +268,7 @@ export class Message {
|
|
|
268
268
|
// Slice up wire data
|
|
269
269
|
let byteArray = [...buffer];
|
|
270
270
|
|
|
271
|
-
const numRequiredSignatures = byteArray.shift()
|
|
271
|
+
const numRequiredSignatures = byteArray.shift()!;
|
|
272
272
|
if (
|
|
273
273
|
numRequiredSignatures !==
|
|
274
274
|
(numRequiredSignatures & VERSION_PREFIX_MASK)
|
|
@@ -278,8 +278,8 @@ export class Message {
|
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
const numReadonlySignedAccounts = byteArray.shift()
|
|
282
|
-
const numReadonlyUnsignedAccounts = byteArray.shift()
|
|
281
|
+
const numReadonlySignedAccounts = byteArray.shift()!;
|
|
282
|
+
const numReadonlyUnsignedAccounts = byteArray.shift()!;
|
|
283
283
|
|
|
284
284
|
const accountCount = shortvec.decodeLength(byteArray);
|
|
285
285
|
let accountKeys = [];
|
|
@@ -295,7 +295,7 @@ export class Message {
|
|
|
295
295
|
const instructionCount = shortvec.decodeLength(byteArray);
|
|
296
296
|
let instructions: CompiledInstruction[] = [];
|
|
297
297
|
for (let i = 0; i < instructionCount; i++) {
|
|
298
|
-
const programIdIndex = byteArray.shift()
|
|
298
|
+
const programIdIndex = byteArray.shift()!;
|
|
299
299
|
const accountCount = shortvec.decodeLength(byteArray);
|
|
300
300
|
const accounts = byteArray.slice(0, accountCount);
|
|
301
301
|
byteArray = byteArray.slice(accountCount);
|
package/src/nonce-account.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as BufferLayout from '@solana/buffer-layout';
|
|
2
2
|
import {Buffer} from 'buffer';
|
|
3
3
|
|
|
4
|
-
import type {Blockhash} from './blockhash';
|
|
5
4
|
import * as Layout from './layout';
|
|
6
5
|
import {PublicKey} from './publickey';
|
|
7
6
|
import type {FeeCalculator} from './fee-calculator';
|
|
@@ -36,9 +35,14 @@ const NonceAccountLayout = BufferLayout.struct<
|
|
|
36
35
|
|
|
37
36
|
export const NONCE_ACCOUNT_LENGTH = NonceAccountLayout.span;
|
|
38
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A durable nonce is a 32 byte value encoded as a base58 string.
|
|
40
|
+
*/
|
|
41
|
+
export type DurableNonce = string;
|
|
42
|
+
|
|
39
43
|
type NonceAccountArgs = {
|
|
40
44
|
authorizedPubkey: PublicKey;
|
|
41
|
-
nonce:
|
|
45
|
+
nonce: DurableNonce;
|
|
42
46
|
feeCalculator: FeeCalculator;
|
|
43
47
|
};
|
|
44
48
|
|
|
@@ -47,7 +51,7 @@ type NonceAccountArgs = {
|
|
|
47
51
|
*/
|
|
48
52
|
export class NonceAccount {
|
|
49
53
|
authorizedPubkey: PublicKey;
|
|
50
|
-
nonce:
|
|
54
|
+
nonce: DurableNonce;
|
|
51
55
|
feeCalculator: FeeCalculator;
|
|
52
56
|
|
|
53
57
|
/**
|
package/src/publickey.ts
CHANGED
|
@@ -69,14 +69,14 @@ export class PublicKey extends Struct {
|
|
|
69
69
|
this._bn = new BN(value);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
if (this._bn.byteLength() >
|
|
72
|
+
if (this._bn.byteLength() > PUBLIC_KEY_LENGTH) {
|
|
73
73
|
throw new Error(`Invalid public key input`);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Returns a unique PublicKey for tests and benchmarks using
|
|
79
|
+
* Returns a unique PublicKey for tests and benchmarks using a counter
|
|
80
80
|
*/
|
|
81
81
|
static unique(): PublicKey {
|
|
82
82
|
const key = new PublicKey(uniquePublicKeyCounter);
|
|
@@ -186,6 +186,8 @@ export class PublicKey extends Struct {
|
|
|
186
186
|
/**
|
|
187
187
|
* Async version of createProgramAddressSync
|
|
188
188
|
* For backwards compatibility
|
|
189
|
+
*
|
|
190
|
+
* @deprecated Use {@link createProgramAddressSync} instead
|
|
189
191
|
*/
|
|
190
192
|
/* eslint-disable require-await */
|
|
191
193
|
static async createProgramAddress(
|
|
@@ -227,6 +229,8 @@ export class PublicKey extends Struct {
|
|
|
227
229
|
/**
|
|
228
230
|
* Async version of findProgramAddressSync
|
|
229
231
|
* For backwards compatibility
|
|
232
|
+
*
|
|
233
|
+
* @deprecated Use {@link findProgramAddressSync} instead
|
|
230
234
|
*/
|
|
231
235
|
static async findProgramAddress(
|
|
232
236
|
seeds: Array<Buffer | Uint8Array>,
|
|
@@ -33,3 +33,16 @@ export class TransactionExpiredTimeoutError extends Error {
|
|
|
33
33
|
Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
|
|
34
34
|
value: 'TransactionExpiredTimeoutError',
|
|
35
35
|
});
|
|
36
|
+
|
|
37
|
+
export class TransactionExpiredNonceInvalidError extends Error {
|
|
38
|
+
signature: string;
|
|
39
|
+
|
|
40
|
+
constructor(signature: string) {
|
|
41
|
+
super(`Signature ${signature} has expired: the nonce is no longer valid.`);
|
|
42
|
+
this.signature = signature;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Object.defineProperty(TransactionExpiredNonceInvalidError.prototype, 'name', {
|
|
47
|
+
value: 'TransactionExpiredNonceInvalidError',
|
|
48
|
+
});
|