@solana/rpc-graphql 2.0.0-experimental.ee4214c → 2.0.0-experimental.fbd3974

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.
Files changed (36) hide show
  1. package/README.md +1172 -30
  2. package/dist/index.browser.cjs +3141 -287
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +3141 -287
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.native.js +3141 -287
  7. package/dist/index.native.js.map +1 -1
  8. package/dist/index.node.cjs +3141 -287
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.js +3141 -287
  11. package/dist/index.node.js.map +1 -1
  12. package/dist/types/cache.d.ts.map +1 -0
  13. package/dist/types/context.d.ts +3 -2
  14. package/dist/types/context.d.ts.map +1 -0
  15. package/dist/types/index.d.ts.map +1 -0
  16. package/dist/types/rpc.d.ts.map +1 -0
  17. package/dist/types/schema/account/index.d.ts.map +1 -0
  18. package/dist/types/schema/account/query.d.ts +2 -2
  19. package/dist/types/schema/account/query.d.ts.map +1 -0
  20. package/dist/types/schema/account/types.d.ts.map +1 -0
  21. package/dist/types/schema/block/index.d.ts.map +1 -0
  22. package/dist/types/schema/block/query.d.ts +1 -1
  23. package/dist/types/schema/block/query.d.ts.map +1 -0
  24. package/dist/types/schema/block/types.d.ts.map +1 -0
  25. package/dist/types/schema/inputs.d.ts.map +1 -0
  26. package/dist/types/schema/picks.d.ts.map +1 -0
  27. package/dist/types/schema/program-accounts/index.d.ts.map +1 -0
  28. package/dist/types/schema/program-accounts/query.d.ts +2 -2
  29. package/dist/types/schema/program-accounts/query.d.ts.map +1 -0
  30. package/dist/types/schema/scalars.d.ts.map +1 -0
  31. package/dist/types/schema/transaction/index.d.ts.map +1 -0
  32. package/dist/types/schema/transaction/query.d.ts +1 -1
  33. package/dist/types/schema/transaction/query.d.ts.map +1 -0
  34. package/dist/types/schema/transaction/types.d.ts.map +1 -0
  35. package/package.json +14 -13
  36. package/dist/types/schema/program-accounts/types.d.ts +0 -3
package/README.md CHANGED
@@ -3,61 +3,1203 @@
3
3
  This package defines a GraphQL client resolver built on top of the
