@solana/web3.js 1.20.1 → 1.20.3
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.esm.js +78 -2014
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +75 -45
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.esm.js +72 -41
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +1647 -3826
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +10 -2
- package/lib/index.iife.min.js.map +1 -1
- package/package.json +27 -27
- package/src/connection.ts +3 -4
- package/src/message.ts +9 -12
- package/src/secp256k1-program.ts +1 -1
- package/src/transaction.ts +3 -3
- package/src/util/assert.ts +8 -0
- package/src/util/guarded-array-utils.ts +37 -0
- package/src/util/url.ts +3 -5
- package/src/validator-info.ts +5 -4
package/lib/index.esm.js
CHANGED
|
@@ -7,10 +7,8 @@ import bs58 from 'bs58';
|
|
|
7
7
|
import { sha256 } from 'crypto-hash';
|
|
8
8
|
import { serialize, deserialize, deserializeUnchecked } from 'borsh';
|
|
9
9
|
import * as BufferLayout from '@solana/buffer-layout';
|
|
10
|
-
import invariant from 'assert';
|
|
11
|
-
import { format, parse } from 'url';
|
|
12
10
|
import fetch from 'node-fetch';
|
|
13
|
-
import { coerce, instance, string, tuple, literal, unknown, union, type, optional, any, number, array, nullable, create, boolean, record, assert } from 'superstruct';
|
|
11
|
+
import { coerce, instance, string, tuple, literal, unknown, union, type, optional, any, number, array, nullable, create, boolean, record, assert as assert$1 } from 'superstruct';
|
|
14
12
|
import { Client } from 'rpc-websockets';
|
|
15
13
|
import RpcClient from 'jayson/lib/client/browser';
|
|
16
14
|
import http from 'http';
|
|
@@ -441,6 +439,36 @@ function encodeLength(bytes, len) {
|
|
|
441
439
|
}
|
|
442
440
|
}
|
|
443
441
|
|
|
442
|
+
const END_OF_BUFFER_ERROR_MESSAGE = 'Reached end of buffer unexpectedly';
|
|
443
|
+
/**
|
|
444
|
+
* Delegates to `Array#shift`, but throws if the array is zero-length.
|
|
445
|
+
*/
|
|
446
|
+
|
|
447
|
+
function guardedShift(byteArray) {
|
|
448
|
+
if (byteArray.length === 0) {
|
|
449
|
+
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return byteArray.shift();
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Delegates to `Array#splice`, but throws if the section being spliced out extends past the end of
|
|
456
|
+
* the array.
|
|
457
|
+
*/
|
|
458
|
+
|
|
459
|
+
function guardedSplice(byteArray, ...args) {
|
|
460
|
+
var _args$;
|
|
461
|
+
|
|
462
|
+
const [start] = args;
|
|
463
|
+
|
|
464
|
+
if (args.length === 2 // Implies that `deleteCount` was supplied
|
|
465
|
+
? start + ((_args$ = args[1]) !== null && _args$ !== void 0 ? _args$ : 0) > byteArray.length : start >= byteArray.length) {
|
|
466
|
+
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return byteArray.splice(...args);
|
|
470
|
+
}
|
|
471
|
+
|
|
444
472
|
/**
|
|
445
473
|
* The message header, identifying signed and read-only account
|
|
446
474
|
*/
|
|
@@ -525,32 +553,28 @@ class Message {
|
|
|
525
553
|
static from(buffer) {
|
|
526
554
|
// Slice up wire data
|
|
527
555
|
let byteArray = [...buffer];
|
|
528
|
-
const numRequiredSignatures = byteArray
|
|
529
|
-
const numReadonlySignedAccounts = byteArray
|
|
530
|
-
const numReadonlyUnsignedAccounts = byteArray
|
|
556
|
+
const numRequiredSignatures = guardedShift(byteArray);
|
|
557
|
+
const numReadonlySignedAccounts = guardedShift(byteArray);
|
|
558
|
+
const numReadonlyUnsignedAccounts = guardedShift(byteArray);
|
|
531
559
|
const accountCount = decodeLength(byteArray);
|
|
532
560
|
let accountKeys = [];
|
|
533
561
|
|
|
534
562
|
for (let i = 0; i < accountCount; i++) {
|
|
535
|
-
const account = byteArray
|
|
536
|
-
byteArray = byteArray.slice(PUBKEY_LENGTH);
|
|
563
|
+
const account = guardedSplice(byteArray, 0, PUBKEY_LENGTH);
|
|
537
564
|
accountKeys.push(bs58.encode(Buffer.from(account)));
|
|
538
565
|
}
|
|
539
566
|
|
|
540
|
-
const recentBlockhash = byteArray
|
|
541
|
-
byteArray = byteArray.slice(PUBKEY_LENGTH);
|
|
567
|
+
const recentBlockhash = guardedSplice(byteArray, 0, PUBKEY_LENGTH);
|
|
542
568
|
const instructionCount = decodeLength(byteArray);
|
|
543
569
|
let instructions = [];
|
|
544
570
|
|
|
545
571
|
for (let i = 0; i < instructionCount; i++) {
|
|
546
|
-
const programIdIndex = byteArray
|
|
572
|
+
const programIdIndex = guardedShift(byteArray);
|
|
547
573
|
const accountCount = decodeLength(byteArray);
|
|
548
|
-
const accounts = byteArray
|
|
549
|
-
byteArray = byteArray.slice(accountCount);
|
|
574
|
+
const accounts = guardedSplice(byteArray, 0, accountCount);
|
|
550
575
|
const dataLength = decodeLength(byteArray);
|
|
551
|
-
const dataSlice = byteArray
|
|
576
|
+
const dataSlice = guardedSplice(byteArray, 0, dataLength);
|
|
552
577
|
const data = bs58.encode(Buffer.from(dataSlice));
|
|
553
|
-
byteArray = byteArray.slice(dataLength);
|
|
554
578
|
instructions.push({
|
|
555
579
|
programIdIndex,
|
|
556
580
|
accounts,
|
|
@@ -573,6 +597,16 @@ class Message {
|
|
|
573
597
|
|
|
574
598
|
}
|
|
575
599
|
|
|
600
|
+
function assert (condition, message) {
|
|
601
|
+
if (!condition) {
|
|
602
|
+
throw new Error(message || 'Assertion failed');
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Transaction signature as base-58 encoded string
|
|
608
|
+
*/
|
|
609
|
+
|
|
576
610
|
/**
|
|
577
611
|
* Default (empty) signature
|
|
578
612
|
*
|
|
@@ -848,8 +882,8 @@ class Transaction {
|
|
|
848
882
|
};
|
|
849
883
|
});
|
|
850
884
|
instructions.forEach(instruction => {
|
|
851
|
-
|
|
852
|
-
instruction.accounts.forEach(keyIndex =>
|
|
885
|
+
assert(instruction.programIdIndex >= 0);
|
|
886
|
+
instruction.accounts.forEach(keyIndex => assert(keyIndex >= 0));
|
|
853
887
|
});
|
|
854
888
|
return new Message({
|
|
855
889
|
header: {
|
|
@@ -1036,7 +1070,7 @@ class Transaction {
|
|
|
1036
1070
|
|
|
1037
1071
|
|
|
1038
1072
|
_addSignature(pubkey, signature) {
|
|
1039
|
-
|
|
1073
|
+
assert(signature.length === 64);
|
|
1040
1074
|
const index = this.signatures.findIndex(sigpair => pubkey.equals(sigpair.publicKey));
|
|
1041
1075
|
|
|
1042
1076
|
if (index < 0) {
|
|
@@ -1110,18 +1144,18 @@ class Transaction {
|
|
|
1110
1144
|
encodeLength(signatureCount, signatures.length);
|
|
1111
1145
|
const transactionLength = signatureCount.length + signatures.length * 64 + signData.length;
|
|
1112
1146
|
const wireTransaction = Buffer.alloc(transactionLength);
|
|
1113
|
-
|
|
1147
|
+
assert(signatures.length < 256);
|
|
1114
1148
|
Buffer.from(signatureCount).copy(wireTransaction, 0);
|
|
1115
1149
|
signatures.forEach(({
|
|
1116
1150
|
signature
|
|
1117
1151
|
}, index) => {
|
|
1118
1152
|
if (signature !== null) {
|
|
1119
|
-
|
|
1153
|
+
assert(signature.length === 64, `signature has invalid length`);
|
|
1120
1154
|
Buffer.from(signature).copy(wireTransaction, signatureCount.length + index * 64);
|
|
1121
1155
|
}
|
|
1122
1156
|
});
|
|
1123
1157
|
signData.copy(wireTransaction, signatureCount.length + signatures.length * 64);
|
|
1124
|
-
|
|
1158
|
+
assert(wireTransaction.length <= PACKET_DATA_SIZE, `Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`);
|
|
1125
1159
|
return wireTransaction;
|
|
1126
1160
|
}
|
|
1127
1161
|
/**
|
|
@@ -1131,7 +1165,7 @@ class Transaction {
|
|
|
1131
1165
|
|
|
1132
1166
|
|
|
1133
1167
|
get keys() {
|
|
1134
|
-
|
|
1168
|
+
assert(this.instructions.length === 1);
|
|
1135
1169
|
return this.instructions[0].keys.map(keyObj => keyObj.pubkey);
|
|
1136
1170
|
}
|
|
1137
1171
|
/**
|
|
@@ -1141,7 +1175,7 @@ class Transaction {
|
|
|
1141
1175
|
|
|
1142
1176
|
|
|
1143
1177
|
get programId() {
|
|
1144
|
-
|
|
1178
|
+
assert(this.instructions.length === 1);
|
|
1145
1179
|
return this.instructions[0].programId;
|
|
1146
1180
|
}
|
|
1147
1181
|
/**
|
|
@@ -1151,7 +1185,7 @@ class Transaction {
|
|
|
1151
1185
|
|
|
1152
1186
|
|
|
1153
1187
|
get data() {
|
|
1154
|
-
|
|
1188
|
+
assert(this.instructions.length === 1);
|
|
1155
1189
|
return this.instructions[0].data;
|
|
1156
1190
|
}
|
|
1157
1191
|
/**
|
|
@@ -1166,8 +1200,7 @@ class Transaction {
|
|
|
1166
1200
|
let signatures = [];
|
|
1167
1201
|
|
|
1168
1202
|
for (let i = 0; i < signatureCount; i++) {
|
|
1169
|
-
const signature = byteArray
|
|
1170
|
-
byteArray = byteArray.slice(SIGNATURE_LENGTH);
|
|
1203
|
+
const signature = guardedSplice(byteArray, 0, SIGNATURE_LENGTH);
|
|
1171
1204
|
signatures.push(bs58.encode(Buffer.from(signature)));
|
|
1172
1205
|
}
|
|
1173
1206
|
|
|
@@ -2450,7 +2483,7 @@ function promiseTimeout(promise, timeoutMs) {
|
|
|
2450
2483
|
}
|
|
2451
2484
|
|
|
2452
2485
|
function makeWebsocketUrl(endpoint) {
|
|
2453
|
-
let url =
|
|
2486
|
+
let url = new URL(endpoint);
|
|
2454
2487
|
const useHttps = url.protocol === 'https:';
|
|
2455
2488
|
url.protocol = useHttps ? 'wss:' : 'ws:';
|
|
2456
2489
|
url.host = ''; // Only shift the port by +1 as a convention for ws(s) only if given endpoint
|
|
@@ -2460,11 +2493,11 @@ function makeWebsocketUrl(endpoint) {
|
|
|
2460
2493
|
// default ports: http(80) or https(443) and it's assumed we're behind a reverse
|
|
2461
2494
|
// proxy which manages WebSocket upgrade and backend port redirection.
|
|
2462
2495
|
|
|
2463
|
-
if (url.port !==
|
|
2496
|
+
if (url.port !== '') {
|
|
2464
2497
|
url.port = String(Number(url.port) + 1);
|
|
2465
2498
|
}
|
|
2466
2499
|
|
|
2467
|
-
return
|
|
2500
|
+
return url.toString();
|
|
2468
2501
|
}
|
|
2469
2502
|
|
|
2470
2503
|
const PublicKeyFromString = coerce(instance(PublicKey), string(), value => new PublicKey(value));
|
|
@@ -3418,7 +3451,7 @@ class Connection {
|
|
|
3418
3451
|
|
|
3419
3452
|
_defineProperty(this, "_slotUpdateSubscriptions", {});
|
|
3420
3453
|
|
|
3421
|
-
let url =
|
|
3454
|
+
let url = new URL(endpoint);
|
|
3422
3455
|
const useHttps = url.protocol === 'https:';
|
|
3423
3456
|
let wsEndpoint;
|
|
3424
3457
|
let httpHeaders;
|
|
@@ -3437,7 +3470,7 @@ class Connection {
|
|
|
3437
3470
|
|
|
3438
3471
|
this._rpcEndpoint = endpoint;
|
|
3439
3472
|
this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
|
|
3440
|
-
this._rpcClient = createRpcClient(url.
|
|
3473
|
+
this._rpcClient = createRpcClient(url.toString(), useHttps, httpHeaders, fetchMiddleware, disableRetryOnRateLimit);
|
|
3441
3474
|
this._rpcRequest = createRpcRequest(this._rpcClient);
|
|
3442
3475
|
this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient);
|
|
3443
3476
|
this._rpcWebSocket = new Client(this._rpcWsEndpoint, {
|
|
@@ -3850,7 +3883,7 @@ class Connection {
|
|
|
3850
3883
|
throw new Error('signature must be base58 encoded: ' + signature);
|
|
3851
3884
|
}
|
|
3852
3885
|
|
|
3853
|
-
|
|
3886
|
+
assert(decodedSignature.length === 64, 'signature has invalid length');
|
|
3854
3887
|
const start = Date.now();
|
|
3855
3888
|
const subscriptionCommitment = commitment || this.commitment;
|
|
3856
3889
|
let subscriptionId;
|
|
@@ -3993,7 +4026,7 @@ class Connection {
|
|
|
3993
4026
|
context,
|
|
3994
4027
|
value: values
|
|
3995
4028
|
} = await this.getSignatureStatuses([signature], config);
|
|
3996
|
-
|
|
4029
|
+
assert(values.length === 1);
|
|
3997
4030
|
const value = values[0];
|
|
3998
4031
|
return {
|
|
3999
4032
|
context,
|
|
@@ -6287,7 +6320,7 @@ class Secp256k1Program {
|
|
|
6287
6320
|
* @param {Buffer} publicKey a 64 byte secp256k1 public key buffer
|
|
6288
6321
|
*/
|
|
6289
6322
|
static publicKeyToEthAddress(publicKey) {
|
|
6290
|
-
|
|
6323
|
+
assert(publicKey.length === PUBLIC_KEY_BYTES, `Public key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`);
|
|
6291
6324
|
|
|
6292
6325
|
try {
|
|
6293
6326
|
return Buffer.from(keccak_256.update(toBuffer(publicKey)).digest()).slice(-ETHEREUM_ADDRESS_BYTES);
|
|
@@ -6340,7 +6373,7 @@ class Secp256k1Program {
|
|
|
6340
6373
|
ethAddress = rawAddress;
|
|
6341
6374
|
}
|
|
6342
6375
|
|
|
6343
|
-
|
|
6376
|
+
assert(ethAddress.length === ETHEREUM_ADDRESS_BYTES, `Address must be ${ETHEREUM_ADDRESS_BYTES} bytes but received ${ethAddress.length} bytes`);
|
|
6344
6377
|
const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
|
|
6345
6378
|
const ethAddressOffset = dataStart;
|
|
6346
6379
|
const signatureOffset = dataStart + ethAddress.length;
|
|
@@ -6378,7 +6411,7 @@ class Secp256k1Program {
|
|
|
6378
6411
|
privateKey: pkey,
|
|
6379
6412
|
message
|
|
6380
6413
|
} = params;
|
|
6381
|
-
|
|
6414
|
+
assert(pkey.length === PRIVATE_KEY_BYTES, `Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${pkey.length} bytes`);
|
|
6382
6415
|
|
|
6383
6416
|
try {
|
|
6384
6417
|
const privateKey = toBuffer(pkey);
|
|
@@ -6459,10 +6492,8 @@ class ValidatorInfo {
|
|
|
6459
6492
|
const configKeys = [];
|
|
6460
6493
|
|
|
6461
6494
|
for (let i = 0; i < 2; i++) {
|
|
6462
|
-
const publicKey = new PublicKey(byteArray
|
|
6463
|
-
|
|
6464
|
-
const isSigner = byteArray.slice(0, 1)[0] === 1;
|
|
6465
|
-
byteArray = byteArray.slice(1);
|
|
6495
|
+
const publicKey = new PublicKey(guardedSplice(byteArray, 0, PUBKEY_LENGTH));
|
|
6496
|
+
const isSigner = guardedShift(byteArray) === 1;
|
|
6466
6497
|
configKeys.push({
|
|
6467
6498
|
publicKey,
|
|
6468
6499
|
isSigner
|
|
@@ -6473,7 +6504,7 @@ class ValidatorInfo {
|
|
|
6473
6504
|
if (configKeys[1].isSigner) {
|
|
6474
6505
|
const rawInfo = rustString().decode(Buffer.from(byteArray));
|
|
6475
6506
|
const info = JSON.parse(rawInfo);
|
|
6476
|
-
assert(info, InfoString);
|
|
6507
|
+
assert$1(info, InfoString);
|
|
6477
6508
|
return new ValidatorInfo(configKeys[1].publicKey, info);
|
|
6478
6509
|
}
|
|
6479
6510
|
}
|