This repository has been archived by the owner on Sep 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Readme.md
234 lines (156 loc) · 6.61 KB
/
Readme.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Capi
Capi is a WIP TypeScript toolkit for crafting interactions with Substrate-based chains.
Capi consists of [FRAME](https://docs.substrate.io/v3/runtime/frame/)-oriented utilities and (soon) [a high-level functional effect system](_docs/Effects.md) which facilitate multistep, multichain interactions without compromising on performance or safety.
<!--
<h4>
<a href="">Guide</a> ·
<a href="">API Reference</a> ·
<a href="">Support</a> ·
<a href="">Roadmap</a> ·
<a href="">Contributing</a>
</h4>
-->
## ⚠ This Is a Work in Progress
️Please share feedback or even join us in Capi's development; issues and PRs are very welcome!
### In Good Shape
- [x] RPC `call` and `subscribe` utils
- [x] Metadata types and SCALE codecs
- [x] Metadata-based codec derivation
- [x] Storage key encoding and (when transparent) decoding
- [x] Storage value decoding
- [x] Creating and decoding extrinsics
- [x] RPC Client hooks / error handing
### TODO
- [ ] Take a look at [this repo's issues](https://github.com/paritytech/capi/issues)
### Setup
If you're using [Deno](https://deno.land/), import via the `denoland/x` specifier.
```ts
import * as C from "https://deno.land/x/capi/mod.ts";
```
> Note: you may want to pin the version in your import specifier (`https://deno.land/x/[email protected]/mod.ts`).
If you're using [Node](https://nodejs.org/), install Capi from NPM.
```sh
npm install capi
```
Then import as follows.
```ts
import * as C from "capi";
```
## Configs
### Introduction
Before interacting with a given chain, we must have a means of finding nodes of that chain (a config).
A Polkadot-specific config is accessible from `capi/known`.
```ts
// Deno
import { polkadot } from "https://deno.land/x/capi/known/mod.ts";
// Node
import { polkadot } from "capi/known";
```
The static type of any config can describe accessible RPC server methods and FRAME metadata. This enables a narrowly-typed experience to flow through all usage of Capi.
```ts
const polkadot = C.chain(polkadot);
```
Better yet, let's import `polkadot` directly from `capi/known`.
```ts
import { polkadot } from "capi/known";
```
### Testing
During development, connecting to a live network can slow down the feedback loop. It also may be infeasible, in the case that you are without an internet connection. In these situations, you can utilize Capi's test utilities.
```diff
+ const node = await C.test.node();
+
- const chain = C.chain(myConfig);
+ const chain = C.test.chain(node);
//
+ node.close()
```
Here, we've spun up a tiny, temporary chain. You can even access accounts (and their corresponding signers).
```ts
const { alice } = chain.address;
```
For convenience, we'll be utilizing the test chain and addresses.
### Read a Balance
```ts
const alicePublicKey = chain.address.alice.asPublicKeyBytes();
const value = await chain
.pallet("System")
.entry("Account", alicePublicKey)
.read();
```
#### Read at Specific Block Hash
```ts
const block = chain.block(BLOCK_HASH);
// ...
const value = await chain
.pallet("System")
.entry("Account", alicePublicKey)
.read(block);
```
### Note About Typings
#### Signatures
The signature `value` is a union of `Read<unknown>` and all possible error types.
```ts
assertTypeEquals<
typeof value,
C.Read<unknown> | C.WsRpcError | C.StorageEntryDneError | C.StorageValueDecodeError
>();
```
#### Narrow Error Handling
We can utilize an `instanceof` check to narrow the `result` before accessing the read value.
```ts
if (result instanceof Error) {
// Handle narrow error types here
} else {
// Handle `C.Read<unknown>` here
}
```
### Transfer Some Dot
```ts
import * as C from "../mod.ts";
// ...
const { alice, bob } = chain.address;
const result = chain
.pallet("Balances")
.extrinsic("transfer")
.call({
dest: alice.asPublicKeyBytes(),
value: 12345n,
})
.signed(bob, bob.sign)
.send();
for await (const event of result) {
console.log({ event });
}
```
> Note: it is up to the developer to supply `sign` with a signing function, which will vary depending on your environment, wallet, misc.
## Environment setup
> In the future, Gitpod and dev containers will simplify spinning up a Capi development environments. The [Dockerfile](./Dockerfile), [Gitpod configuration](./.gitpod.yml) and [Dev Containers / Codespaces configuration](./.devcontainer/devcontainer.json) are in need some finessing.
Make sure you have the following installed on your machine (and please submit issues if errors crop up).
### System Requirements
- [Deno](https://deno.land/[email protected]/getting_started/installation)
- [Docker](https://docs.docker.com/get-docker/)
- [NodeJS](https://nodejs.org/) (only necessary if you're going to run [the build_npm task](./_/tasks/build_npm.ts))
### Running an Example
```sh
deno task run <path-to-example>
```
### Utilizing the Package in a NodeJS Project
Build the NPM package and link it locally.
```sh
deno task dnt && cd target/npm && npm link
```
Then link to Capi from your NodeJS project.
```ts
npm link capi
```
## Code Structure
You may have noticed that the Capi repository looks somewhat different from a traditional TypeScript repository. This is because Capi is developed Deno-first. [Deno](https://deno.land/) is a TypeScript runtime and toolkit written in Rust. Unlike NodeJS, Deno emphasizes web standards and exposes a performant and type-safe standard library. Deno-first TypeScript can be easily packaged for consumption in NodeJS, Browsers, CloudFlare Workers and other environments. Some things to note:
### No `src` nor Distinct `package/*`
We no longer need to think about the separation of code for the sake of packaging. We can think about separation of code in terms of what best suits our development needs.
For example, exports of [`util/types.ts`](./util/types.ts) can be imported directly into any other TypeScript file, without specifying the dependency in a package manifest. We are free to use (for example) `U2I`, the union to intersection utility, in out-of-band processes, the effect system or even GitHub workflow scripts. From anywhere in the repository, we can import and use any code with configuration overhead.
When it comes time to [build our code](./tasks/dnt.ts) for NPM distribution, [DNT](https://github.com/denoland/dnt) takes care of transforming our dependency graph into something that NodeJS and web browsers will understand.
## Contributing
Contributions are welcome and appreciated! Check out the [contributing guide](CONTRIBUTING.md) before you dive in.
Everyone interacting in the project is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
## License
Capi is [Apache licensed](LICENSE).