- v0.1.1-beta.1Latest
- v0.1.1-beta.0
- v0.1.0-gamma.1
- v0.1.0-gamma.0
- v0.1.0-beta.49
- v0.1.0-beta.48
- v0.1.0-beta.47
- v0.1.0-beta.46
- v0.1.0-beta.45
- v0.1.0-beta.42
- v0.1.0-beta.41
- v0.1.0-beta.40
- v0.1.0-beta.39
- v0.1.0-beta.38
- v0.1.0-beta.37
- v0.1.0-beta.36
- v0.1.0-beta.35
- v0.1.0-beta.34
- v0.1.0-beta.33
- v0.1.0-beta.32
- v0.1.0-beta.31
- v0.1.0-beta.30
- v0.1.0-beta.29
- v0.1.0-beta.28
- v0.1.0-beta.27
- v0.1.0-beta.26
- v0.1.0-beta.25
- v0.1.0-beta.24
- v0.1.0-beta.23
- v0.1.0-beta.22
- v0.1.0-beta.21
- v0.1.0-beta.20
- v0.1.0-beta.19
- v0.1.0-beta.18
- v0.1.0-beta.17
- v0.1.0-beta.16
- v0.1.0-beta.15
- v0.1.0-beta.14
- v0.1.0-beta.13
- v0.1.0-beta.12
- v0.1.0-beta.11
- v0.1.0-beta.10
- v0.1.0-beta.9
- v0.1.0-beta.8
- v0.1.0-beta.7
- v0.1.0-beta.6
- v0.1.0-beta.5
- v0.1.0-beta.4
- v0.1.0-beta.2
- v0.1.0-beta.1
Capi
Capi is a WIP TypeScript toolkit for crafting interactions with Substrate-based chains.
Capi consists of FRAME-oriented utilities and (soon) a high-level functional effect system which facilitate multistep, multichain interactions without compromising on performance or safety.
⚠ 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
- RPC
call
andsubscribe
utils - Metadata types and SCALE codecs
- Metadata-based codec derivation
- Storage key encoding and (when transparent) decoding
- Storage value decoding
- Creating and decoding extrinsics
- RPC Client hooks / error handing
TODO
- Take a look at this repo’s issues
Setup
If you’re using Deno, import via the denoland/x
specifier.
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/capi@x.x.x/mod.ts
).
If you’re using Node, install Capi from NPM.
npm install capi
Then import as follows.
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
.
// 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.
const polkadot = C.chain(polkadot);
Better yet, let’s import polkadot
directly from capi/known
.
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.
+ 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).
const { alice } = chain.address;
For convenience, we’ll be utilizing the test chain and addresses.
Read a Balance
const alicePublicKey = chain.address.alice.asPublicKeyBytes();
const value = await chain
.pallet("System")
.entry("Account", alicePublicKey)
.read();
Read at Specific Block Hash
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.
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.
if (result instanceof Error) {
// Handle narrow error types here
} else {
// Handle `C.Read<unknown>` here
}
Transfer Some Dot
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.
Contributing
In the future, Gitpod and dev containers will simplify spinning up a Capi development environments. The Dockerfile, Gitpod configuration and Dev Containers / Codespaces configuration 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
- Docker
- NodeJS (only necessary if you’re going to run the build_npm task)
Running an Example
deno task run <path-to-example>
Utilizing the Package in a NodeJS Project
Build the NPM package and link it locally.
deno task dnt && cd target/npm && npm link
Then link to Capi from your NodeJS project.
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 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:
src
nor Distinct package/*
No 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
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 for NPM distribution, DNT takes care of transforming our dependency graph into something that NodeJS and web browsers will understand.