|
1 | | -# PolkadotClient |
| 1 | +# Top-level client |
2 | 2 |
|
3 | 3 | `PolkadotClient` interface shapes the top-level API for `polkadot-api`. Once we get a client using `createClient` function, we'll find the following: |
4 | 4 |
|
| 5 | +## Create a client |
| 6 | + |
| 7 | +In order to create a client, you only need to have a [provider](/providers). |
| 8 | +Optionally, you can pass `getMetadata` and `setMetadata` functions, useful for metadata caching. You can [find a recipe in the docs](/recipes/metadata-caching) on how to use this! |
| 9 | + |
| 10 | +```ts twoslash |
| 11 | +// [!include ~/snippets/startSm.ts] |
| 12 | +import { getSmProvider } from "polkadot-api/sm-provider" |
| 13 | +const provider = getSmProvider(smoldot.addChain({ chainSpec: "" })) |
| 14 | +//---cut--- |
| 15 | +import { createClient } from "polkadot-api" |
| 16 | + |
| 17 | +const client = createClient(provider) |
| 18 | +``` |
| 19 | + |
| 20 | +## `PolkadotClient` |
| 21 | + |
| 22 | +Let's dive into each part of the `PolkadotClient` interface. |
| 23 | + |
| 24 | +### `getChainSpecData` |
| 25 | + |
| 26 | +Type: `() => Promise<{name: string; genesisHash: string; properties: any}>{:ts}` |
| 27 | + |
| 28 | +Retrieve the ChainSpecData directly as it comes from the [JSON-RPC spec](https://paritytech.github.io/json-rpc-interface-spec/api/chainSpec.html). |
| 29 | + |
| 30 | +The consumer shouldn't make assumptions on this data, as it might change from session to session and it is not strictly typed. |
| 31 | + |
| 32 | +### `getMetadata$` |
| 33 | + |
| 34 | +Type: `(atBlock: HexString) => Observable<Uint8Array>{:ts}` |
| 35 | + |
| 36 | +Retrieves the most modern version of the metadata for a given block. That is, if metadata versions 14, 15 and 16 are available, metadata version 16 will be returned. |
| 37 | + |
| 38 | +The observable will emit once, and immediately complete. |
| 39 | + |
| 40 | +### `getMetadata` |
| 41 | + |
| 42 | +Type: `(atBlock: HexString, signal?: AbortSignal) => Promise<Uint8Array>{:ts}` |
| 43 | + |
| 44 | +Retrieves the most modern version of the metadata for a given block. That is, if metadata versions 14, 15 and 16 are available, metadata version 16 will be returned. |
| 45 | + |
| 46 | +The function accepts an abort signal to make the promise abortable. |
| 47 | + |
| 48 | +### `finalizedBlock$` |
| 49 | + |
| 50 | +Type: `Observable<BlockInfo>{:ts}` |
| 51 | + |
| 52 | +This Observable emits [`BlockInfo`](/types#blockinfo) for every new finalized block. It is multicast and stateful. For a new subscription, it will synchronously repeat its latest known state. |
| 53 | + |
| 54 | +### `getFinalizedBlock` |
| 55 | + |
| 56 | +Type: `() => Promise<BlockInfo>{:ts}` |
| 57 | + |
| 58 | +This function returns [`BlockInfo`](/types#blockinfo) for the latest known finalized block. |
| 59 | + |
| 60 | +### `bestBlocks$` |
| 61 | + |
| 62 | +Type: `Observable<BlockInfo[]>{:ts}` |
| 63 | + |
| 64 | +This Observable emits an array of [`BlockInfo`](/types#blockinfo), being the first element the latest known best block, and the last element the latest known finalized block. |
| 65 | + |
| 66 | +The following guarantees apply: |
| 67 | + |
| 68 | +- It is a multicast and stateful observable. For a new subscription, it will synchronously repeat its latest known state. |
| 69 | +- In every emission, the array will have length of at least `1{:ts}`. |
| 70 | +- The emitted arrays are immutable data structures; i.e. a new array is emitted at every event but the reference to its children are stable if the children didn't change. |
| 71 | + |
| 72 | +### `getBestBlocks` |
| 73 | + |
| 74 | +Type: `() => Promise<BlockInfo[]>{:ts}` |
| 75 | + |
| 76 | +This function returns the latest known state of [`bestBlocks$`](/client#bestblocks). It holds the same guarantees. |
| 77 | + |
| 78 | +### `blocks$` |
| 79 | + |
| 80 | +Type: `Observable<BlockInfo>{:ts}` |
| 81 | + |
| 82 | +This observable emits [`BlockInfo`](/types#blockinfo) for every block the client discovers. This observable follows the following rules: |
| 83 | + |
| 84 | +- Right after subscription, the observable will emit synchronously the latest finalized block and all its known descendants. |
| 85 | +- The emissions are "continuous"; i.e. for every block emitted it is guaranteed that the parent of it has already been emitted. |
| 86 | +- The Observable will complete if the continuity of the blocks cannot be guaranteed. |
| 87 | + |
| 88 | +### `hodlBlock` |
| 89 | + |
| 90 | +Type: `(blockHash: HexString) => () => void{:ts}` |
| 91 | + |
| 92 | +This function prevents the block from being unpinned. Returns a function that releases the hold, allowing the block to be unpinned once no other operations remain. |
| 93 | + |
| 94 | +```ts twoslash |
| 95 | +import type { PolkadotClient } from "polkadot-api" |
| 96 | +const client: PolkadotClient = null as any |
| 97 | +// ---cut--- |
| 98 | +const finalized = await client.getFinalizedBlock() |
| 99 | +const releaseFn = client.hodlBlock(finalized.hash) |
| 100 | + |
| 101 | +// the block will not be released! |
| 102 | +setTimeout(async () => { |
| 103 | + const body = await client.getBlockBody(finalized.hash) |
| 104 | + releaseFn() |
| 105 | +}, 100_000) |
| 106 | +``` |
| 107 | + |
| 108 | +### `watchBlockBody` |
| 109 | + |
| 110 | +Type: `(hash: string) => Observable<HexString[]>{:ts}` |
| 111 | + |
| 112 | +Retrieves the body of the block given; which can be a block hash, `"finalized"{:ts}` or `"best"{:ts}`. |
| 113 | + |
| 114 | +The observable will emit once, and immediately complete. |
| 115 | + |
| 116 | +### `getBlockBody` |
| 117 | + |
| 118 | +Type: `(hash: string) => Promise<HexString[]>{:ts}` |
| 119 | + |
| 120 | +Retrieves the body of the block given; which can be a block hash, `"finalized"{:ts}` or `"best"{:ts}`. |
| 121 | + |
| 122 | +### `getBlockHeader` |
| 123 | + |
| 124 | +Type: `(hash?: string) => Promise<BlockHeader>{:ts}` |
| 125 | + |
| 126 | +Retrieves the decoded header of the block given; which can be a block hash, `"finalized"{:ts}` (default) or `"best"{:ts}`. |
| 127 | + |
| 128 | +### `submit` |
| 129 | + |
| 130 | +Type: `(transaction: HexString, at?: HexString) => Promise<TxFinalizedPayload>{:ts}` |
| 131 | + |
| 132 | +Broadcasts a transaction. The promise will resolve when the transaction is found in a finalized block, and will reject if the transaction is deemed invalid (either before or after broadcasting). |
| 133 | + |
| 134 | +This function follows the same logic as the [transaction API `submitAndWatch` function](/typed/tx#signandsubmit), find more information about it there. |
| 135 | + |
| 136 | +### `submitAndWatch` |
| 137 | + |
| 138 | +Type: `(transaction: HexString, at?: HexString) => Observable<TxBroadcastEvent>{:ts}` |
| 139 | + |
| 140 | +Broadcasts a transaction. This function follows the same logic as the [transaction API `signSubmitAndWatch` function](/typed/tx#signsubmitandwatch), find more information about the emitted events there. |
| 141 | + |
| 142 | +### `getTypedApi` |
| 143 | + |
| 144 | +Type: `(descriptors: ChainDefinition) => TypedApi{:ts}` |
| 145 | + |
| 146 | +The Typed API is the entry point to the runtime-specific interactions with Polkadot-API. You can do storage queries, create transactions, run view functions, etc! |
| 147 | + |
| 148 | +[`TypedApi` has its own documentation](/typed). Check it out! |
| 149 | + |
| 150 | +### `getUnsafeApi` |
| 151 | + |
| 152 | +Type: `() => UnsafeApi{:ts}` |
| 153 | + |
| 154 | +The Unsafe API is another way to access the specific interactions of the chain you're connected to. Nevertheless, it has its own caveats, read the docs before using it! |
| 155 | + |
| 156 | +[`UnsafeApi` has its own documentation](/unsafe). Check it out! |
| 157 | + |
| 158 | +### `rawQuery` |
| 159 | + |
| 160 | +Type: |
| 161 | + |
5 | 162 | ```ts |
6 | | -interface PolkadotClient { |
7 | | - /** |
8 | | - * Retrieve the ChainSpecData as it comes from the [JSON-RPC |
9 | | - * spec](https://paritytech.github.io/json-rpc-interface-spec/api/chainSpec.html) |
10 | | - */ |
11 | | - getChainSpecData: () => Promise<ChainSpecData> |
12 | | - |
13 | | - /** |
14 | | - * Retrieves the most modern stable version of the metadata for a given block. |
15 | | - * |
16 | | - * @param atBlock The block-hash of the block. |
17 | | - * @returns Observable that emits the most modern stable version of the |
18 | | - * metadata, and immediately completes. |
19 | | - */ |
20 | | - getMetadata$: (atBlock: HexString) => Observable<Uint8Array> |
21 | | - /** |
22 | | - * Retrieves the most modern stable version of the metadata for a given block. |
23 | | - * |
24 | | - * @param atBlock The block-hash of the block. |
25 | | - * @returns An abortable Promise that resolves into the most modern |
26 | | - * stable version of the metadata. |
27 | | - */ |
28 | | - getMetadata: (atBlock: HexString, signal?: AbortSignal) => Promise<Uint8Array> |
29 | | - |
30 | | - /** |
31 | | - * Observable that emits `BlockInfo` for every new finalized block. It's a |
32 | | - * multicast and stateful observable, that will synchronously replay its |
33 | | - * latest known state. |
34 | | - */ |
35 | | - finalizedBlock$: Observable<BlockInfo> |
36 | | - /** |
37 | | - * @returns Latest known finalized block. |
38 | | - */ |
39 | | - getFinalizedBlock: () => Promise<BlockInfo> |
40 | | - |
41 | | - /** |
42 | | - * Observable that emits an Array of `BlockInfo`, being the first element the |
43 | | - * latest known best block, and the last element the latest known finalized |
44 | | - * block. It's a multicast and stateful observable, that will synchronously |
45 | | - * replay its latest known state. This array is an immutable data structure; |
46 | | - * i.e. a new array is emitted at every event but the reference to its |
47 | | - * children are stable if the children didn't change. |
48 | | - * |
49 | | - * Note that some blocks might not get reported, e.g. if they become finalized |
50 | | - * immediately without being part of the best block chain. |
51 | | - */ |
52 | | - bestBlocks$: Observable<BlockInfo[]> |
53 | | - /** |
54 | | - * @returns Array of `BlockInfo`, being the first element the latest |
55 | | - * known best block, and the last element the latest known |
56 | | - * finalized block. |
57 | | - */ |
58 | | - getBestBlocks: () => Promise<BlockInfo[]> |
59 | | - |
60 | | - /** |
61 | | - * Observable of new blocks that have been discovered by the client. |
62 | | - */ |
63 | | - blocks$: Observable<BlockInfo> |
64 | | - |
65 | | - /** |
66 | | - * Ensures that a block stays available, even after it has been finalized and |
67 | | - * no operations are running for that block. |
68 | | - * |
69 | | - * @returns A callback function to release the block. |
70 | | - */ |
71 | | - hodlBlock: (blockHash: HexString) => () => void |
72 | | - |
73 | | - /** |
74 | | - * Observable to watch Block Body. |
75 | | - * |
76 | | - * @param hash It can be a block hash, `"finalized"`, or `"best"` |
77 | | - * @returns Observable to watch a block body. There'll be just one event |
78 | | - * with the payload and the observable will complete. |
79 | | - */ |
80 | | - watchBlockBody: (hash: string) => Observable<HexString[]> |
81 | | - /** |
82 | | - * Get Block Body (Promise-based) |
83 | | - * |
84 | | - * @param hash It can be a block hash, `"finalized"`, or `"best"` |
85 | | - * @returns Block body. |
86 | | - */ |
87 | | - getBlockBody: (hash: string) => Promise<HexString[]> |
88 | | - |
89 | | - /** |
90 | | - * Get Block Header (Promise-based) |
91 | | - * |
92 | | - * @param hash It can be a block hash, `"finalized"` (default), or |
93 | | - * `"best"` |
94 | | - * @returns Block hash. |
95 | | - */ |
96 | | - getBlockHeader: (hash?: string) => Promise<BlockHeader> |
97 | | - |
98 | | - /** |
99 | | - * Broadcasts a transaction (Promise-based). The promise will resolve when the |
100 | | - * transaction is found in a finalized block; and will reject if the |
101 | | - * transaction is invalid and can't be broadcasted, or if it is deemed invalid |
102 | | - * later on. |
103 | | - * |
104 | | - * @param transaction SCALE-encoded tx to broadcast. |
105 | | - * @param at It can be a block hash, `"finalized"`, or `"best"`. |
106 | | - * That block will be used to verify the validity of |
107 | | - * the tx. |
108 | | - */ |
109 | | - submit: ( |
110 | | - transaction: HexString, |
111 | | - at?: HexString, |
112 | | - ) => Promise<TxFinalizedPayload> |
113 | | - /** |
114 | | - * Broadcasts a transaction and returns an Observable. The observable will |
115 | | - * complete as soon as the transaction is in a finalized block. See |
116 | | - * https://papi.how/typed/tx#signsubmitandwatch to learn about all possible |
117 | | - * events. |
118 | | - * |
119 | | - * @param transaction SCALE-encoded tx to broadcast. |
120 | | - * @param at It can be a block hash, `"finalized"`, or `"best"`. |
121 | | - * That block will be used to verify the validity of |
122 | | - * the tx. |
123 | | - */ |
124 | | - submitAndWatch: ( |
125 | | - transaction: HexString, |
126 | | - at?: HexString, |
127 | | - ) => Observable<TxBroadcastEvent> |
128 | | - |
129 | | - /** |
130 | | - * Returns an instance of a `TypedApi`. |
131 | | - * |
132 | | - * @param descriptors Pass descriptors from `@polkadot-api/descriptors` |
133 | | - * generated by `papi` CLI. |
134 | | - */ |
135 | | - getTypedApi: <D extends ChainDefinition>(descriptors: D) => TypedApi<D> |
136 | | - |
137 | | - /** |
138 | | - * Returns an instance of a `UnsafeApi`. |
139 | | - * |
140 | | - * Note that this method is only meant for advanced users that really know |
141 | | - * what are they doing. This API does not provide any runtime compatibility |
142 | | - * checks protection and the consumer should implement them on their own. |
143 | | - */ |
144 | | - getUnsafeApi: <D>() => UnsafeApi<D> |
145 | | - |
146 | | - /** |
147 | | - * Returns a Promise that resolves into the encoded value of a storage entry |
148 | | - * or `null` if the key doesn't have a corresponding value. |
149 | | - * |
150 | | - * @param storageKey Either one of the well-known substrate storage keys |
151 | | - * or an hexadecimal storage key. |
152 | | - */ |
153 | | - rawQuery: ( |
154 | | - storageKey: HexString | string, |
155 | | - options?: PullOptions, |
156 | | - ) => Promise<HexString | null> |
157 | | - |
158 | | - /** |
159 | | - * This will `unfollow` the provider, disconnect and error every subscription. |
160 | | - * After calling it nothing can be done with the client. |
161 | | - */ |
162 | | - destroy: () => void |
163 | | - |
164 | | - /** |
165 | | - * This API is meant as an "escape hatch" to allow access to debug endpoints |
166 | | - * such as `system_version`, and other useful endpoints that are not spec |
167 | | - * compliant. |
168 | | - * |
169 | | - * @example |
170 | | - * |
171 | | - * const systemVersion = await client._request<string>("system_version", []) |
172 | | - * const myFancyThhing = await client._request< |
173 | | - * { value: string }, |
174 | | - * [id: number] |
175 | | - * >("very_fancy", [1714]) |
176 | | - * |
177 | | - */ |
178 | | - _request: <Reply = any, Params extends Array<any> = any[]>( |
179 | | - method: string, |
180 | | - params: Params, |
181 | | - ) => Promise<Reply> |
182 | | -} |
| 163 | +rawQuery: ( |
| 164 | + storageKey: HexString | string, |
| 165 | + options?: { at: string; signal: AbortSignal }, |
| 166 | +) => Promise<HexString | null> |
183 | 167 | ``` |
184 | 168 |
|
185 | | -As one can note, `PolkadotClient` heavily relies on rxjs' `Observable`, used as well under the hood of Promise-based methods. Every method is fairly straight-forward and already documented exhaustively, except for `getTypedApi` and `getUnsafeApi`. We will see first of all the `TypedApi`, and afterwards the `UnsafeApi`. |
| 169 | +This function allows to access the raw storage value of a given key. It'll return the encoded value, or `null{:ts}` if the value is not found. |
| 170 | + |
| 171 | +Parameters: |
| 172 | + |
| 173 | +- `storageKey`: it can be both an encoded key (as `HexString`) or a well-known Substrate key (such as `":code"{:ts}`). |
| 174 | +- `options`: Optionally pass `at` (block hash, `"finalized"{:ts}` (default), or `"best"{:ts}`) and/or `signal`, to make the promise abortable. |
| 175 | + |
| 176 | +### `destroy` |
| 177 | + |
| 178 | +Type: `() => void{:ts}` |
| 179 | + |
| 180 | +This function will unfollow the provider, error every subscription pending and disconnect from the provider. After calling it, nothing else can be done with the client. |
| 181 | + |
| 182 | +### `_request` |
| 183 | + |
| 184 | +Type: `(method: string, params: Array<any>) => Promise<any>{:ts}` |
| 185 | + |
| 186 | +This function allows to call any RPC endpoint through the JSON-RPC provider. This method is not typed by itself, but you can add your own types. It is meant as an escape-hatch for chain-specific nodes, you should use all the other APIs for regular interactions. |
| 187 | + |
| 188 | +For example, with `system_version`: |
| 189 | + |
| 190 | +```ts twoslash |
| 191 | +import type { PolkadotClient } from "polkadot-api" |
| 192 | +const client: PolkadotClient = null as any |
| 193 | +// ---cut--- |
| 194 | +const nodeVersion = await client._request<string, []>("system_version", []) |
| 195 | +// ^? |
| 196 | +``` |
0 commit comments