@solana/web3.js 1.24.2 → 1.28.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.esm.js +724 -30
- package/lib/index.browser.esm.js.map +1 -1
- package/lib/index.cjs.js +167 -8
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +75 -2
- package/lib/index.esm.js +167 -9
- package/lib/index.esm.js.map +1 -1
- package/lib/index.iife.js +730 -37
- package/lib/index.iife.js.map +1 -1
- package/lib/index.iife.min.js +4 -4
- package/lib/index.iife.min.js.map +1 -1
- package/module.flow.js +104 -3
- package/package.json +8 -5
- package/src/connection.ts +76 -5
- package/src/ed25519-program.ts +140 -0
- package/src/index.ts +1 -0
- package/src/message.ts +27 -0
- package/src/publickey.ts +8 -2
- package/src/transaction.ts +10 -6
package/module.flow.js
CHANGED
|
@@ -23,6 +23,10 @@ declare module "@solana/web3.js" {
|
|
|
23
23
|
* Maximum length of derived pubkey seed
|
|
24
24
|
*/
|
|
25
25
|
declare export var MAX_SEED_LENGTH: 32;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Value to be converted into public key
|
|
29
|
+
*/
|
|
26
30
|
declare export type PublicKeyInitData =
|
|
27
31
|
| number
|
|
28
32
|
| string
|
|
@@ -30,6 +34,10 @@ declare module "@solana/web3.js" {
|
|
|
30
34
|
| Uint8Array
|
|
31
35
|
| Array<number>
|
|
32
36
|
| PublicKeyData;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* JSON object representation of PublicKey class
|
|
40
|
+
*/
|
|
33
41
|
declare export type PublicKeyData = { ... };
|
|
34
42
|
|
|
35
43
|
/**
|
|
@@ -354,7 +362,11 @@ declare module "@solana/web3.js" {
|
|
|
354
362
|
recentBlockhash: Blockhash;
|
|
355
363
|
instructions: CompiledInstruction[];
|
|
356
364
|
constructor(args: MessageArgs): this;
|
|
365
|
+
isAccountSigner(index: number): boolean;
|
|
357
366
|
isAccountWritable(index: number): boolean;
|
|
367
|
+
isProgramId(index: number): boolean;
|
|
368
|
+
programIds(): PublicKey[];
|
|
369
|
+
nonProgramIds(): PublicKey[];
|
|
358
370
|
serialize(): Buffer;
|
|
359
371
|
|
|
360
372
|
/**
|
|
@@ -618,7 +630,7 @@ declare module "@solana/web3.js" {
|
|
|
618
630
|
/**
|
|
619
631
|
* Populate Transaction object from message and signatures
|
|
620
632
|
*/
|
|
621
|
-
static populate(message: Message, signatures
|
|
633
|
+
static populate(message: Message, signatures?: Array<string>): Transaction;
|
|
622
634
|
}
|
|
623
635
|
declare export type TokenAccountsFilter =
|
|
624
636
|
| {
|
|
@@ -958,9 +970,38 @@ declare module "@solana/web3.js" {
|
|
|
958
970
|
"feature-set"?: number,
|
|
959
971
|
...
|
|
960
972
|
};
|
|
973
|
+
declare export type SimulatedTransactionAccountInfo = {
|
|
974
|
+
/**
|
|
975
|
+
* `true` if this account's data contains a loaded program
|
|
976
|
+
*/
|
|
977
|
+
executable: boolean,
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Identifier of the program that owns the account
|
|
981
|
+
*/
|
|
982
|
+
owner: string,
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Number of lamports assigned to the account
|
|
986
|
+
*/
|
|
987
|
+
lamports: number,
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Optional data assigned to the account
|
|
991
|
+
*/
|
|
992
|
+
data: string[],
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Optional rent epoch info for account
|
|
996
|
+
*/
|
|
997
|
+
rentEpoch?: number,
|
|
998
|
+
...
|
|
999
|
+
};
|
|
961
1000
|
declare export type SimulatedTransactionResponse = {
|
|
962
1001
|
err: TransactionError | string | null,
|
|
963
1002
|
logs: Array<string> | null,
|
|
1003
|
+
accounts?: SimulatedTransactionAccountInfo[] | null,
|
|
1004
|
+
unitsConsumed?: number,
|
|
964
1005
|
...
|
|
965
1006
|
};
|
|
966
1007
|
declare export type ParsedInnerInstruction = {
|
|
@@ -1783,6 +1824,11 @@ declare module "@solana/web3.js" {
|
|
|
1783
1824
|
* Optional data assigned to the account
|
|
1784
1825
|
*/
|
|
1785
1826
|
data: T,
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* Optional rent epoch infor for account
|
|
1830
|
+
*/
|
|
1831
|
+
rentEpoch?: number,
|
|
1786
1832
|
...
|
|
1787
1833
|
};
|
|
1788
1834
|
|
|
@@ -2016,6 +2062,11 @@ declare module "@solana/web3.js" {
|
|
|
2016
2062
|
* Optional Disable retring calls when server responds with HTTP 429 (Too Many Requests)
|
|
2017
2063
|
*/
|
|
2018
2064
|
disableRetryOnRateLimit?: boolean,
|
|
2065
|
+
|
|
2066
|
+
/**
|
|
2067
|
+
* time to allow for the server to initially process a transaction (in milliseconds)
|
|
2068
|
+
*/
|
|
2069
|
+
confirmTransactionInitialTimeout?: number,
|
|
2019
2070
|
...
|
|
2020
2071
|
};
|
|
2021
2072
|
|
|
@@ -2373,6 +2424,11 @@ feeCalculator: FeeCalculator,...
|
|
|
2373
2424
|
*/
|
|
2374
2425
|
getVersion(): Promise<Version>;
|
|
2375
2426
|
|
|
2427
|
+
/**
|
|
2428
|
+
* Fetch the genesis hash
|
|
2429
|
+
*/
|
|
2430
|
+
getGenesisHash(): Promise<string>;
|
|
2431
|
+
|
|
2376
2432
|
/**
|
|
2377
2433
|
* Fetch a processed block from the cluster.
|
|
2378
2434
|
*/
|
|
@@ -2514,8 +2570,9 @@ feeCalculator: FeeCalculator,...
|
|
|
2514
2570
|
* Simulate a transaction
|
|
2515
2571
|
*/
|
|
2516
2572
|
simulateTransaction(
|
|
2517
|
-
|
|
2518
|
-
signers?: Array<Signer
|
|
2573
|
+
transactionOrMessage: Transaction | Message,
|
|
2574
|
+
signers?: Array<Signer>,
|
|
2575
|
+
includeAccounts?: boolean | Array<PublicKey>
|
|
2519
2576
|
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>>;
|
|
2520
2577
|
|
|
2521
2578
|
/**
|
|
@@ -2712,6 +2769,50 @@ feeCalculator: FeeCalculator,...
|
|
|
2712
2769
|
): Promise<boolean>;
|
|
2713
2770
|
}
|
|
2714
2771
|
|
|
2772
|
+
/**
|
|
2773
|
+
* Params for creating an ed25519 instruction using a public key
|
|
2774
|
+
*/
|
|
2775
|
+
declare export type CreateEd25519InstructionWithPublicKeyParams = {
|
|
2776
|
+
publicKey: Uint8Array,
|
|
2777
|
+
message: Uint8Array,
|
|
2778
|
+
signature: Uint8Array,
|
|
2779
|
+
instructionIndex?: number,
|
|
2780
|
+
...
|
|
2781
|
+
};
|
|
2782
|
+
|
|
2783
|
+
/**
|
|
2784
|
+
* Params for creating an ed25519 instruction using a private key
|
|
2785
|
+
*/
|
|
2786
|
+
declare export type CreateEd25519InstructionWithPrivateKeyParams = {
|
|
2787
|
+
privateKey: Uint8Array,
|
|
2788
|
+
message: Uint8Array,
|
|
2789
|
+
instructionIndex?: number,
|
|
2790
|
+
...
|
|
2791
|
+
};
|
|
2792
|
+
declare export class Ed25519Program {
|
|
2793
|
+
/**
|
|
2794
|
+
* Public key that identifies the ed25519 program
|
|
2795
|
+
*/
|
|
2796
|
+
static programId: PublicKey;
|
|
2797
|
+
|
|
2798
|
+
/**
|
|
2799
|
+
* Create an ed25519 instruction with a public key and signature. The
|
|
2800
|
+
* public key must be a buffer that is 32 bytes long, and the signature
|
|
2801
|
+
* must be a buffer of 64 bytes.
|
|
2802
|
+
*/
|
|
2803
|
+
static createInstructionWithPublicKey(
|
|
2804
|
+
params: CreateEd25519InstructionWithPublicKeyParams
|
|
2805
|
+
): TransactionInstruction;
|
|
2806
|
+
|
|
2807
|
+
/**
|
|
2808
|
+
* Create an ed25519 instruction with a private key. The private key
|
|
2809
|
+
* must be a buffer that is 64 bytes long.
|
|
2810
|
+
*/
|
|
2811
|
+
static createInstructionWithPrivateKey(
|
|
2812
|
+
params: CreateEd25519InstructionWithPrivateKeyParams
|
|
2813
|
+
): TransactionInstruction;
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2715
2816
|
/**
|
|
2716
2817
|
* Program loader interface
|
|
2717
2818
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/web3.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "Solana Javascript API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"clean": "rimraf ./coverage ./lib",
|
|
44
44
|
"codecov": "set -ex; npm run test:cover; cat ./coverage/lcov.info | codecov",
|
|
45
45
|
"dev": "cross-env NODE_ENV=development rollup -c",
|
|
46
|
-
"doc": "set -ex; typedoc",
|
|
46
|
+
"doc": "set -ex; typedoc --treatWarningsAsErrors",
|
|
47
47
|
"flow:check": "flow check-contents < module.flow.js",
|
|
48
48
|
"flow:gen": "flowgen lib/index.d.ts -o module.flow.js",
|
|
49
49
|
"type:gen": "./scripts/typegen.sh",
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
"borsh": "^0.4.0",
|
|
69
69
|
"bs58": "^4.0.1",
|
|
70
70
|
"buffer": "6.0.1",
|
|
71
|
+
"cross-fetch": "^3.1.4",
|
|
71
72
|
"crypto-hash": "^1.2.2",
|
|
72
73
|
"jayson": "^3.4.4",
|
|
73
74
|
"js-sha3": "^0.8.0",
|
|
74
|
-
"node-fetch": "^2.6.1",
|
|
75
75
|
"rpc-websockets": "^7.4.2",
|
|
76
76
|
"secp256k1": "^4.0.2",
|
|
77
77
|
"superstruct": "^0.14.2",
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
"@types/mocha": "^9.0.0",
|
|
103
103
|
"@types/mz": "^2.7.3",
|
|
104
104
|
"@types/node": "^16.0.0",
|
|
105
|
-
"@types/node-fetch": "^2.5.8",
|
|
106
105
|
"@types/secp256k1": "^4.0.1",
|
|
107
106
|
"@types/sinon": "^10.0.0",
|
|
108
107
|
"@typescript-eslint/eslint-plugin": "^4.14.2",
|
|
@@ -127,6 +126,7 @@
|
|
|
127
126
|
"npm-run-all": "^4.1.5",
|
|
128
127
|
"nyc": "^15.1.0",
|
|
129
128
|
"prettier": "^2.3.0",
|
|
129
|
+
"puppeteer": "^10.2.0",
|
|
130
130
|
"rimraf": "3.0.2",
|
|
131
131
|
"rollup": "2.56.3",
|
|
132
132
|
"rollup-plugin-dts": "^4.0.0",
|
|
@@ -137,7 +137,10 @@
|
|
|
137
137
|
"start-server-and-test": "^1.12.0",
|
|
138
138
|
"ts-node": "^10.0.0",
|
|
139
139
|
"tslib": "^2.1.0",
|
|
140
|
-
"typedoc": "^0.
|
|
140
|
+
"typedoc": "^0.22.2",
|
|
141
141
|
"typescript": "^4.3.2"
|
|
142
|
+
},
|
|
143
|
+
"engines": {
|
|
144
|
+
"node": ">=12.20.0"
|
|
142
145
|
}
|
|
143
146
|
}
|
package/src/connection.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import bs58 from 'bs58';
|
|
2
2
|
import {Buffer} from 'buffer';
|
|
3
|
-
import fetch
|
|
3
|
+
import fetch from 'cross-fetch';
|
|
4
|
+
import type {Response} from 'cross-fetch';
|
|
4
5
|
import {
|
|
5
6
|
type as pick,
|
|
6
7
|
number,
|
|
@@ -438,15 +439,44 @@ const VersionResult = pick({
|
|
|
438
439
|
'feature-set': optional(number()),
|
|
439
440
|
});
|
|
440
441
|
|
|
442
|
+
export type SimulatedTransactionAccountInfo = {
|
|
443
|
+
/** `true` if this account's data contains a loaded program */
|
|
444
|
+
executable: boolean;
|
|
445
|
+
/** Identifier of the program that owns the account */
|
|
446
|
+
owner: string;
|
|
447
|
+
/** Number of lamports assigned to the account */
|
|
448
|
+
lamports: number;
|
|
449
|
+
/** Optional data assigned to the account */
|
|
450
|
+
data: string[];
|
|
451
|
+
/** Optional rent epoch info for account */
|
|
452
|
+
rentEpoch?: number;
|
|
453
|
+
};
|
|
454
|
+
|
|
441
455
|
export type SimulatedTransactionResponse = {
|
|
442
456
|
err: TransactionError | string | null;
|
|
443
457
|
logs: Array<string> | null;
|
|
458
|
+
accounts?: SimulatedTransactionAccountInfo[] | null;
|
|
459
|
+
unitsConsumed?: number;
|
|
444
460
|
};
|
|
445
461
|
|
|
446
462
|
const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(
|
|
447
463
|
pick({
|
|
448
464
|
err: nullable(union([pick({}), string()])),
|
|
449
465
|
logs: nullable(array(string())),
|
|
466
|
+
accounts: optional(
|
|
467
|
+
nullable(
|
|
468
|
+
array(
|
|
469
|
+
pick({
|
|
470
|
+
executable: boolean(),
|
|
471
|
+
owner: string(),
|
|
472
|
+
lamports: number(),
|
|
473
|
+
data: array(string()),
|
|
474
|
+
rentEpoch: optional(number()),
|
|
475
|
+
}),
|
|
476
|
+
),
|
|
477
|
+
),
|
|
478
|
+
),
|
|
479
|
+
unitsConsumed: optional(number()),
|
|
450
480
|
}),
|
|
451
481
|
);
|
|
452
482
|
|
|
@@ -1678,6 +1708,8 @@ export type AccountInfo<T> = {
|
|
|
1678
1708
|
lamports: number;
|
|
1679
1709
|
/** Optional data assigned to the account */
|
|
1680
1710
|
data: T;
|
|
1711
|
+
/** Optional rent epoch infor for account */
|
|
1712
|
+
rentEpoch?: number;
|
|
1681
1713
|
};
|
|
1682
1714
|
|
|
1683
1715
|
/**
|
|
@@ -1947,6 +1979,8 @@ export type ConnectionConfig = {
|
|
|
1947
1979
|
fetchMiddleware?: FetchMiddleware;
|
|
1948
1980
|
/** Optional Disable retring calls when server responds with HTTP 429 (Too Many Requests) */
|
|
1949
1981
|
disableRetryOnRateLimit?: boolean;
|
|
1982
|
+
/** time to allow for the server to initially process a transaction (in milliseconds) */
|
|
1983
|
+
confirmTransactionInitialTimeout?: number;
|
|
1950
1984
|
};
|
|
1951
1985
|
|
|
1952
1986
|
/**
|
|
@@ -1954,6 +1988,7 @@ export type ConnectionConfig = {
|
|
|
1954
1988
|
*/
|
|
1955
1989
|
export class Connection {
|
|
1956
1990
|
/** @internal */ _commitment?: Commitment;
|
|
1991
|
+
/** @internal */ _confirmTransactionInitialTimeout?: number;
|
|
1957
1992
|
/** @internal */ _rpcEndpoint: string;
|
|
1958
1993
|
/** @internal */ _rpcWsEndpoint: string;
|
|
1959
1994
|
/** @internal */ _rpcClient: RpcClient;
|
|
@@ -2038,6 +2073,8 @@ export class Connection {
|
|
|
2038
2073
|
this._commitment = commitmentOrConfig;
|
|
2039
2074
|
} else if (commitmentOrConfig) {
|
|
2040
2075
|
this._commitment = commitmentOrConfig.commitment;
|
|
2076
|
+
this._confirmTransactionInitialTimeout =
|
|
2077
|
+
commitmentOrConfig.confirmTransactionInitialTimeout;
|
|
2041
2078
|
wsEndpoint = commitmentOrConfig.wsEndpoint;
|
|
2042
2079
|
httpHeaders = commitmentOrConfig.httpHeaders;
|
|
2043
2080
|
fetchMiddleware = commitmentOrConfig.fetchMiddleware;
|
|
@@ -2597,14 +2634,14 @@ export class Connection {
|
|
|
2597
2634
|
}
|
|
2598
2635
|
});
|
|
2599
2636
|
|
|
2600
|
-
let timeoutMs = 60 * 1000;
|
|
2637
|
+
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
|
|
2601
2638
|
switch (subscriptionCommitment) {
|
|
2602
2639
|
case 'processed':
|
|
2603
2640
|
case 'recent':
|
|
2604
2641
|
case 'single':
|
|
2605
2642
|
case 'confirmed':
|
|
2606
2643
|
case 'singleGossip': {
|
|
2607
|
-
timeoutMs = 30 * 1000;
|
|
2644
|
+
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
|
|
2608
2645
|
break;
|
|
2609
2646
|
}
|
|
2610
2647
|
// exhaust enums to ensure full coverage
|
|
@@ -2962,6 +2999,18 @@ export class Connection {
|
|
|
2962
2999
|
return res.result;
|
|
2963
3000
|
}
|
|
2964
3001
|
|
|
3002
|
+
/**
|
|
3003
|
+
* Fetch the genesis hash
|
|
3004
|
+
*/
|
|
3005
|
+
async getGenesisHash(): Promise<string> {
|
|
3006
|
+
const unsafeRes = await this._rpcRequest('getGenesisHash', []);
|
|
3007
|
+
const res = create(unsafeRes, jsonRpcResult(string()));
|
|
3008
|
+
if ('error' in res) {
|
|
3009
|
+
throw new Error('failed to get genesis hash: ' + res.error.message);
|
|
3010
|
+
}
|
|
3011
|
+
return res.result;
|
|
3012
|
+
}
|
|
3013
|
+
|
|
2965
3014
|
/**
|
|
2966
3015
|
* Fetch a processed block from the cluster.
|
|
2967
3016
|
*/
|
|
@@ -3417,9 +3466,17 @@ export class Connection {
|
|
|
3417
3466
|
* Simulate a transaction
|
|
3418
3467
|
*/
|
|
3419
3468
|
async simulateTransaction(
|
|
3420
|
-
|
|
3469
|
+
transactionOrMessage: Transaction | Message,
|
|
3421
3470
|
signers?: Array<Signer>,
|
|
3471
|
+
includeAccounts?: boolean | Array<PublicKey>,
|
|
3422
3472
|
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>> {
|
|
3473
|
+
let transaction;
|
|
3474
|
+
if (transactionOrMessage instanceof Transaction) {
|
|
3475
|
+
transaction = transactionOrMessage;
|
|
3476
|
+
} else {
|
|
3477
|
+
transaction = Transaction.populate(transactionOrMessage);
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3423
3480
|
if (transaction.nonceInfo && signers) {
|
|
3424
3481
|
transaction.sign(...signers);
|
|
3425
3482
|
} else {
|
|
@@ -3453,7 +3510,8 @@ export class Connection {
|
|
|
3453
3510
|
}
|
|
3454
3511
|
}
|
|
3455
3512
|
|
|
3456
|
-
const
|
|
3513
|
+
const message = transaction._compile();
|
|
3514
|
+
const signData = message.serialize();
|
|
3457
3515
|
const wireTransaction = transaction._serialize(signData);
|
|
3458
3516
|
const encodedTransaction = wireTransaction.toString('base64');
|
|
3459
3517
|
const config: any = {
|
|
@@ -3461,6 +3519,19 @@ export class Connection {
|
|
|
3461
3519
|
commitment: this.commitment,
|
|
3462
3520
|
};
|
|
3463
3521
|
|
|
3522
|
+
if (includeAccounts) {
|
|
3523
|
+
const addresses = (
|
|
3524
|
+
Array.isArray(includeAccounts)
|
|
3525
|
+
? includeAccounts
|
|
3526
|
+
: message.nonProgramIds()
|
|
3527
|
+
).map(key => key.toBase58());
|
|
3528
|
+
|
|
3529
|
+
config['accounts'] = {
|
|
3530
|
+
encoding: 'base64',
|
|
3531
|
+
addresses,
|
|
3532
|
+
};
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3464
3535
|
if (signers) {
|
|
3465
3536
|
config.sigVerify = true;
|
|
3466
3537
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {Buffer} from 'buffer';
|
|
2
|
+
import * as BufferLayout from '@solana/buffer-layout';
|
|
3
|
+
import nacl from 'tweetnacl';
|
|
4
|
+
|
|
5
|
+
import {Keypair} from './keypair';
|
|
6
|
+
import {PublicKey} from './publickey';
|
|
7
|
+
import {TransactionInstruction} from './transaction';
|
|
8
|
+
import assert from './util/assert';
|
|
9
|
+
|
|
10
|
+
const PRIVATE_KEY_BYTES = 64;
|
|
11
|
+
const PUBLIC_KEY_BYTES = 32;
|
|
12
|
+
const SIGNATURE_BYTES = 64;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Params for creating an ed25519 instruction using a public key
|
|
16
|
+
*/
|
|
17
|
+
export type CreateEd25519InstructionWithPublicKeyParams = {
|
|
18
|
+
publicKey: Uint8Array;
|
|
19
|
+
message: Uint8Array;
|
|
20
|
+
signature: Uint8Array;
|
|
21
|
+
instructionIndex?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Params for creating an ed25519 instruction using a private key
|
|
26
|
+
*/
|
|
27
|
+
export type CreateEd25519InstructionWithPrivateKeyParams = {
|
|
28
|
+
privateKey: Uint8Array;
|
|
29
|
+
message: Uint8Array;
|
|
30
|
+
instructionIndex?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const ED25519_INSTRUCTION_LAYOUT = BufferLayout.struct([
|
|
34
|
+
BufferLayout.u8('numSignatures'),
|
|
35
|
+
BufferLayout.u8('padding'),
|
|
36
|
+
BufferLayout.u16('signatureOffset'),
|
|
37
|
+
BufferLayout.u16('signatureInstructionIndex'),
|
|
38
|
+
BufferLayout.u16('publicKeyOffset'),
|
|
39
|
+
BufferLayout.u16('publicKeyInstructionIndex'),
|
|
40
|
+
BufferLayout.u16('messageDataOffset'),
|
|
41
|
+
BufferLayout.u16('messageDataSize'),
|
|
42
|
+
BufferLayout.u16('messageInstructionIndex'),
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
export class Ed25519Program {
|
|
46
|
+
/**
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
constructor() {}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Public key that identifies the ed25519 program
|
|
53
|
+
*/
|
|
54
|
+
static programId: PublicKey = new PublicKey(
|
|
55
|
+
'Ed25519SigVerify111111111111111111111111111',
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create an ed25519 instruction with a public key and signature. The
|
|
60
|
+
* public key must be a buffer that is 32 bytes long, and the signature
|
|
61
|
+
* must be a buffer of 64 bytes.
|
|
62
|
+
*/
|
|
63
|
+
static createInstructionWithPublicKey(
|
|
64
|
+
params: CreateEd25519InstructionWithPublicKeyParams,
|
|
65
|
+
): TransactionInstruction {
|
|
66
|
+
const {publicKey, message, signature, instructionIndex} = params;
|
|
67
|
+
|
|
68
|
+
assert(
|
|
69
|
+
publicKey.length === PUBLIC_KEY_BYTES,
|
|
70
|
+
`Public Key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
assert(
|
|
74
|
+
signature.length === SIGNATURE_BYTES,
|
|
75
|
+
`Signature must be ${SIGNATURE_BYTES} bytes but received ${signature.length} bytes`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const publicKeyOffset = ED25519_INSTRUCTION_LAYOUT.span;
|
|
79
|
+
const signatureOffset = publicKeyOffset + publicKey.length;
|
|
80
|
+
const messageDataOffset = signatureOffset + signature.length;
|
|
81
|
+
const numSignatures = 1;
|
|
82
|
+
|
|
83
|
+
const instructionData = Buffer.alloc(messageDataOffset + message.length);
|
|
84
|
+
|
|
85
|
+
ED25519_INSTRUCTION_LAYOUT.encode(
|
|
86
|
+
{
|
|
87
|
+
numSignatures,
|
|
88
|
+
padding: 0,
|
|
89
|
+
signatureOffset,
|
|
90
|
+
signatureInstructionIndex: instructionIndex,
|
|
91
|
+
publicKeyOffset,
|
|
92
|
+
publicKeyInstructionIndex: instructionIndex,
|
|
93
|
+
messageDataOffset,
|
|
94
|
+
messageDataSize: message.length,
|
|
95
|
+
messageInstructionIndex: instructionIndex,
|
|
96
|
+
},
|
|
97
|
+
instructionData,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
instructionData.fill(publicKey, publicKeyOffset);
|
|
101
|
+
instructionData.fill(signature, signatureOffset);
|
|
102
|
+
instructionData.fill(message, messageDataOffset);
|
|
103
|
+
|
|
104
|
+
return new TransactionInstruction({
|
|
105
|
+
keys: [],
|
|
106
|
+
programId: Ed25519Program.programId,
|
|
107
|
+
data: instructionData,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create an ed25519 instruction with a private key. The private key
|
|
113
|
+
* must be a buffer that is 64 bytes long.
|
|
114
|
+
*/
|
|
115
|
+
static createInstructionWithPrivateKey(
|
|
116
|
+
params: CreateEd25519InstructionWithPrivateKeyParams,
|
|
117
|
+
): TransactionInstruction {
|
|
118
|
+
const {privateKey, message, instructionIndex} = params;
|
|
119
|
+
|
|
120
|
+
assert(
|
|
121
|
+
privateKey.length === PRIVATE_KEY_BYTES,
|
|
122
|
+
`Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${privateKey.length} bytes`,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const keypair = Keypair.fromSecretKey(privateKey);
|
|
127
|
+
const publicKey = keypair.publicKey.toBytes();
|
|
128
|
+
const signature = nacl.sign.detached(message, keypair.secretKey);
|
|
129
|
+
|
|
130
|
+
return this.createInstructionWithPublicKey({
|
|
131
|
+
publicKey,
|
|
132
|
+
message,
|
|
133
|
+
signature,
|
|
134
|
+
instructionIndex,
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw new Error(`Error creating instruction; ${error}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './bpf-loader-deprecated';
|
|
|
4
4
|
export * from './bpf-loader';
|
|
5
5
|
export * from './connection';
|
|
6
6
|
export * from './epoch-schedule';
|
|
7
|
+
export * from './ed25519-program';
|
|
7
8
|
export * from './fee-calculator';
|
|
8
9
|
export * from './keypair';
|
|
9
10
|
export * from './loader';
|
package/src/message.ts
CHANGED
|
@@ -65,11 +65,26 @@ export class Message {
|
|
|
65
65
|
recentBlockhash: Blockhash;
|
|
66
66
|
instructions: CompiledInstruction[];
|
|
67
67
|
|
|
68
|
+
private indexToProgramIds: Map<number, PublicKey> = new Map<
|
|
69
|
+
number,
|
|
70
|
+
PublicKey
|
|
71
|
+
>();
|
|
72
|
+
|
|
68
73
|
constructor(args: MessageArgs) {
|
|
69
74
|
this.header = args.header;
|
|
70
75
|
this.accountKeys = args.accountKeys.map(account => new PublicKey(account));
|
|
71
76
|
this.recentBlockhash = args.recentBlockhash;
|
|
72
77
|
this.instructions = args.instructions;
|
|
78
|
+
this.instructions.forEach(ix =>
|
|
79
|
+
this.indexToProgramIds.set(
|
|
80
|
+
ix.programIdIndex,
|
|
81
|
+
this.accountKeys[ix.programIdIndex],
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
isAccountSigner(index: number): boolean {
|
|
87
|
+
return index < this.header.numRequiredSignatures;
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
isAccountWritable(index: number): boolean {
|
|
@@ -83,6 +98,18 @@ export class Message {
|
|
|
83
98
|
);
|
|
84
99
|
}
|
|
85
100
|
|
|
101
|
+
isProgramId(index: number): boolean {
|
|
102
|
+
return this.indexToProgramIds.has(index);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
programIds(): PublicKey[] {
|
|
106
|
+
return [...this.indexToProgramIds.values()];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
nonProgramIds(): PublicKey[] {
|
|
110
|
+
return this.accountKeys.filter((_, index) => !this.isProgramId(index));
|
|
111
|
+
}
|
|
112
|
+
|
|
86
113
|
serialize(): Buffer {
|
|
87
114
|
const numKeys = this.accountKeys.length;
|
|
88
115
|
|
package/src/publickey.ts
CHANGED
|
@@ -12,7 +12,10 @@ import {toBuffer} from './util/to-buffer';
|
|
|
12
12
|
*/
|
|
13
13
|
export const MAX_SEED_LENGTH = 32;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Value to be converted into public key
|
|
17
|
+
*/
|
|
18
|
+
export type PublicKeyInitData =
|
|
16
19
|
| number
|
|
17
20
|
| string
|
|
18
21
|
| Buffer
|
|
@@ -20,7 +23,10 @@ type PublicKeyInitData =
|
|
|
20
23
|
| Array<number>
|
|
21
24
|
| PublicKeyData;
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
/**
|
|
27
|
+
* JSON object representation of PublicKey class
|
|
28
|
+
*/
|
|
29
|
+
export type PublicKeyData = {
|
|
24
30
|
/** @internal */
|
|
25
31
|
_bn: BN;
|
|
26
32
|
};
|
package/src/transaction.ts
CHANGED
|
@@ -106,7 +106,7 @@ export type SignaturePubkeyPair = {
|
|
|
106
106
|
* List of Transaction object fields that may be initialized at construction
|
|
107
107
|
*
|
|
108
108
|
*/
|
|
109
|
-
type TransactionCtorFields = {
|
|
109
|
+
export type TransactionCtorFields = {
|
|
110
110
|
/** A recent blockhash */
|
|
111
111
|
recentBlockhash?: Blockhash | null;
|
|
112
112
|
/** Optional nonce information used for offline nonce'd transactions */
|
|
@@ -120,7 +120,7 @@ type TransactionCtorFields = {
|
|
|
120
120
|
/**
|
|
121
121
|
* Nonce information to be used to build an offline Transaction.
|
|
122
122
|
*/
|
|
123
|
-
type NonceInformation = {
|
|
123
|
+
export type NonceInformation = {
|
|
124
124
|
/** The current blockhash stored in the nonce */
|
|
125
125
|
nonce: Blockhash;
|
|
126
126
|
/** AdvanceNonceAccount Instruction */
|
|
@@ -666,7 +666,10 @@ export class Transaction {
|
|
|
666
666
|
/**
|
|
667
667
|
* Populate Transaction object from message and signatures
|
|
668
668
|
*/
|
|
669
|
-
static populate(
|
|
669
|
+
static populate(
|
|
670
|
+
message: Message,
|
|
671
|
+
signatures: Array<string> = [],
|
|
672
|
+
): Transaction {
|
|
670
673
|
const transaction = new Transaction();
|
|
671
674
|
transaction.recentBlockhash = message.recentBlockhash;
|
|
672
675
|
if (message.header.numRequiredSignatures > 0) {
|
|
@@ -688,9 +691,10 @@ export class Transaction {
|
|
|
688
691
|
const pubkey = message.accountKeys[account];
|
|
689
692
|
return {
|
|
690
693
|
pubkey,
|
|
691
|
-
isSigner:
|
|
692
|
-
|
|
693
|
-
|
|
694
|
+
isSigner:
|
|
695
|
+
transaction.signatures.some(
|
|
696
|
+
keyObj => keyObj.publicKey.toString() === pubkey.toString(),
|
|
697
|
+
) || message.isAccountSigner(account),
|
|
694
698
|
isWritable: message.isAccountWritable(account),
|
|
695
699
|
};
|
|
696
700
|
});
|