Kwil JS Overview
Below is a quick overview of how to use the Kwil JS SDK. For more detailed information, see the API Reference.
Installation
The Kwil JS SDK can be installed using npm.
npm install @kwilteam/kwil-js
Initialize
Kwil has different initialization logic for Web and NodeJS
- Web
- NodeJS
import { BrowserProvider } from 'ethers';
import { WebKwil } from '@kwilteam/kwil-js';
// to be used for funding and signing transactions
const provider = new BrowserProvider(window.ethereum)
const kwil = new WebKwil({
kwilProvider: "kwil_provider_endpoint",
chainId: "your_kwil_chain_id"
});
const { Wallet } = require('ethers');
const kwiljs = require('@kwilteam/kwil-js');
// to be used for signing transactions
// instead of a provider, nodeJS requires a wallet
const wallet = new Wallet("my_ethereum_private_key")
const kwil = new kwiljs.NodeKwil({
kwilProvider: "kwil_provider_endpoint",
chainId: "your_kwil_chain_id"
});
Optional Configuration
The WebKwil
and NodeKwil
constructors take a configuration object. The only required fields are kwilProvider
and chainId
; however, there are additional configuration options available:
import { WebKwil, Utils } from '@kwilteam/kwil-js';
const kwil = new WebKwil({
kwilProvider: 'https://longhorn.kwil.com';
chainId: 'longhorn-2';
// optional configuration
unconfirmedNonce?: boolean; // sends transactions and returns getAccount with unconfirmed nonce, default false
timeout?: number; // timeout for requests, default 30000
logging?: boolean; // enable logging, default false
logger?: Function // custom logger, default console.log
cache?: number // ttl for cache in seconds, default is 10 minutes. 0 disables cache.
});
To verify you have the correct chainId
, you can use the chainInfo()
method.
Identifiers
Account Identifiers
In Kwil, accounts are identified by the signer(s) that are used on the Kwil Network. Kwil natively supports two types of signers: Secp256k1 (EVM) and ED25519.
Secp256k1 signers use Ethereum wallet addresses as account identifiers. ED25519 signers use the ED25519 public key as account identifiers.
Database Identifiers (DBID)
In Kwil, databases are identified by a 'database identifier' (sometime referred to as DBID), which is a hex encoded SHA224 Hash of the database name and public key, prepended with an x
.
The account identifier can be passed as a hex-encoded string, or as Bytes (Uint8Array
).
To get the DBID for an account identifier and database name, you can use the following helper method:
import { Utils } from "@kwilteam/kwil-js";
const dbid = Utils.generateDBID('account_identifier', 'database_name')
Signers
Certain operations in Kwil require signature authentication from the user (e.g. deploy database, drop database, execute CRUD actions, etc).
To manage signing, Kwil-JS uses a KwilSigner
class. Out of the box, Kwil-JS supports signers from EthersJS (v5 and v6). You can also pass a signing callback function (see below).
import { KwilSigner } from '@kwilteam/kwil-js';
import { BrowserProvider } from 'ethers';
// get ethers signer
const provider = new BrowserProvider(window.ethereum)
const signer = await provider.getSigner();
// get ethereum address
const identifier = await signer.getAddress();
// create kwil signer
const kwilSigner = new KwilSigner(signer, identifier);
Custom Signers
If you wish to sign with something other than an EtherJS signer, you may pass a callback function that accepts and returns a Uint8Array()
and the enumerator for the signature type used.
Currently, Kwil supports two signature types:
Type | Identifier | Enumerator | Description |
---|---|---|---|
Secp256k1 | Ethereum Wallet Address | 'secp256k1_ep' | The Kwil Signer will use a secp256k1 elliptic curve signature, which is the same signature used in Ethereum's personal sign. |
ED25519 | ED25519 Public Key | 'ed25519' | The Kwil Signer will use an ED25519 signature. |
To use an ed25519 signature:
import nacl from "tweetnacl";
import { KwilSigner } from "@kwilteam/kwil-js";
// create keypair and signer
const keys = nacl.sign.keyPair();
const customSigner = (msg) => nacl.sign.detached(msg, keys.secretKey);
const kwilSigner = new KwilSigner(customSigner, keys.publicKey, "ed25519");
Database Queries
Create, Update, Delete (CUD) Actions
Any action that executes a CUD operation must be signed and broadcasted to the network through the kwil.execute()
method.
.execute()
takes an object that matches the ActionBody
interface. Action body has two required fields: dbid
and action
. You can also optionally add an inputs
field if the action requires inputs, and a description
field to customize the signature message that the user will sign.
- JavaScript
- Typescript
// construct action body
const actionBody = {
dbid,
action: "your_action_name",
inputs: [{
$input_name_1: "input_value_1",
$input_name_2: ...
}],
description: "Click sign to execute the action!",
};
// pass action body and signer to execute method
const res = await kwil.execute(actionBody, kwilSigner);
/*
res.data = {
tx_hash: "hash",
}
*/
import { Types } from "@kwilteam/kwil-js";
// construct action body
const actionBody: Types.ActionBody = {
dbid: dbid,
action: "your_action_name",
inputs:[{
$input_name_1: "input_value_1",
$input_name_2: ...
}],
description: "Click sign to execute the action!",
};
// pass action body and signer to execute method
await kwil.execute(actionBody, kwilSigner);
/*
res.data = {
tx_hash: "hash",
}
*/
Reading Data
To read data on Kwil, you can (1) execute a view
action message or (2) query with the .selectQuery()
method.
View
Action Message
View
actions are read-only actions that can be used to query data without having to wait for a transaction to be mined on Kwil.
Only one input
object is allowed in the inputs
array for view
actions.
- JavaScript
- Typescript
const actionBody = {
dbid,
action: "your_action_name",
inputs: [{ // only one input object is allowed
$input_name_1: "input_value_1",
$input_name_2: ...
}],
};
// pass action body to execute method
const res = await kwil.call(actionBody);
/*
res.data = {
result: [ query results ],
}
*/
import { Types } from "@kwilteam/kwil-js";
const actionBody: Types.ActionBody = {
dbid,
action: "your_action_name",
inputs: [{
$input_name_1: "input_value_1",
$input_name_2: ...
}],
};
// pass action body to execute method
const res = await kwil.call(actionBody);
/*
res.data = {
result: [ query results ],
}
*/
If the view action uses a @caller
contextual variable, you should also pass the kwilSigner
to the kwil.call()
method. This will allow the view action to access the caller's account identifier. The user does not need to sign for view actions.
await kwil.call(actionBody, kwilSigner)
Select Query
const dbid = kwil.getDBID("account_identifier", "database_name");
const res = await kwil.selectQuery(dbid, "SELECT * FROM users");
/*
res.data = [
...
]
*/
Network Info
Get Chain Info
Returns the chain id, latest block height, and latest block hash for the Kwil chain you are connected to.
const res = await kwil.chainInfo()
/*
res.data = {
chainId: "your_chain_id",
blockHeight: "latest_block_height",
blockHash: "latest_block_hash"
}
*/
List Databases
Returns all database on a network. If an account identifier is passed, it will return all databases owned by that account.
const res = await kwil.listDatabases("account_identifier (optional)");
// res.data = ["db1", "db2", "db3"]
Get Schema
import { Utils } from "@kwilteam/kwil-js";
const dbid = Utils.generateDBID("account_identifier", "database_name");
const schema = await kwil.getSchema(dbid);
/*
schema.data = {
owner: Uint8Array,
name: "database_name",
tables: [ tableObject1, tableObject2, tableObject3 ],
actions: [ action1, action2, action3 ],
extensions: [ extension1, extension2 ]
}
*/
Get Account Info
Returns the balance and nonce of a public key.
const res = await kwil.getAccount("account_identifier")
/*
res.data = {
identifier: Uint8Array,
balance: "some_balance",
nonce: "some_nonce"
}
*/
Kwil Gateway Authentication
Kwil Gateway is an optional service on Kwil networks that allows for authenticating users with their signatures for read queries / view actions. If your Kwil network used a Kwil Gateway, you should pass a KwilSigner
to the kwil.call()
method. If the user is not authenticated, the user will be prompted to sign a message to authenticate, and the SDK will automatically include the authentication cookie in each subsequent request.
The Kwil Gateway is still in private beta. If you would like access, please contact our team.
// pass KwilSigner to the call method
const res = await kwil.call(actionBody, kwilSigner);
/*
res.data = {
result: [ query results ],
}
*/
Gateway logout
To log out of the Kwil Gateway, you can call the kwil.auth.logout()
method. This is useful if you want to switch accounts or remove the authentication cookie.
await kwil.auth.logout();
For advanced authentication usage, see read access control advanced usage.