1.0.69 • Published 1 year ago

kwil-js-sdk v1.0.69

Weekly downloads
-
License
ISC
Repository
-
Last release
1 year ago

Kwil-JS

Kwil-JS is a JavaScript/Typescript SDK for building web applications to interact with the Kwil network. Currently the SDK is in alpha and is not ready for NodeJS production use, but should be ready for use in the browser.

The Kwil-JS SDK does not yet include DDL capabilities. In order to make DDL calls, you will need to use the Kwil-CLI.

Installation

npm i kwil

Initialization

Web

import { ethers } from 'ethers';
import kwiljs from 'kwil';

// prompt metamask to connect
const provider = new ethers.providers.Web3Provider(window.ethereum)
await provider._ready()
await ethereum.request({ method: 'eth_requestAccounts' });

// create a new Kwil web client
const kwil = new kwiljs.WebKwil({
    provider: provider,
    pool: "0xb0a194286A901FeAEA39D2b765247BEd64aD4F41",
    kwilProvider: "localhost:8081",
    ssl: false,
    timeout: 10000,
    apiKey: "N2lZDtEim0HDDU8k2YrtUOE8qMuwBpG0"
});

// connect to your Kwil provider.  This authorizes your client and retrieves the validator address.
await kwil.connect()

NodeJS

const { ethers } = require('ethers');
const kwiljs = require('kwil');

// prompt metamask to connect
const provider = new ethers.providers.Web3Provider(window.ethereum)
provider.send("eth_requestAccounts", [])

// create a new Kwil web client
const kwil = new kwiljs.WebKwil({
    provider: provider,
    pool: "0xb0a194286A901FeAEA39D2b765247BEd64aD4F41",
    kwilProvider: "localhost:8081",
    ssl: false,
    timeout: 10000,
    apiKey: "N2lZDtEim0HDDU8k2YrtUOE8qMuwBpG0"
});

// connect to your Kwil provider.  This authorizes your client and retrieves the validator address.
await kwil.connect()

Usage

Funding

Adding funds to a funding pool

Here, you can add funds to a funding pool.

Since Kwil supports a variety of token types as payment, it is important to initialize the ERC20 smart contract before you can fund. This is done automatically if you connect your client to your Kwil provider using the Kwil.connect() method. You can also manually set the pool with the funder.setPool() method, which will auto initialize your ERC20 contract. Finally, you can also call the initErc20Contract() method directly.

/*
    The funder.setPool method can be used to set the funding pool to deposit funds to.
    This is already set in the constructor, but can be changed at any time.
*/
await kwil.funder.setPool("0xE596928C26A11e9373FC4245d6Ee02aE0De32612") // Kwil USDC pool on Goerli

// OR

await kwil.funder.initErc20Contract()

Approving and deposit funds

const currentAllowance = await kwil.funder.getAllowance()
// currentAllowance: BigNumber { _hex: '0x00', _isBigNumber: true }

let res = await kwil.funder.approve(1000000) // $1 USDC
/*
    res: { hash: '0x...'}
*/

res = await kwil.funder.deposit(1000000) // $1 USDC
/*
    res: { hash: '0x...'}
*/

const depositAmt = await kwil.funder.getDepositAmount()
// depositAmt: BigNumber { _hex: '0x00', _isBigNumber: true }

Kwil-JS also provides other utility functions for checking your token balance and usage:

// get the token address for the current pool
const token = await kwil.funder.getToken()
// token: "0xE596928C26A11e9373FC4245d6Ee02aE0De32612"

// get the total (both used and unused) token balance for the pool
const balance = await kwil.funder.getBalance("0xAfFDC06cF34aFD7D5801A13d48C92AD39609901D")
// balance: BigNumber { _hex: '0x00', _isBigNumber: true }

// get the unused balance held in escrow
const escrowBalance = await kwil.funder.getRemainingBalance("0xAfFDC06cF34aFD7D5801A13d48C92AD39609901D")
// escrowBalance: BigNumber { _hex: '0x00', _isBigNumber: true }

Querying

Querying a Kwil provider You can create new database objects for managing queries and roles in databases. Databases are stored in a directory-like structure, where the root directory is the creator's wallet, and the subdirectory is the database name.

Once the database is initialized, you have to make a call to the server to load the database query metadata.

let res = await kwil.retrieveDatabase("owner_address", "database_name")

const db = res.data

