@solana/web3.js 1.53.0 → 1.54.0
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 +335 -28
- package/lib/index.browser.cjs.js.map +1 -1
- package/lib/index.browser.esm.js +331 -29
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +338 -29
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +98 -6
- package/lib/index.esm.js +334 -30
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +337 -30
- 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 +335 -27
- package/lib/index.native.js.map +1 -1
- package/package.json +1 -2
- package/src/connection.ts +11 -9
- package/src/layout.ts +7 -0
- package/src/message/index.ts +19 -6
- package/src/message/legacy.ts +58 -9
- package/src/message/v0.ts +324 -0
- package/src/message/versioned.ts +27 -0
- package/src/programs/vote.ts +21 -0
- package/src/publickey.ts +7 -2
- package/src/transaction/constants.ts +2 -0
- package/src/transaction/index.ts +1 -0
- package/src/transaction/versioned.ts +108 -0
- package/src/utils/makeWebsocketUrl.ts +22 -16
- package/src/validator-info.ts +3 -5
- package/src/utils/__forks__/react-native/url-impl.ts +0 -2
- package/src/utils/url-impl.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/web3.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.54.0",
|
|
4
4
|
"description": "Solana Javascript API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -69,7 +69,6 @@
|
|
|
69
69
|
"jayson": "^3.4.4",
|
|
70
70
|
"js-sha3": "^0.8.0",
|
|
71
71
|
"node-fetch": "2",
|
|
72
|
-
"react-native-url-polyfill": "^1.3.0",
|
|
73
72
|
"rpc-websockets": "^7.5.0",
|
|
74
73
|
"secp256k1": "^4.0.2",
|
|
75
74
|
"superstruct": "^0.14.2",
|
package/src/connection.ts
CHANGED
|
@@ -43,7 +43,6 @@ import {
|
|
|
43
43
|
TransactionExpiredTimeoutError,
|
|
44
44
|
} from './transaction/expiry-custom-errors';
|
|
45
45
|
import {makeWebsocketUrl} from './utils/makeWebsocketUrl';
|
|
46
|
-
import {URL} from './utils/url-impl';
|
|
47
46
|
import type {Blockhash} from './blockhash';
|
|
48
47
|
import type {FeeCalculator} from './fee-calculator';
|
|
49
48
|
import type {TransactionSignature} from './transaction';
|
|
@@ -305,6 +304,14 @@ export type BlockheightBasedTransactionConfirmationStrategy = {
|
|
|
305
304
|
signature: TransactionSignature;
|
|
306
305
|
} & BlockhashWithExpiryBlockHeight;
|
|
307
306
|
|
|
307
|
+
/* @internal */
|
|
308
|
+
function assertEndpointUrl(putativeUrl: string) {
|
|
309
|
+
if (/^https?:/.test(putativeUrl) === false) {
|
|
310
|
+
throw new TypeError('Endpoint URL must start with `http:` or `https:`.');
|
|
311
|
+
}
|
|
312
|
+
return putativeUrl;
|
|
313
|
+
}
|
|
314
|
+
|
|
308
315
|
/** @internal */
|
|
309
316
|
function extractCommitmentFromConfig<TConfig>(
|
|
310
317
|
commitmentOrConfig?: Commitment | ({commitment?: Commitment} & TConfig),
|
|
@@ -1117,7 +1124,6 @@ export type PerfSample = {
|
|
|
1117
1124
|
|
|
1118
1125
|
function createRpcClient(
|
|
1119
1126
|
url: string,
|
|
1120
|
-
useHttps: boolean,
|
|
1121
1127
|
httpHeaders?: HttpHeaders,
|
|
1122
1128
|
customFetch?: FetchFn,
|
|
1123
1129
|
fetchMiddleware?: FetchMiddleware,
|
|
@@ -1126,7 +1132,7 @@ function createRpcClient(
|
|
|
1126
1132
|
const fetch = customFetch ? customFetch : fetchImpl;
|
|
1127
1133
|
let agentManager: AgentManager | undefined;
|
|
1128
1134
|
if (!process.env.BROWSER) {
|
|
1129
|
-
agentManager = new AgentManager(useHttps);
|
|
1135
|
+
agentManager = new AgentManager(url.startsWith('https:') /* useHttps */);
|
|
1130
1136
|
}
|
|
1131
1137
|
|
|
1132
1138
|
let fetchWithMiddleware: FetchFn | undefined;
|
|
@@ -2493,9 +2499,6 @@ export class Connection {
|
|
|
2493
2499
|
endpoint: string,
|
|
2494
2500
|
commitmentOrConfig?: Commitment | ConnectionConfig,
|
|
2495
2501
|
) {
|
|
2496
|
-
let url = new URL(endpoint);
|
|
2497
|
-
const useHttps = url.protocol === 'https:';
|
|
2498
|
-
|
|
2499
2502
|
let wsEndpoint;
|
|
2500
2503
|
let httpHeaders;
|
|
2501
2504
|
let fetch;
|
|
@@ -2514,12 +2517,11 @@ export class Connection {
|
|
|
2514
2517
|
disableRetryOnRateLimit = commitmentOrConfig.disableRetryOnRateLimit;
|
|
2515
2518
|
}
|
|
2516
2519
|
|
|
2517
|
-
this._rpcEndpoint = endpoint;
|
|
2520
|
+
this._rpcEndpoint = assertEndpointUrl(endpoint);
|
|
2518
2521
|
this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
|
|
2519
2522
|
|
|
2520
2523
|
this._rpcClient = createRpcClient(
|
|
2521
|
-
|
|
2522
|
-
useHttps,
|
|
2524
|
+
endpoint,
|
|
2523
2525
|
httpHeaders,
|
|
2524
2526
|
fetch,
|
|
2525
2527
|
fetchMiddleware,
|
package/src/layout.ts
CHANGED
|
@@ -8,6 +8,13 @@ export const publicKey = (property: string = 'publicKey') => {
|
|
|
8
8
|
return BufferLayout.blob(32, property);
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Layout for a signature
|
|
13
|
+
*/
|
|
14
|
+
export const signature = (property: string = 'signature') => {
|
|
15
|
+
return BufferLayout.blob(64, property);
|
|
16
|
+
};
|
|
17
|
+
|
|
11
18
|
/**
|
|
12
19
|
* Layout for a 64bit unsigned value
|
|
13
20
|
*/
|
package/src/message/index.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import {PublicKey} from '../publickey';
|
|
2
|
+
|
|
1
3
|
export * from './legacy';
|
|
4
|
+
export * from './versioned';
|
|
5
|
+
export * from './v0';
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* The message header, identifying signed and read-only account
|
|
@@ -15,18 +19,27 @@ export type MessageHeader = {
|
|
|
15
19
|
numReadonlyUnsignedAccounts: number;
|
|
16
20
|
};
|
|
17
21
|
|
|
22
|
+
/**
|
|
23
|
+
* An address table lookup used to load additional accounts
|
|
24
|
+
*/
|
|
25
|
+
export type MessageAddressTableLookup = {
|
|
26
|
+
accountKey: PublicKey;
|
|
27
|
+
writableIndexes: Array<number>;
|
|
28
|
+
readonlyIndexes: Array<number>;
|
|
29
|
+
};
|
|
30
|
+
|
|
18
31
|
/**
|
|
19
32
|
* An instruction to execute by a program
|
|
20
33
|
*
|
|
21
34
|
* @property {number} programIdIndex
|
|
22
|
-
* @property {number[]}
|
|
23
|
-
* @property {
|
|
35
|
+
* @property {number[]} accountKeyIndexes
|
|
36
|
+
* @property {Uint8Array} data
|
|
24
37
|
*/
|
|
25
|
-
export type
|
|
38
|
+
export type MessageCompiledInstruction = {
|
|
26
39
|
/** Index into the transaction keys array indicating the program account that executes this instruction */
|
|
27
40
|
programIdIndex: number;
|
|
28
41
|
/** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
|
|
29
|
-
|
|
30
|
-
/** The program input data
|
|
31
|
-
data:
|
|
42
|
+
accountKeyIndexes: number[];
|
|
43
|
+
/** The program input data */
|
|
44
|
+
data: Uint8Array;
|
|
32
45
|
};
|
package/src/message/legacy.ts
CHANGED
|
@@ -2,13 +2,33 @@ import bs58 from 'bs58';
|
|
|
2
2
|
import {Buffer} from 'buffer';
|
|
3
3
|
import * as BufferLayout from '@solana/buffer-layout';
|
|
4
4
|
|
|
5
|
-
import {PublicKey} from '../publickey';
|
|
5
|
+
import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey';
|
|
6
6
|
import type {Blockhash} from '../blockhash';
|
|
7
7
|
import * as Layout from '../layout';
|
|
8
|
-
import {PACKET_DATA_SIZE} from '../transaction/constants';
|
|
8
|
+
import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants';
|
|
9
9
|
import * as shortvec from '../utils/shortvec-encoding';
|
|
10
10
|
import {toBuffer} from '../utils/to-buffer';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
MessageHeader,
|
|
13
|
+
MessageAddressTableLookup,
|
|
14
|
+
MessageCompiledInstruction,
|
|
15
|
+
} from './index';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An instruction to execute by a program
|
|
19
|
+
*
|
|
20
|
+
* @property {number} programIdIndex
|
|
21
|
+
* @property {number[]} accounts
|
|
22
|
+
* @property {string} data
|
|
23
|
+
*/
|
|
24
|
+
export type CompiledInstruction = {
|
|
25
|
+
/** Index into the transaction keys array indicating the program account that executes this instruction */
|
|
26
|
+
programIdIndex: number;
|
|
27
|
+
/** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
|
|
28
|
+
accounts: number[];
|
|
29
|
+
/** The program input data encoded as base 58 */
|
|
30
|
+
data: string;
|
|
31
|
+
};
|
|
12
32
|
|
|
13
33
|
/**
|
|
14
34
|
* Message constructor arguments
|
|
@@ -24,8 +44,6 @@ export type MessageArgs = {
|
|
|
24
44
|
instructions: CompiledInstruction[];
|
|
25
45
|
};
|
|
26
46
|
|
|
27
|
-
const PUBKEY_LENGTH = 32;
|
|
28
|
-
|
|
29
47
|
/**
|
|
30
48
|
* List of instructions to be processed atomically
|
|
31
49
|
*/
|
|
@@ -53,6 +71,28 @@ export class Message {
|
|
|
53
71
|
);
|
|
54
72
|
}
|
|
55
73
|
|
|
74
|
+
get version(): 'legacy' {
|
|
75
|
+
return 'legacy';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get staticAccountKeys(): Array<PublicKey> {
|
|
79
|
+
return this.accountKeys;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get compiledInstructions(): Array<MessageCompiledInstruction> {
|
|
83
|
+
return this.instructions.map(
|
|
84
|
+
(ix): MessageCompiledInstruction => ({
|
|
85
|
+
programIdIndex: ix.programIdIndex,
|
|
86
|
+
accountKeyIndexes: ix.accounts,
|
|
87
|
+
data: bs58.decode(ix.data),
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get addressTableLookups(): Array<MessageAddressTableLookup> {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
|
|
56
96
|
isAccountSigner(index: number): boolean {
|
|
57
97
|
return index < this.header.numRequiredSignatures;
|
|
58
98
|
}
|
|
@@ -193,19 +233,28 @@ export class Message {
|
|
|
193
233
|
let byteArray = [...buffer];
|
|
194
234
|
|
|
195
235
|
const numRequiredSignatures = byteArray.shift() as number;
|
|
236
|
+
if (
|
|
237
|
+
numRequiredSignatures !==
|
|
238
|
+
(numRequiredSignatures & VERSION_PREFIX_MASK)
|
|
239
|
+
) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
'Versioned messages must be deserialized with VersionedMessage.deserialize()',
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
196
245
|
const numReadonlySignedAccounts = byteArray.shift() as number;
|
|
197
246
|
const numReadonlyUnsignedAccounts = byteArray.shift() as number;
|
|
198
247
|
|
|
199
248
|
const accountCount = shortvec.decodeLength(byteArray);
|
|
200
249
|
let accountKeys = [];
|
|
201
250
|
for (let i = 0; i < accountCount; i++) {
|
|
202
|
-
const account = byteArray.slice(0,
|
|
203
|
-
byteArray = byteArray.slice(
|
|
251
|
+
const account = byteArray.slice(0, PUBLIC_KEY_LENGTH);
|
|
252
|
+
byteArray = byteArray.slice(PUBLIC_KEY_LENGTH);
|
|
204
253
|
accountKeys.push(bs58.encode(Buffer.from(account)));
|
|
205
254
|
}
|
|
206
255
|
|
|
207
|
-
const recentBlockhash = byteArray.slice(0,
|
|
208
|
-
byteArray = byteArray.slice(
|
|
256
|
+
const recentBlockhash = byteArray.slice(0, PUBLIC_KEY_LENGTH);
|
|
257
|
+
byteArray = byteArray.slice(PUBLIC_KEY_LENGTH);
|
|
209
258
|
|
|
210
259
|
const instructionCount = shortvec.decodeLength(byteArray);
|
|
211
260
|
let instructions: CompiledInstruction[] = [];
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import bs58 from 'bs58';
|
|
2
|
+
import * as BufferLayout from '@solana/buffer-layout';
|
|
3
|
+
|
|
4
|
+
import * as Layout from '../layout';
|
|
5
|
+
import {Blockhash} from '../blockhash';
|
|
6
|
+
import {
|
|
7
|
+
MessageHeader,
|
|
8
|
+
MessageAddressTableLookup,
|
|
9
|
+
MessageCompiledInstruction,
|
|
10
|
+
} from './index';
|
|
11
|
+
import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey';
|
|
12
|
+
import * as shortvec from '../utils/shortvec-encoding';
|
|
13
|
+
import assert from '../utils/assert';
|
|
14
|
+
import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Message constructor arguments
|
|
18
|
+
*/
|
|
19
|
+
export type MessageV0Args = {
|
|
20
|
+
/** The message header, identifying signed and read-only `accountKeys` */
|
|
21
|
+
header: MessageHeader;
|
|
22
|
+
/** The static account keys used by this transaction */
|
|
23
|
+
staticAccountKeys: PublicKey[];
|
|
24
|
+
/** The hash of a recent ledger block */
|
|
25
|
+
recentBlockhash: Blockhash;
|
|
26
|
+
/** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */
|
|
27
|
+
compiledInstructions: MessageCompiledInstruction[];
|
|
28
|
+
/** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */
|
|
29
|
+
addressTableLookups: MessageAddressTableLookup[];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class MessageV0 {
|
|
33
|
+
header: MessageHeader;
|
|
34
|
+
staticAccountKeys: Array<PublicKey>;
|
|
35
|
+
recentBlockhash: Blockhash;
|
|
36
|
+
compiledInstructions: Array<MessageCompiledInstruction>;
|
|
37
|
+
addressTableLookups: Array<MessageAddressTableLookup>;
|
|
38
|
+
|
|
39
|
+
constructor(args: MessageV0Args) {
|
|
40
|
+
this.header = args.header;
|
|
41
|
+
this.staticAccountKeys = args.staticAccountKeys;
|
|
42
|
+
this.recentBlockhash = args.recentBlockhash;
|
|
43
|
+
this.compiledInstructions = args.compiledInstructions;
|
|
44
|
+
this.addressTableLookups = args.addressTableLookups;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get version(): 0 {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
serialize(): Uint8Array {
|
|
52
|
+
const encodedStaticAccountKeysLength = Array<number>();
|
|
53
|
+
shortvec.encodeLength(
|
|
54
|
+
encodedStaticAccountKeysLength,
|
|
55
|
+
this.staticAccountKeys.length,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const serializedInstructions = this.serializeInstructions();
|
|
59
|
+
const encodedInstructionsLength = Array<number>();
|
|
60
|
+
shortvec.encodeLength(
|
|
61
|
+
encodedInstructionsLength,
|
|
62
|
+
this.compiledInstructions.length,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const serializedAddressTableLookups = this.serializeAddressTableLookups();
|
|
66
|
+
const encodedAddressTableLookupsLength = Array<number>();
|
|
67
|
+
shortvec.encodeLength(
|
|
68
|
+
encodedAddressTableLookupsLength,
|
|
69
|
+
this.addressTableLookups.length,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const messageLayout = BufferLayout.struct<{
|
|
73
|
+
prefix: number;
|
|
74
|
+
header: MessageHeader;
|
|
75
|
+
staticAccountKeysLength: Uint8Array;
|
|
76
|
+
staticAccountKeys: Array<Uint8Array>;
|
|
77
|
+
recentBlockhash: Uint8Array;
|
|
78
|
+
instructionsLength: Uint8Array;
|
|
79
|
+
serializedInstructions: Uint8Array;
|
|
80
|
+
addressTableLookupsLength: Uint8Array;
|
|
81
|
+
serializedAddressTableLookups: Uint8Array;
|
|
82
|
+
}>([
|
|
83
|
+
BufferLayout.u8('prefix'),
|
|
84
|
+
BufferLayout.struct<MessageHeader>(
|
|
85
|
+
[
|
|
86
|
+
BufferLayout.u8('numRequiredSignatures'),
|
|
87
|
+
BufferLayout.u8('numReadonlySignedAccounts'),
|
|
88
|
+
BufferLayout.u8('numReadonlyUnsignedAccounts'),
|
|
89
|
+
],
|
|
90
|
+
'header',
|
|
91
|
+
),
|
|
92
|
+
BufferLayout.blob(
|
|
93
|
+
encodedStaticAccountKeysLength.length,
|
|
94
|
+
'staticAccountKeysLength',
|
|
95
|
+
),
|
|
96
|
+
BufferLayout.seq(
|
|
97
|
+
Layout.publicKey(),
|
|
98
|
+
this.staticAccountKeys.length,
|
|
99
|
+
'staticAccountKeys',
|
|
100
|
+
),
|
|
101
|
+
Layout.publicKey('recentBlockhash'),
|
|
102
|
+
BufferLayout.blob(encodedInstructionsLength.length, 'instructionsLength'),
|
|
103
|
+
BufferLayout.blob(
|
|
104
|
+
serializedInstructions.length,
|
|
105
|
+
'serializedInstructions',
|
|
106
|
+
),
|
|
107
|
+
BufferLayout.blob(
|
|
108
|
+
encodedAddressTableLookupsLength.length,
|
|
109
|
+
'addressTableLookupsLength',
|
|
110
|
+
),
|
|
111
|
+
BufferLayout.blob(
|
|
112
|
+
serializedAddressTableLookups.length,
|
|
113
|
+
'serializedAddressTableLookups',
|
|
114
|
+
),
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
const serializedMessage = new Uint8Array(PACKET_DATA_SIZE);
|
|
118
|
+
const MESSAGE_VERSION_0_PREFIX = 1 << 7;
|
|
119
|
+
const serializedMessageLength = messageLayout.encode(
|
|
120
|
+
{
|
|
121
|
+
prefix: MESSAGE_VERSION_0_PREFIX,
|
|
122
|
+
header: this.header,
|
|
123
|
+
staticAccountKeysLength: new Uint8Array(encodedStaticAccountKeysLength),
|
|
124
|
+
staticAccountKeys: this.staticAccountKeys.map(key => key.toBytes()),
|
|
125
|
+
recentBlockhash: bs58.decode(this.recentBlockhash),
|
|
126
|
+
instructionsLength: new Uint8Array(encodedInstructionsLength),
|
|
127
|
+
serializedInstructions,
|
|
128
|
+
addressTableLookupsLength: new Uint8Array(
|
|
129
|
+
encodedAddressTableLookupsLength,
|
|
130
|
+
),
|
|
131
|
+
serializedAddressTableLookups,
|
|
132
|
+
},
|
|
133
|
+
serializedMessage,
|
|
134
|
+
);
|
|
135
|
+
return serializedMessage.slice(0, serializedMessageLength);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private serializeInstructions(): Uint8Array {
|
|
139
|
+
let serializedLength = 0;
|
|
140
|
+
const serializedInstructions = new Uint8Array(PACKET_DATA_SIZE);
|
|
141
|
+
for (const instruction of this.compiledInstructions) {
|
|
142
|
+
const encodedAccountKeyIndexesLength = Array<number>();
|
|
143
|
+
shortvec.encodeLength(
|
|
144
|
+
encodedAccountKeyIndexesLength,
|
|
145
|
+
instruction.accountKeyIndexes.length,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const encodedDataLength = Array<number>();
|
|
149
|
+
shortvec.encodeLength(encodedDataLength, instruction.data.length);
|
|
150
|
+
|
|
151
|
+
const instructionLayout = BufferLayout.struct<{
|
|
152
|
+
programIdIndex: number;
|
|
153
|
+
encodedAccountKeyIndexesLength: Uint8Array;
|
|
154
|
+
accountKeyIndexes: number[];
|
|
155
|
+
encodedDataLength: Uint8Array;
|
|
156
|
+
data: Uint8Array;
|
|
157
|
+
}>([
|
|
158
|
+
BufferLayout.u8('programIdIndex'),
|
|
159
|
+
BufferLayout.blob(
|
|
160
|
+
encodedAccountKeyIndexesLength.length,
|
|
161
|
+
'encodedAccountKeyIndexesLength',
|
|
162
|
+
),
|
|
163
|
+
BufferLayout.seq(
|
|
164
|
+
BufferLayout.u8(),
|
|
165
|
+
instruction.accountKeyIndexes.length,
|
|
166
|
+
'accountKeyIndexes',
|
|
167
|
+
),
|
|
168
|
+
BufferLayout.blob(encodedDataLength.length, 'encodedDataLength'),
|
|
169
|
+
BufferLayout.blob(instruction.data.length, 'data'),
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
serializedLength += instructionLayout.encode(
|
|
173
|
+
{
|
|
174
|
+
programIdIndex: instruction.programIdIndex,
|
|
175
|
+
encodedAccountKeyIndexesLength: new Uint8Array(
|
|
176
|
+
encodedAccountKeyIndexesLength,
|
|
177
|
+
),
|
|
178
|
+
accountKeyIndexes: instruction.accountKeyIndexes,
|
|
179
|
+
encodedDataLength: new Uint8Array(encodedDataLength),
|
|
180
|
+
data: instruction.data,
|
|
181
|
+
},
|
|
182
|
+
serializedInstructions,
|
|
183
|
+
serializedLength,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return serializedInstructions.slice(0, serializedLength);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private serializeAddressTableLookups(): Uint8Array {
|
|
191
|
+
let serializedLength = 0;
|
|
192
|
+
const serializedAddressTableLookups = new Uint8Array(PACKET_DATA_SIZE);
|
|
193
|
+
for (const lookup of this.addressTableLookups) {
|
|
194
|
+
const encodedWritableIndexesLength = Array<number>();
|
|
195
|
+
shortvec.encodeLength(
|
|
196
|
+
encodedWritableIndexesLength,
|
|
197
|
+
lookup.writableIndexes.length,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const encodedReadonlyIndexesLength = Array<number>();
|
|
201
|
+
shortvec.encodeLength(
|
|
202
|
+
encodedReadonlyIndexesLength,
|
|
203
|
+
lookup.readonlyIndexes.length,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const addressTableLookupLayout = BufferLayout.struct<{
|
|
207
|
+
accountKey: Uint8Array;
|
|
208
|
+
encodedWritableIndexesLength: Uint8Array;
|
|
209
|
+
writableIndexes: number[];
|
|
210
|
+
encodedReadonlyIndexesLength: Uint8Array;
|
|
211
|
+
readonlyIndexes: number[];
|
|
212
|
+
}>([
|
|
213
|
+
Layout.publicKey('accountKey'),
|
|
214
|
+
BufferLayout.blob(
|
|
215
|
+
encodedWritableIndexesLength.length,
|
|
216
|
+
'encodedWritableIndexesLength',
|
|
217
|
+
),
|
|
218
|
+
BufferLayout.seq(
|
|
219
|
+
BufferLayout.u8(),
|
|
220
|
+
lookup.writableIndexes.length,
|
|
221
|
+
'writableIndexes',
|
|
222
|
+
),
|
|
223
|
+
BufferLayout.blob(
|
|
224
|
+
encodedReadonlyIndexesLength.length,
|
|
225
|
+
'encodedReadonlyIndexesLength',
|
|
226
|
+
),
|
|
227
|
+
BufferLayout.seq(
|
|
228
|
+
BufferLayout.u8(),
|
|
229
|
+
lookup.readonlyIndexes.length,
|
|
230
|
+
'readonlyIndexes',
|
|
231
|
+
),
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
serializedLength += addressTableLookupLayout.encode(
|
|
235
|
+
{
|
|
236
|
+
accountKey: lookup.accountKey.toBytes(),
|
|
237
|
+
encodedWritableIndexesLength: new Uint8Array(
|
|
238
|
+
encodedWritableIndexesLength,
|
|
239
|
+
),
|
|
240
|
+
writableIndexes: lookup.writableIndexes,
|
|
241
|
+
encodedReadonlyIndexesLength: new Uint8Array(
|
|
242
|
+
encodedReadonlyIndexesLength,
|
|
243
|
+
),
|
|
244
|
+
readonlyIndexes: lookup.readonlyIndexes,
|
|
245
|
+
},
|
|
246
|
+
serializedAddressTableLookups,
|
|
247
|
+
serializedLength,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return serializedAddressTableLookups.slice(0, serializedLength);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
static deserialize(serializedMessage: Uint8Array): MessageV0 {
|
|
255
|
+
let byteArray = [...serializedMessage];
|
|
256
|
+
|
|
257
|
+
const prefix = byteArray.shift() as number;
|
|
258
|
+
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
|
|
259
|
+
assert(
|
|
260
|
+
prefix !== maskedPrefix,
|
|
261
|
+
`Expected versioned message but received legacy message`,
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const version = maskedPrefix;
|
|
265
|
+
assert(
|
|
266
|
+
version === 0,
|
|
267
|
+
`Expected versioned message with version 0 but found version ${version}`,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const header: MessageHeader = {
|
|
271
|
+
numRequiredSignatures: byteArray.shift() as number,
|
|
272
|
+
numReadonlySignedAccounts: byteArray.shift() as number,
|
|
273
|
+
numReadonlyUnsignedAccounts: byteArray.shift() as number,
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const staticAccountKeys = [];
|
|
277
|
+
const staticAccountKeysLength = shortvec.decodeLength(byteArray);
|
|
278
|
+
for (let i = 0; i < staticAccountKeysLength; i++) {
|
|
279
|
+
staticAccountKeys.push(
|
|
280
|
+
new PublicKey(byteArray.splice(0, PUBLIC_KEY_LENGTH)),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const recentBlockhash = bs58.encode(byteArray.splice(0, PUBLIC_KEY_LENGTH));
|
|
285
|
+
|
|
286
|
+
const instructionCount = shortvec.decodeLength(byteArray);
|
|
287
|
+
const compiledInstructions: MessageCompiledInstruction[] = [];
|
|
288
|
+
for (let i = 0; i < instructionCount; i++) {
|
|
289
|
+
const programIdIndex = byteArray.shift() as number;
|
|
290
|
+
const accountKeyIndexesLength = shortvec.decodeLength(byteArray);
|
|
291
|
+
const accountKeyIndexes = byteArray.splice(0, accountKeyIndexesLength);
|
|
292
|
+
const dataLength = shortvec.decodeLength(byteArray);
|
|
293
|
+
const data = new Uint8Array(byteArray.splice(0, dataLength));
|
|
294
|
+
compiledInstructions.push({
|
|
295
|
+
programIdIndex,
|
|
296
|
+
accountKeyIndexes,
|
|
297
|
+
data,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const addressTableLookupsCount = shortvec.decodeLength(byteArray);
|
|
302
|
+
const addressTableLookups: MessageAddressTableLookup[] = [];
|
|
303
|
+
for (let i = 0; i < addressTableLookupsCount; i++) {
|
|
304
|
+
const accountKey = new PublicKey(byteArray.splice(0, PUBLIC_KEY_LENGTH));
|
|
305
|
+
const writableIndexesLength = shortvec.decodeLength(byteArray);
|
|
306
|
+
const writableIndexes = byteArray.splice(0, writableIndexesLength);
|
|
307
|
+
const readonlyIndexesLength = shortvec.decodeLength(byteArray);
|
|
308
|
+
const readonlyIndexes = byteArray.splice(0, readonlyIndexesLength);
|
|
309
|
+
addressTableLookups.push({
|
|
310
|
+
accountKey,
|
|
311
|
+
writableIndexes,
|
|
312
|
+
readonlyIndexes,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return new MessageV0({
|
|
317
|
+
header,
|
|
318
|
+
staticAccountKeys,
|
|
319
|
+
recentBlockhash,
|
|
320
|
+
compiledInstructions,
|
|
321
|
+
addressTableLookups,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {VERSION_PREFIX_MASK} from '../transaction/constants';
|
|
2
|
+
import {Message} from './legacy';
|
|
3
|
+
import {MessageV0} from './v0';
|
|
4
|
+
|
|
5
|
+
export type VersionedMessage = Message | MessageV0;
|
|
6
|
+
// eslint-disable-next-line no-redeclare
|
|
7
|
+
export const VersionedMessage = {
|
|
8
|
+
deserialize: (serializedMessage: Uint8Array): VersionedMessage => {
|
|
9
|
+
const prefix = serializedMessage[0];
|
|
10
|
+
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
|
|
11
|
+
|
|
12
|
+
// if the highest bit of the prefix is not set, the message is not versioned
|
|
13
|
+
if (maskedPrefix === prefix) {
|
|
14
|
+
return Message.from(serializedMessage);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// the lower 7 bits of the prefix indicate the message version
|
|
18
|
+
const version = maskedPrefix;
|
|
19
|
+
if (version === 0) {
|
|
20
|
+
return MessageV0.deserialize(serializedMessage);
|
|
21
|
+
} else {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Transaction message version ${version} deserialization is not supported`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
};
|
package/src/programs/vote.ts
CHANGED
|
@@ -410,4 +410,25 @@ export class VoteProgram {
|
|
|
410
410
|
data,
|
|
411
411
|
});
|
|
412
412
|
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Generate a transaction to withdraw safely from a Vote account.
|
|
416
|
+
*
|
|
417
|
+
* This function was created as a safeguard for vote accounts running validators, `safeWithdraw`
|
|
418
|
+
* checks that the withdraw amount will not exceed the specified balance while leaving enough left
|
|
419
|
+
* to cover rent. If you wish to close the vote account by withdrawing the full amount, call the
|
|
420
|
+
* `withdraw` method directly.
|
|
421
|
+
*/
|
|
422
|
+
static safeWithdraw(
|
|
423
|
+
params: WithdrawFromVoteAccountParams,
|
|
424
|
+
currentVoteAccountBalance: number,
|
|
425
|
+
rentExemptMinimum: number,
|
|
426
|
+
): Transaction {
|
|
427
|
+
if (params.lamports > currentVoteAccountBalance - rentExemptMinimum) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
'Withdraw will leave vote account with insuffcient funds.',
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
return VoteProgram.withdraw(params);
|
|
433
|
+
}
|
|
413
434
|
}
|
package/src/publickey.ts
CHANGED
|
@@ -12,6 +12,11 @@ import {toBuffer} from './utils/to-buffer';
|
|
|
12
12
|
*/
|
|
13
13
|
export const MAX_SEED_LENGTH = 32;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Size of public key in bytes
|
|
17
|
+
*/
|
|
18
|
+
export const PUBLIC_KEY_LENGTH = 32;
|
|
19
|
+
|
|
15
20
|
/**
|
|
16
21
|
* Value to be converted into public key
|
|
17
22
|
*/
|
|
@@ -54,7 +59,7 @@ export class PublicKey extends Struct {
|
|
|
54
59
|
if (typeof value === 'string') {
|
|
55
60
|
// assume base 58 encoding by default
|
|
56
61
|
const decoded = bs58.decode(value);
|
|
57
|
-
if (decoded.length !=
|
|
62
|
+
if (decoded.length != PUBLIC_KEY_LENGTH) {
|
|
58
63
|
throw new Error(`Invalid public key input`);
|
|
59
64
|
}
|
|
60
65
|
this._bn = new BN(decoded);
|
|
@@ -103,7 +108,7 @@ export class PublicKey extends Struct {
|
|
|
103
108
|
*/
|
|
104
109
|
toBuffer(): Buffer {
|
|
105
110
|
const b = this._bn.toArrayLike(Buffer);
|
|
106
|
-
if (b.length ===
|
|
111
|
+
if (b.length === PUBLIC_KEY_LENGTH) {
|
|
107
112
|
return b;
|
|
108
113
|
}
|
|
109
114
|
|
package/src/transaction/index.ts
CHANGED