4
4
  [Solana JSON-RPC](https://docs.solana.com/api/http).
5
5
 
6
- # Solana & GraphQL
7
-
8
6
  GraphQL is a query language for your API, and a server-side runtime for
9
7
  executing queries using a type system you define for your data.
10
8
 
11
9
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/GraphQL_Logo.svg/1024px-GraphQL_Logo.svg.png?20161105194737" alt="graphql-icon" width="24" align="center"/> [**GraphQL**](https://graphql.org/learn/)
12
10
 
13
- This library attempts to define a type system for Solana. With the proper
14
- type system, developers can take advantage of the best features of GraphQL
11
+ This library attempts to define a type schema for Solana. With the proper
12
+ type schema, developers can take advantage of the best features of GraphQL
15
13
  to make interacting with Solana via RPC smoother, faster, more reliable,
16
14
  and involve less code.
17
15
 
18
- ## Design
16
+ # Design
17
+
18
+ On-chain data can be categorized into three main types:
19
+
20
+ - Accounts
21
+ - Transactions
22
+ - Blocks
23
+
24
+ These types encompass everything that can be queried from the Solana ledger.
25
+
26
+ The Solana RPC provides a parsing method known as `jsonParsed` for supported
27
+ types, such as accounts and transaction instructions.
28
+
29
+ This library leverages GraphQL **interfaces** for each of these types paired
30
+ with specific GraphQL types for each `jsonParsed` object. This allows for
31
+ powerful querying of `jsonParsed` data, including nested and chained queries!
32
+
33
+ ## Setting up a GraphQL RPC Client
34
+
35
+ Initializing an RPC-GraphQL using `@solana/rpc-graphql` requires an RPC client,
36
+ either built using `@solana/web3.js` or it's child libraries `@solana/rpc-core`
37
+ and `@solana/rpc-transport`.
38
+
39
+ ```typescript
40
+ import { createSolanaRpc, createDefaultRpcTransport } from '@solana/web3.js';
41
+ import { createRpcGraphQL } from '@solana/rpc-graphql';
42
+
43
+ // Set up an HTTP transport
44
+ const transport = createDefaultRpcTransport({ url: 'http://127.0.0.1:8899' });
45
+
46
+ // Create the RPC client
47
+ const rpc = createSolanaRpc({ transport });
48
+
49
+ // Create the RPC-GraphQL client
50
+ const rpcGraphQL = createRpcGraphQL(rpc);
51
+ ```
52
+
53
+ The `RpcGraphQL` type supports one method `query(..)` which accepts a string
54
+ query source and an optional `variableValues` parameter - which is an object
55
+ containing any variables to pipe into the query string.
56
+
57
+ You can define queries with hard-coded parameters.
58
+
59
+ ```typescript
60
+ const source = `
61
+ query myQuery {
62
+ account(address: "AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca") {
63
+ lamports
64
+ }
65
+ }
66
+ `;
67
+
68
+ const result = await rpcGraphQL.query(source);
69
+ ```
70
+
71
+ ```
72
+ data: {
73
+ account: {
74
+ lamports: 10290815n,
75
+ },
76
+ }
77
+ ```
78
+
79
+ You can also pass the variable values.
80
+
81
+ ```typescript
82
+ const source = `
83
+ query myQuery($address: String!) {
84
+ account(address: $address) {
85
+ lamports
86
+ }
87
+ }
88
+ `;
89
+
90
+ const variableValues = {
91
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
92
+ };
93
+
94
+ const result = await rpcGraphQL.query(source, variableValues);
95
+ ```
96
+
97
+ ```
98
+ data: {
99
+ account: {
100
+ lamports: 10290815n,
101
+ },
102
+ }
103
+ ```
104
+
105
+ Queries with variable values can also be re-used!
106
+
107
+ ```typescript
108
+ const source = `
109
+ query myQuery($address: String!) {
110
+ account(address: $address) {
111
+ lamports
112
+ }
113
+ }
114
+ `;
115
+
116
+ const lamportsAccountA = await rpcGraphQL.query(source, {
117
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
118
+ });
119
+
120
+ const lamportsAccountB = await rpcGraphQL.query(source, {
121
+ address: 'CcYNb7WqpjaMrNr7B1mapaNfWctZRH7LyAjWRLBGt1Fk',
122
+ });
123
+ ```
124
+
125
+ ## Querying Accounts
126
+
127
+ The `Account` interface contains common fields across all accounts.
128
+
129
+ `src/schema/account/types.ts: AccountInterface`
130
+
131
+ ```graphql
132
+ interface Account {
133
+ encoding: String,
134
+ executable: Boolean,
135
+ lamports: BigInt,
136
+ owner: Account, # Interface
137
+ rentEpoch: BigInt,
138
+ }
139
+ ```
140
+
141
+ Any account can be queried by these fields without specifying the specific
142
+ account type.
143
+
144
+ ```typescript
145
+ const source = `
146
+ query myQuery($address: String!) {
147
+ account(address: $address) {
148
+ executable
149
+ lamports
150
+ rentEpoch
151
+ }
152
+ }
153
+ `;
154
+
155
+ const variableValues = {
156
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
157
+ };
158
+
159
+ const result = await rpcGraphQL.query(source, variableValues);
160
+ ```
161
+
162
+ ```
163
+ data: {
164
+ account: {
165
+ executable: false,
166
+ lamports: 10290815n,
167
+ rentEpoch: 0n,
168
+ },
169
+ }
170
+ ```
171
+
172
+ ### Specific Account Types
173
+
174
+ Each `jsonParsed` account type has its own GraphQL type that can be used in a
175
+ GraphQL query.
176
+
177
+ - `AccountBase58`: A Solana account with base58 encoded data
178
+ - `AccountBase64`: A Solana account with base64 encoded data
179
+ - `AccountBase64Zstd`: A Solana account with base64 encoded data compressed with zstd
180
+ - `NonceAccount`: A nonce account
181
+ - `LookupTableAccount`: An address lookup table account
182
+ - `MintAccount`: An SPL mint
183
+ - `TokenAccount`: An SPL token account
184
+ - `StakeAccount`: A stake account
185
+ - `VoteAccount`: A vote account
186
+
187
+ You can choose how to handle querying of specific account types. For example,
188
+ you might _only_ want specifically any account that matches `MintAccount`.
189
+
190
+ ```typescript
191
+ const maybeMintAddresses = [
192
+ 'J7iup799j5BVjKXACZycYef7WQ4x1wfzhUsc5v357yWQ',
193
+ 'JAbWqZ7S2c6jomQr8ofAYBo257bE1QJtHwbX1yWc2osZ',
194
+ '2AQ4CSNu6zNUZsUq4aLNUSjyrLv4qFFXQuKs5RTHbg2Y',
195
+ 'EVW3CoyogapBfQxBFFEKGMM1bn3JyoFiqkAJdw3FHX1b',
196
+ ];
197
+
198
+ const mintAccounts = [];
199
+
200
+ const source = `
201
+ query myQuery($address: String!) {
202
+ account(address: $address) {
203
+ ... on MintAccount {
204
+ data {
205
+ parsed {
206
+ info {
207
+ decimals
208
+ isInitialized
209
+ mintAuthority
210
+ supply
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ `;
218
+
219
+ for (const address of maybeMintAddresses) {
220
+ const result = await rpcGraphQL.query(source, { address });
221
+ if (result != null) {
222
+ const {
223
+ data: {
224
+ account: {
225
+ data: {
226
+ parsed: { info: mintInfo },
227
+ },
228
+ },
229
+ },
230
+ } = result;
231
+ mintAccounts.push(mintInfo);
232
+ }
233
+ }
234
+ ```
235
+
236
+ Maybe you want to handle both mints _and_ token accounts.
237
+
238
+ ```typescript
239
+ const mintOrTokenAccountAddresses = [
240
+ 'J7iup799j5BVjKXACZycYef7WQ4x1wfzhUsc5v357yWQ',
241
+ 'JAbWqZ7S2c6jomQr8ofAYBo257bE1QJtHwbX1yWc2osZ',
242
+ '2AQ4CSNu6zNUZsUq4aLNUSjyrLv4qFFXQuKs5RTHbg2Y',
243
+ 'EVW3CoyogapBfQxBFFEKGMM1bn3JyoFiqkAJdw3FHX1b',
244
+ ];
245
+
246
+ const mintAccounts = [];
247
+ const tokenAccounts = [];
248
+
249
+ const source = `
250
+ query myQuery($address: String!) {
251
+ account(address: $address) {
252
+ ... on MintAccount {
253
+ data {
254
+ parsed {
255
+ info {
256
+ decimals
257
+ isInitialized
258
+ supply
259
+ }
260
+ type
261
+ }
262
+ }
263
+ }
264
+ ... on TokenAccount {
265
+ data {
266
+ parsed {
267
+ info {
268
+ isNative
269
+ mint
270
+ state
271
+ }
272
+ type
273
+ }
274
+ }
275
+ }
276
+ }
277
+ }
278
+ `;
279
+
280
+ for (const address of mintOrTokenAccountAddresses) {
281
+ const result = await rpcGraphQL.query(source, { address });
282
+ if (result != null) {
283
+ const {
284
+ data: {
285
+ account: {
286
+ data: {
287
+ parsed: {
288
+ info: accountParsedInfo,
289
+ type: accountType,
290
+ }
291
+ }
292
+ }
293
+ }
294
+ } = result;
295
+ if (accountType === 'mint') {
296
+ mintAccounts.push(accountParsedInfo)
297
+ } else {
298
+ tokenAccounts.push(accountParsedInfo)
299
+ }
300
+ }
301
+ }
302
+ ```
303
+
304
+ Querying accounts by their encoded data (`base58`, `base64`, `base64+zstd`) is
305
+ still fully supported.
306
+
307
+ ```typescript
308
+ const source = `
309
+ query myQuery($address: String!, $encoding: AccountEncoding) {
310
+ account(address: $address, encoding: $encoding) {
311
+ ... on AccountBase64 {
312
+ data
313
+ }
314
+ }
315
+ }
316
+ `;
317
+
318
+ const variableValues = {
319
+ address: 'CcYNb7WqpjaMrNr7B1mapaNfWctZRH7LyAjWRLBGt1Fk',
320
+ encoding: 'base64',
321
+ };
322
+
323
+ const result = await rpcGraphQL.query(source, variableValues);
324
+ ```
325
+
326
+ ```
327
+ data: {
328
+ account: {
329
+ data: 'dGVzdCBkYXRh',
330
+ },
331
+ }
332
+ ```
333
+
334
+ ### Nested Account Queries
335
+
336
+ Notice the `owner` field of the `Account` interface is also an `Account`
337
+ interface. This powers nested queries against the `owner` field of an account.
338
+
339
+ ```typescript
340
+ const source = `
341
+ query myQuery($address: String!) {
342
+ account(address: $address) {
343
+ address
344
+ owner {
345
+ address
346
+ executable
347
+ lamports
348
+ }
349
+ }
350
+ }
351
+ `;
352
+
353
+ const variableValues = {
354
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
355
+ };
356
+
357
+ const result = await rpcGraphQL.query(source, variableValues);
358
+ ```
359
+
360
+ ```
361
+ data: {
362
+ account: {
363
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
364
+ owner: {
365
+ address: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
366
+ executable: true,
367
+ lamports: 10290815n,
368
+ },
369
+ },
370
+ }
371
+ ```
372
+
373
+ As you can see, simply defining a nested query with RPC-GraphQL will augment
374
+ the multiple RPC calls and parsing code required to gather the necessary
375
+ information!
376
+
377
+ You can nest queries as far as you want!
378
+
379
+ ```typescript
380
+ const source = `
381
+ query myQuery($address: String!) {
382
+ account(address: $address) {
383
+ address
384
+ owner {
385
+ address
386
+ owner {
387
+ address
388
+ owner {
389
+ address
390
+ }
391
+ }
392
+ }
393
+ }
394
+ }
395
+ `;
396
+
397
+ const variableValues = {
398
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
399
+ };
400
+
401
+ const result = await rpcGraphQL.query(source, variableValues);
402
+ ```
403
+
404
+ ```
405
+ data: {
406
+ account: {
407
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
408
+ owner: {
409
+ address: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
410
+ owner: {
411
+ address: 'BPFLoader2111111111111111111111111111111111',
412
+ owner: {
413
+ address: 'NativeLoader1111111111111111111111111111111',
414
+ },
415
+ },
416
+ },
417
+ },
418
+ }
419
+ ```
420
+
421
+ Nested queries can also be applied to specific account types.
422
+
423
+ ```typescript
424
+ const source = `
425
+ query myQuery($address: String!) {
426
+ account(address: $address) {
427
+ ... on MintAccount {
428
+ address
429
+ data {
430
+ parsed {
431
+ info {
432
+ mintAuthority {
433
+ address
434
+ lamports
435
+ }
436
+ }
437
+ }
438
+ }
439
+ }
440
+ }
441
+ }
442
+ `;
443
+
444
+ const variableValues = {
445
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
446
+ };
447
+
448
+ const result = await rpcGraphQL.query(source, variableValues);
449
+ ```
450
+
451
+ ```
452
+ data: {
453
+ account: {
454
+ address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca',
455
+ data: {
456
+ parsed: {
457
+ info: {
458
+ mintAuthority: {
459
+ address: 'DpfJkNonoVB3sor9H9ceajhex4XHVPrDAGAq2ahdG4JZ',
460
+ lamports: 10290815n,
461
+ }
462
+ }
463
+ }
464
+ },
465
+ },
466
+ }
467
+ ```
468
+
469
+ ## Querying Program Accounts
470
+
471
+ A very common way to query Solana accounts from an RPC is to request all of
472
+ the accounts owned by a particular program.
473
+
474
+ With RPC-GraphQL, querying program-owned accounts is a list-based extension of
475
+ the account query defined previously. This means program accounts queries will
476
+ return a list of objects implementing the `Account` interface.
477
+
478
+ Setting up the query is very similar to the `account` query.
479
+
480
+ ```typescript
481
+ const source = `
482
+ query myQuery($programAddress: String!) {
483
+ programAccounts(programAddress: $address) {
484
+ executable
485
+ lamports
486
+ rentEpoch
487
+ }
488
+ }
489
+ `;
490
+
491
+ const variableValues = {
492
+ programAddress: 'AmtpVzo6H6qQCP9dH9wfu5hfa8kKaAFpTJ4aamPYR6V6',
493
+ };
494
+
495
+ const result = await rpcGraphQL.query(source, variableValues);
496
+ ```
497
+
498
+ ```
499
+ data: {
500
+ programAccounts: [
501
+ {
502
+ executable: false,
503
+ lamports: 10290815n,
504
+ rentEpoch: 0n,
505
+ },
506
+ {
507
+ executable: false,
508
+ lamports: 10290815n,
509
+ rentEpoch: 0n,
510
+ }
511
+ ]
512
+ }
513
+ ```
514
+
515
+ ### Specific Program Account Types
516
+
517
+ Although specific parsed account types are directly tied to the program which
518
+ owns them, it's still possible to handle various specific account types within
519
+ the same program accounts response.
520
+
521
+ ```typescript
522
+ const source = `
523
+ query myQuery($programAddress: String!) {
524
+ programAccounts(programAddress: $address) {
525
+ ... on MintAccount {
526
+ data {
527
+ parsed {
528
+ info {
529
+ decimals
530
+ isInitialized
531
+ mintAuthority
532
+ supply
533
+ }
534
+ }
535
+ }
536
+ }
537
+ ... on TokenAccount {
538
+ data {
539
+ parsed {
540
+ info {
541
+ isNative
542
+ mint
543
+ owner
544
+ state
545
+ }
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ `;
552
+
553
+ const variableValues = {
554
+ programAddress: 'AmtpVzo6H6qQCP9dH9wfu5hfa8kKaAFpTJ4aamPYR6V6',
555
+ };
556
+
557
+ const result = await rpcGraphQL.query(source, variableValues);
558
+
559
+ const { mints, tokenAccounts } = result.data.programAccounts.reduce(
560
+ (acc: { mints: any[]; tokenAccounts: any[] }, account) => {
561
+ const {
562
+ data: {
563
+ parsed: {
564
+ info: accountParsedInfo,
565
+ type: accountType,
566
+ }
567
+ }
568
+ } = account;
569
+ if (accountType === "mint") {
570
+ acc.mints.push(accountParsedInfo);
571
+ } else {
572
+ acc.tokenAccounts.push(accountParsedInfo);
573
+ }
574
+ return acc;
575
+ },
576
+ { mints: [], tokenAccounts: [] }
577
+ );
578
+ ```
579
+
580
+ Account data encoding in `base58`, `base64`, and `base64+zstd` is also
581
+ supported, as well as `dataSlice` and `filter`!
582
+
583
+ ```typescript
584
+ const source = `
585
+ query myQuery(
586
+ $programAddress: String!,
587
+ $commitment: Commitment,
588
+ $dataSlice: DataSlice,
589
+ $encoding: AccountEncoding,
590
+ ) {
591
+ programAccounts(
592
+ programAddress: $programAddress,
593
+ commitment: $commitment,
594
+ dataSlice: $dataSlice,
595
+ encoding: $encoding,
596
+ ) {
597
+ ... on AccountBase64 {
598
+ data
599
+ }
600
+ }
601
+ }
602
+ `;
603
+
604
+ const variableValues = {
605
+ programAddress: 'DXngmJfjurhnAwbMPgpUGPH6qNvetCKRJ6PiD4ag4PTj',
606
+ commitment: 'confirmed',
607
+ dataSlice: {
608
+ length: 5,
609
+ offset: 0,
610
+ },
611
+ encoding: 'base64',
612
+ };
613
+
614
+ const result = await rpcGraphQL.query(source, variableValues);
615
+ ```
616
+
617
+ ```
618
+ data: {
619
+ programAccounts: [
620
+ {
621
+ data: 'dGVzdCA=',
622
+ },
623
+ ],
624
+ }
625
+ ```
626
+
627
+ ### Nested Program Account Queries
628
+
629
+ Querying program accounts and applying nested queries to the objects within the
630
+ response list is an area where RPC-GraphQL really shines.
631
+
632
+ Consider an example where we want to get the **sum** of every lamports balance
633
+ of every **owner of the owner** of each token account, while discarding any
634
+ mint accounts.
635
+
636
+ ```typescript
637
+ const source = `
638
+ query getLamportsOfOwnersOfOwnersOfTokenAccounts {
639
+ programAccounts(programAddress: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") {
640
+ ... on TokenAccount {
641
+ data {
642
+ parsed {
643
+ info {
644
+ owner {
645
+ owner {
646
+ lamports
647
+ }
648
+ }
649
+ }
650
+ }
651
+ }
652
+ }
653
+ }
654
+ }
655
+ `;
656
+
657
+ const result = await rpcGraphQL.query(source);
658
+
659
+ const sumOfAllLamportsOfOwnersOfOwnersOfTokenAccounts = result.data
660
+ .map(o => o.account.data.parsed.info.owner.owner.lamports)
661
+ .reduce((acc, lamports) => acc + lamports, 0);
662
+ ```
663
+
664
+ ## Querying Transactions
665
+
666
+ The `Transaction` interface contains common fields across all transactions.
667
+
668
+ `src/schema/transaction/types.ts: TransactionInterface`
669
+
670
+ ```graphql
671
+ interface Transaction {
672
+ blocktime: BigInt,
673
+ encoding: String,
674
+ meta: TransactionMeta, # Interface
675
+ slot: BigInt,
676
+ }
677
+ ```
678
+
679
+ Notice the `TransactionMetaInterface` type present in the transaction
680
+ interface.
681
+
682
+ ```graphql
683
+ interface TransactionMeta {
684
+ computeUnitsConsumed: BigInt,
685
+ err: String,
686
+ fee: BigInt,
687
+ format: String,
688
+ loadedAddresses: TransactionMetaLoadedAddresses,
689
+ logMessages: [String],
690
+ postBalances: [BigInt],
691
+ postTokenBalances: [TokenBalance],
692
+ preBalances: [BigInt],
693
+ preTokenBalances: [TokenBalance],
694
+ returnData: ReturnData,
695
+ rewards: [Reward],
696
+ status: TransactionStatus,
697
+ }
698
+ ```
699
+
700
+ The `TransactionMeta` interface is required since the field `innerInstructions`
701
+ will depend on the encoding level requested for the transaction. This also
702
+ applies to the actual `transaction` object itself.
703
+
704
+ Similar to account types, any transaction can be queried by these fields
705
+ without specifying the specific transaction type or the transaction meta
706
+ type.
707
+
708
+ ```typescript
709
+ const source = `
710
+ query myQuery($signature: String!, $commitment: Commitment) {
711
+ transaction(signature: $signature, commitment: $commitment) {
712
+ blockTime
713
+ meta {
714
+ computeUnitsConsumed
715
+ logMessages
716
+ }
717
+ slot
718
+ }
719
+ }
720
+ `;
721
+
722
+ const variableValues = {
723
+ signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC',
724
+ commitment: 'confirmed',
725
+ };
726
+
727
+ const result = await rpcGraphQL.query(source, variableValues);
728
+ ```
729
+
730
+ ```
731
+ data: {
732
+ transaction: {
733
+ blockTime: 230860412n,
734
+ meta: {
735
+ computeUnitsConsumed: 120000n,
736
+ logMessages: [
737
+ "Program 8tfDNiaEyrV6Q1U4DEXrEigs9DoDtkugzFbybENEbCDz invoke [1]",
738
+ "Program 8tfDNiaEyrV6Q1U4DEXrEigs9DoDtkugzFbybENEbCDz consumed 2164 of 452155 compute units",
739
+ "Program 8tfDNiaEyrV6Q1U4DEXrEigs9DoDtkugzFbybENEbCDz success",
740
+ "Program ComputeBudget111111111111111111111111111111 invoke [1]",
741
+ "Program ComputeBudget111111111111111111111111111111 success"
742
+ ]
743
+ },
744
+ slot: 230860693n,
745
+ },
746
+ }
747
+ ```
748
+
749
+ ### Specific Transaction Types
750
+
751
+ Each `jsonParsed` instruction type has its own GraphQL type that can be used in
752
+ a GraphQL transaction query.
753
+
754
+ Instructions for the following programs are supported.
755
+
756
+ - Address Lookup Table
757
+ - BPF Loader
758
+ - BPF Upgradeable Loader
759
+ - Stake
760
+ - SPL Associated Token
761
+ - SPL Memo
762
+ - SPL Token
763
+ - System
764
+ - Vote
765
+
766
+ Note at this time Token 2022 extensions are not yet supported.
767
+
768
+ Similar to accounts, transactions with encoded data are also supported.
769
+
770
+ - `TransactionBase58`: A Solana transaction with base58 encoded data
771
+ - `TransactionBase64`: A Solana transaction with base64 encoded data
772
+ - `TransactionJson`: A Solana transaction with JSON data
773
+
774
+ Specific instruction types can be used in the transaction's instructions. The
775
+ default instruction if it cannot be parsed using `jsonParsed` is the JSON
776
+ version dubbed `PartiallyDecodedInstruction`.
777
+
778
+ ```typescript
779
+ const source = `
780
+ query myQuery($signature: String!, $commitment: Commitment) {
781
+ transaction(signature: $signature, commitment: $commitment) {
782
+ ... on TransactionJsonParsed {
783
+ transaction {
784
+ message {
785
+ ... on TransactionMessageParsed {
786
+ accountKeys {
787
+ pubkey
788
+ signer
789
+ source
790
+ writable
791
+ }
792
+ instructions {
793
+ ... on PartiallyDecodedInstruction {
794
+ accounts
795
+ data
796
+ programId
797
+ }
798
+ }
799
+ }
800
+ }
801
+ }
802
+ }
803
+ }
804
+ }
805
+ `;
806
+
807
+ const variableValues = {
808
+ signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC',
809
+ commitment: 'confirmed',
810
+ };
811
+
812
+ const result = await rpcGraphQL.query(source, variableValues);
813
+ ```
19
814
 
20
- ⚠️ **In Development:** The API's query/schema structure may change as the API
21
- matures.
815
+ ```
816
+ data: {
817
+ transaction: {
818
+ transaction: {
819
+ message: {
820
+ accountKeys: [
821
+ {
822
+ pubkey: '81EBmTWaMkFqW6LPNPfU2478nJkrhCLuiFUPSdvQKQj7',
823
+ signer: false,
824
+ source: 'transaction',
825
+ writable: true,
826
+ },
827
+ {
828
+ pubkey: 'G6TmQyEoxbUzdyncwxVN9GgfALpYErHSkXZeqJj7fwFz',
829
+ signer: true,
830
+ source: 'transaction',
831
+ writable: true,
832
+ },
833
+ ],
834
+ instructions: [
835
+ {
836
+ accounts: [
837
+ '81EBmTWaMkFqW6LPNPfU2478nJkrhCLuiFUPSdvQKQj7',
838
+ 'G6TmQyEoxbUzdyncwxVN9GgfALpYErHSkXZeqJj7fwFz'
839
+ ]
840
+ data: 'WzIsIDU0LCA5LCAgNzYsIDM1LCA2NCwgOCwgOCwgNCwgMywgMiwgNV0=',
841
+ programId: 'EksBYH1iSR8farQc9X26pYrXotj1D2JjXGuj8uM8xMcb',
842
+ }
843
+ ]
844
+ },
845
+ },
846
+ },
847
+ }
848
+ ```
22
849
 
23
- With the exception of many familiar RPC methods for obtaining information about
24
- a validator or cluster, majority of Solana data required by various
25
- applications revolves around two components:
850
+ However, whenever JSON-parseable instructions are present in the list of
851
+ instructions, they can be queried using specific instruction types.
26
852
 
27
- - Accounts
28
- - Blocks
853
+ ```typescript
854
+ const source = `
855
+ query myQuery($signature: String!, $commitment: Commitment) {
856
+ transaction(signature: $signature, commitment: $commitment) {
857
+ ... on TransactionJsonParsed {
858
+ transaction {
859
+ message {
860
+ ... on TransactionMessageParsed {
861
+ instructions {
862
+ ... on CreateAccountInstruction {
863
+ parsed {
864
+ info {
865
+ lamports
866
+ space
867
+ }
868
+ program
869
+ }
870
+ }
871
+ }
872
+ }
873
+ }
874
+ }
875
+ }
876
+ }
877
+ }
878
+ `;
29
879
 
30
- One can add a third component found within a block:
880
+ const variableValues = {
881
+ signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC',
882
+ commitment: 'confirmed',
883
+ };
884
+
885
+ const result = await rpcGraphQL.query(source, variableValues);
886
+ ```
31
887
 
32
- - Transactions
888
+ ```
889
+ data: {
890
+ transaction: {
891
+ transaction: {
892
+ message: {
893
+ instructions: [
894
+ {
895
+ parsed: {
896
+ info: {
897
+ lamports: 890880n,
898
+ space: 0n,
899
+ },
900
+ program: 'system',
901
+ },
902
+ }
903
+ ]
904
+ },
905
+ },
906
+ },
907
+ }
908
+ ```
33
909
 
34
- With these three main components in mind, consider a GraphQL type system that
35
- revolves around accounts, blocks, and transactions.
910
+ Querying transactions by their encoded data (`base58`, `base64`, `json`) is
911
+ still fully supported.
36
912
 
37
- ### Types
913
+ ```typescript
914
+ const source = `
915
+ query myQuery(
916
+ $signature: String!,
917
+ $commitment: Commitment,
918
+ $encoding: TransactionEncoding!,
919
+ ) {
920
+ transaction(
921
+ signature: $signature,
922
+ commitment: $commitment,
923
+ encoding: $encoding,
924
+ ) {
925
+ ... on TransactionBase64 {
926
+ transaction
927
+ }
928
+ }
929
+ }
930
+ `;
38
931
 
39
- Coming soon!
932
+ const variableValues = {
933
+ signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC',
934
+ commitment: 'confirmed',
935
+ encoding: 'base64',
936
+ };
937
+
938
+ const result = await rpcGraphQL.query(source, variableValues);
939
+ ```
40
940
 
41
- #### Account
941
+ ```
942
+ data: {
943
+ transaction: {
944
+ transaction: 'WzIsIDU0LCA5LCAgNzYsIDM1LCA2NCwgOCwgOCwgNCwgMywgMiwgNV0=',
945
+ },
946
+ }
947
+ ```
42
948
 
43
- Coming soon!
949
+ ### Nested Transaction Queries
44
950
 
45
- ### Queries
951
+ Since transactions have a relatively large number of data points, they are
952
+ particularly useful for nested queries!
46
953
 
47
- Coming soon!
954
+ Similar to nested querying accounts, it's possible to nest queries inside your
955
+ transaction queries to look up other objects, such as accounts, as they appear
956
+ in the transaction response.
48
957
 
49
- #### Accounts
958
+ ```typescript
959
+ const source = `
960
+ query myQuery($signature: String!, $commitment: Commitment) {
961
+ transaction(signature: $signature, commitment: $commitment) {
962
+ ... on TransactionJsonParsed {
963
+ transaction {
964
+ message {
965
+ ... on TransactionMessageParsed {
966
+ instructions {
967
+ ... on SplTokenTransferInstruction {
968
+ parsed {
969
+ info {
970
+ amount
971
+ authority {
972
+ address
973
+ lamports
974
+ }
975
+ destination {
976
+ ... on TokenAccount {
977
+ data {
978
+ parsed {
979
+ info {
980
+ address
981
+ mint {
982
+ ... on MintAccount {
983
+ data {
984
+ parsed {
985
+ info {
986
+ address
987
+ decimals
988
+ }
989
+ }
990
+ }
991
+ }
992
+ }
993
+ owner {
994
+ address
995
+ lamports
996
+ }
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ source {
1003
+ ... on TokenAccount {
1004
+ data {
1005
+ parsed {
1006
+ info {
1007
+ address
1008
+ mint {
1009
+ ... on MintAccount {
1010
+ data {
1011
+ parsed {
1012
+ info {
1013
+ address
1014
+ decimals
1015
+ }
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ owner {
1021
+ address
1022
+ lamports
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+ }
1029
+ }
1030
+ program
1031
+ }
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ `;
50
1041
 
51
- Coming soon!
1042
+ const variableValues = {
1043
+ signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC',
1044
+ commitment: 'confirmed',
1045
+ };
1046
+
1047
+ const result = await rpcGraphQL.query(source, variableValues);
1048
+ ```
52
1049
 
53
- #### Program Accounts
1050
+ ```
1051
+ data: {
1052
+ transaction: {
1053
+ transaction: {
1054
+ message: {
1055
+ instructions: [
1056
+ {
1057
+ parsed: {
1058
+ info: {
1059
+ amount: '50',
1060
+ authority: {
1061
+ address: 'AHPPMhzDQix9sKULBqeaQ5BUZgrKdz8tg6DzPxsofB12',
1062
+ lamports: 890880n,
1063
+ },
1064
+ destination: {
1065
+ data: {
1066
+ parsed: {
1067
+ info: {
1068
+ address: '2W8mUY75zxqwAcpirn75r3Cc7TStMirFyHwKqo13fmB1',
1069
+ mint: data: {
1070
+ parsed: {
1071
+ info: {
1072
+ address: '8poKMotB2cEYVv5sbjrdyssASZj1vwYCe7GJFeXo2QP7',
1073
+ decimals: 6,
1074
+ }
1075
+ }
1076
+ },
1077
+ owner: {
1078
+ address: '7tRxJ2znbTFpwW9XaMMiDsXDudoPEUXRcpDpm8qjWgAZ',
1079
+ lamports: 890880n,
1080
+ },
1081
+ }
1082
+ }
1083
+ }
1084
+ },
1085
+ source: {
1086
+ data: {
1087
+ parsed: {
1088
+ info: {
1089
+ address: 'BqFCPqXUm4cq6jaZZx1TDTvUR1wdEuNNwAHBEVR6mJhM',
1090
+ mint: data: {
1091
+ parsed: {
1092
+ info: {
1093
+ address: '8poKMotB2cEYVv5sbjrdyssASZj1vwYCe7GJFeXo2QP7',
1094
+ decimals: 6,
1095
+ }
1096
+ }
1097
+ },
1098
+ owner: {
1099
+ address: '3dPmVLMD7PC5faZNyJUH9WFrUxAsbjydJfoozwmR1wDG',
1100
+ lamports: e890880n,
1101
+ },
1102
+ }
1103
+ }
1104
+ }
1105
+ },
1106
+ },
1107
+ program: 'spl-token',
1108
+ },
1109
+ }
1110
+ ]
1111
+ },
1112
+ },
1113
+ },
1114
+ }
1115
+ ```
54
1116
 
55
- Coming soon!
1117
+ ## Querying Blocks
56
1118
 
57
- #### Blocks
1119
+ Querying blocks is very similar to querying transactions, since a block
1120
+ contains a list of transactions. There's a bit more data at the highest level
1121
+ for a block, but you can query the list of transactions using a block query and
1122
+ transaction types in the same fashion you can query the lsit of accounts using
1123
+ a program accounts query and account types.
58
1124
 
59
- Coming soon!
1125
+ ```typescript
1126
+ const source = `
1127
+ query myQuery($slot: BigInt!, $commitment: Commitment) {
1128
+ block(slot: $slot, commitment: $commitment) {
1129
+ blockHeight
1130
+ blockhash
1131
+ parentSlot
1132
+ rewards {
1133
+ //
1134
+ }
1135
+ transactions {
1136
+ ... on TransactionJsonParsed {
1137
+ transaction {
1138
+ message {
1139
+ ... on TransactionMessageParsed {
1140
+ instructions {
1141
+ ... on CreateAccountInstruction {
1142
+ parsed {
1143
+ info {
1144
+ lamports
1145
+ space
1146
+ }
1147
+ program
1148
+ }
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+ }
1158
+ `;
60
1159
 
61
- #### Transactions
1160
+ const variableValues = {
1161
+ slot: 43596n,
1162
+ commitment: 'confirmed',
1163
+ };
1164
+
1165
+ const result = await rpcGraphQL.query(source, variableValues);
1166
+ ```
62
1167
 
63
- Coming soon!
1168
+ ```
1169
+ data: {
1170
+ block: {
1171
+ blockHeight: 196758578n,
1172
+ blockhash: 'BqFCPqXUm4cq6jaZZx1TDTvUR1wdEuNNwAHBEVR6mJhM',
1173
+ parentSlot: 230862408n,
1174
+ rewards: [
1175
+ {
1176
+ commission: 0.05,
1177
+ lamports: 58578n,
1178
+ rewardType: 'staking',
1179
+ },
1180
+ {
1181
+ commission: 0.05,
1182
+ lamports: 58578n,
1183
+ rewardType: 'staking',
1184
+ }
1185
+ ],
1186
+ transactions: [
1187
+ {
1188
+ message: {
1189
+ instructions: [
1190
+ {
1191
+ parsed: {
1192
+ info: {
1193
+ lamports: 890880n,
1194
+ space: 0n,
1195
+ },
1196
+ program: 'system',
1197
+ },
1198
+ }
1199
+ ]
1200
+ },
1201
+ }
1202
+ ],
1203
+ },
1204
+ }
1205
+ ```