// get a query
const exec = db.query("my_insert_query")

// add inputs
exec.addInput(0 "my_value")
exec.addInput(1, "my_other_value")

const tx = exec.newTx()

await kwil.estimateCost(tx)

await tx.sign(kwil.signer)

res = await kwil.broadcast(tx)

Database Building

With the Kwil-JS SDK, you can build and deploy databases from the browser.

// create a new database
let db = new kwiljs.DBBuilder("my_db")

// create a new table
let table1 = db.newTable("table1")

// add columns
let col1 = table1.newColumn("col1", kwiljs.Types.DataType.STRING)
let col2 = table1.newColumn("col2", kwiljs.Types.DataType.INT64)

// you can add attributes as well
col1.addAttribute(kwiljs.Types.AttributeType.PRIMARY_KEY)

// some attributes require a value (e.g. default, min, max, etc.)
col2.addAttribute(kwiljs.Types.AttributeType.MIN, 420)

// add the columns to the table
table1.addColumn(col1)
table1.addColumn(col2)

// add the table to the database
db.addTable(table1)

// all items stored have unique identifiers. If I add another table called "table1",
// it will overwrite the previous table named "table1".
let table1part2 = db.newTable("table1")
db.addTable(table1part2)
// table1part2 is now the only table in the database

// create a new query
// when defining a query, you must specify the name, the table it is querying, and the type of query
// the queries are uniquely identified by their name
let query1 = db.newQuery("query1", "table1", kwiljs.Types.QueryType.INSERT)

// queries can have inputs and where predicates
// an INSERT can only have inputs, a DELETE can only have where predicates, and an UPDATE can have both
// inputs and where predicates can be left to the user, or they can be set to a default value.
// Furthermore, queries can contain "modifiers", which are special functions that can be used to
// modify the query before it is executed.  For example, you can use the "caller" modifier to
// set the input / where predicate to the address of the function caller (similar to Solidity's msg.sender).

/*
    An input has the following structure:
    {
        column: "col1",
        static: true,
        value: "my_value",
        modifier: kwiljs.Types.ModifierType.CALLER
    }

    The only required field is "column", which is the name of the column to set the input for.

    If static is true, then the value field is also required.
*/

// input where the user must provide a value
query1.addInput({
    column: "col1",
})

// input where the value is static
query1.addInput({
    column: "col2",
    static: true,
    value: 420
})

// Inputs are identified by their column name.  If you add another input with the same column name,
// it will overwrite the previous input.

// An input with a modifier
query1.addInput({
    column: "col1",
    static: true,
    value: "",
    modifier: kwiljs.Types.ModifierType.CALLER
})

// query1 now has 2 default inputs and 0 user inputs

// Let's make an update query.
let query2 = db.newQuery("query2", "table1", kwiljs.Types.QueryType.UPDATE)

// add an input for the user to fill
query2.addInput({
    column: "col2"
})

/*
    Now let's add a where predicate.  A where predicate specifies the row(s) to update.
    The where predicate has the following structure:
    {
        column: "col1",
        static: true,
        value: "",
        modifier: kwiljs.Types.ModifierType.CALLER,
        operator: kwiljs.Types.OperatorType.EQUAL
    }
*/

// the below where predicate will update all columns where col1 = the caller's address
query2.addWhere({
    column: "col1",
    static: true,
    value: "",
    modifier: kwiljs.Types.ModifierType.CALLER,
    operator: kwiljs.Types.OperatorType.EQUAL
})

db.addQuery(query1)
db.addQuery(query2)

// now let's make some roles
let role1 = db.newRole("bingus")

// let's add some permissions to the role
role.addPermission("query1")
role.addPermission("query2")

// let's make another role
let role2 = db.newRole("chowda")

// chowda is inferior to bingus, so let's only give him query1
role2.addPermission("query1")

/*
    the role "Bingus" can execute query1 and query2, while the role "Chowda" can only execute query1.
*/

// add the roles to the database
db.addRole(role1)
db.addRole(role2)

// now, let's make an index
let index1 = db.newIndex("my_index_name", "table1",["col2"], kwiljs.Types.IndexType.BTREE)

// add the index to the database
db.addIndex(index1)

// now, let's submit the database to the network
let tx = db.newTx()

await kwil.estimateCost(tx)

await tx.sign(kwil.signer)

res = await kwil.broadcast(tx)