@solana/rpc-graphql 2.0.0-experimental.eb5fd16 → 2.0.0-experimental.f46b34c

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