# Docs ## Accounts Accounts represent the key material used to sign transactions. The SDK supports two account types: **local accounts** (private key available in-process) and **JSON-RPC accounts** (signing delegated to a browser extension wallet). ### Account Types #### `LocalAccount` A local account holds the private key directly and can sign without external calls. Created via `mnemonicToAccount`, `hdKeyToAccount`, `privateKeyToAccount`, or `toLocalAccount`. ```ts type LocalAccount = { address: Address xOnlyPubKey: XOnlyPubKey source: string type: "local" signMessage: (params: { message: SignableMessage }) => Promise signPsbt: (params: SignPsbtParams) => Promise<{ txid: string; psbt: Hex }> } ``` #### `JsonRpcAccount` A JSON-RPC account delegates signing to an external provider (e.g. Leather, XVerse). It only stores the address and public key. ```ts type JsonRpcAccount = { address: Address xOnlyPubKey: XOnlyPubKey type: "json-rpc" } ``` ### Creating Accounts #### `mnemonicToAccount` Derives an HD account from a BIP-39 mnemonic phrase. ```ts twoslash import { mnemonicToAccount, signet } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("your mnemonic phrase here", { // [!code focus] networkConfig: signet.networkConfig, // [!code focus] coinType: 1, // testnet // [!code focus] }); // [!code focus] account.address; account.xOnlyPubKey; ``` Options: * `networkConfig` — the Bitcoin network parameters (e.g. `signet.networkConfig`) * `coinType` — `0` for mainnet, `1` for testnet (default: `0`) * `accountIndex` — BIP-86 account index (default: `0`) * `addressIndex` — address index (default: `0`) #### `hdKeyToAccount` Creates an account from an existing `HDKey` instance (from `@scure/bip32`). ```ts import { HDKey } from "@scure/bip32"; import { hdKeyToAccount } from "@kontor/kontor-sdk"; const seed = new Uint8Array([112, 111, 108, 121, 99, 114, 105, 115, 105, 115]); const key = HDKey.fromMasterSeed(seed); const account = hdKeyToAccount(key); // [!code focus] ``` Accepts the same options as `mnemonicToAccount`. #### `privateKeyToAccount` Creates an account from a raw private key hex string. ```ts twoslash import { privateKeyToAccount, signet } from "@kontor/kontor-sdk"; const account = privateKeyToAccount("0xdabdad", { // [!code focus] networkConfig: signet.networkConfig, // [!code focus] }); // [!code focus] ``` ### Utilities #### `toLocalAccount` Converts a `CustomSource` into a `LocalAccount`. Use this when you have a custom signing implementation. ```ts import { toLocalAccount } from "@kontor/kontor-sdk"; const account = toLocalAccount({ address: "tb1p...", xOnlyPubKey: "abcd...", signMessage: async ({ message }) => { /* ... */ }, signPsbt: async ({ psbt, signInputs, broadcast }) => { /* ... */ }, }); ``` #### `parseAccount` Normalizes an `[Address, XOnlyPubKey]` tuple into a `JsonRpcAccount`. If already an `Account`, passes through unchanged. ```ts import { parseAccount } from "@kontor/kontor-sdk"; const account = parseAccount(["tb1p...", "abcd..."]); // => { address: "tb1p...", xOnlyPubKey: "abcd...", type: "json-rpc" } ``` #### `publicKeyToP2TRPayment` Derives a P2TR (Taproot) payment object from a compressed public key. ```ts import { publicKeyToP2TRPayment, signet } from "@kontor/kontor-sdk"; const payment = publicKeyToP2TRPayment("0x02abc...", signet.networkConfig); ``` ### Type Annotations The SDK exports specific account subtypes for type annotations: * **`HDAccount`** — returned by `mnemonicToAccount` and `hdKeyToAccount`, includes `getHdKey()` * **`PrivateKeyAccount`** — returned by `privateKeyToAccount` ```ts import type { HDAccount, PrivateKeyAccount } from "@kontor/kontor-sdk"; ``` ## Composing and Signing a `transfer` on the `nativeToken` contract. :::code-group ```ts [with-indexer-client.ts] import { createKontorWalletClient, signet, custom, mnemonicToAccount, createKontorIndexerClient, http, nativeToken, } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); const composeResponse = await indexerClient.procContract({ account: ["taproot-address", "x-only-public-key"], wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10n, }) const signedCommitHex = await walletClient.signCommit({ psbt: composeResponse.result.commit_psbt_hex, }) const signedRevealHex = await walletClient.signReveal({ psbt: composeResponse.result.reveal_psbt_hex, participantScripts: composeResponse.result.per_participant, }) // ... broadcast ... const destinationBalance = await indexerClient.viewContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "balance", args: ["dst-x-only-public-key"], }) ``` ```ts [with-contract-client.ts] import { createKontorWalletClient, signet, custom, mnemonicToAccount, createKontorIndexerClient, http, nativeToken, getContractClient, } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) const composeResponse = await contract.proc.transfer( ["dst-x-only-public-key", [42n, 18]], { utxos: ["txid:vout"], account: ["src-taproot-address", "src-x-only-public-key"], gas: 1000n, satsPerVByte: 1, }, ); const signedCommitHex = await walletClient.signCommit({ psbt: composeResponse.result.commit_psbt_hex, }) const signedRevealHex = await walletClient.signReveal({ psbt: composeResponse.result.reveal_psbt_hex, participantScripts: composeResponse.result.per_participant, }) // ... broadcast ... const destinationBalance = await contract.view.balance( ["dst-x-only-public-key"], ) ``` ```ts [with-leather.ts] import { createKontorWalletClient, signet, custom, mnemonicToAccount, createKontorIndexerClient, http, nativeToken, getContractClient, } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const leatherTransport = custom({ request: async ({ method, params }) => { if (method === "signPsbt") { const res = await window.LeatherProvider!.request("signPsbt", { hex: params.psbt, broadcast: params.broadcast, signAtIndex: params.signInputs, network: "signet", }); return { result: { psbt: res.result.hex } }; } return window.LeatherProvider!.request(method, params); }, }); const walletClient = createKontorWalletClient({ account, chain: signet, transport: leatherTransport, }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }); const composeResponse = await contract.proc.transfer( ["dst-x-only-public-key", [42n, 18]], { utxos: ["txid:vout"], account: ["src-taproot-address", "src-x-only-public-key"], gas: 1000n, satsPerVByte: 1, }, ); const signedCommitHex = await walletClient.signCommit({ psbt: composeResponse.result.commit_psbt_hex, }); const signedRevealHex = await walletClient.signReveal({ psbt: composeResponse.result.reveal_psbt_hex, participantScripts: composeResponse.result.per_participant, }); // ... broadcast ... const destinationBalance = await contract.view.balance([ "dst-x-only-public-key", ]); ``` ::: ## Error Handling All errors thrown by the SDK extend `BaseError`, which provides a structured error chain and a `walk()` method for traversing nested causes. ### `BaseError` Every SDK error includes: * `shortMessage` — a concise description of what went wrong * `details` — additional context (e.g. HTTP status, URL) * `metaMessages` — optional array of hint strings * `cause` — the underlying error, if any #### Walking the error chain Use `error.walk()` to traverse the cause chain and find a specific error type: ```ts import { BaseError, SimulateFailedError, } from "@kontor/kontor-sdk"; try { // ... some SDK call } catch (e) { if (e instanceof BaseError) { const simulateError = e.walk( (err) => err instanceof SimulateFailedError ); if (simulateError) { console.log("Simulation failed:", simulateError.message); } } } ``` Calling `walk()` with no arguments returns the deepest error in the chain. ### Error Categories #### Account * **`AccountNotFoundError`** — no account was provided for an action that requires one * **`PrivateKeyRequiredError`** — an HD key was used that doesn't contain a private key #### Address * **`InvalidAddressError`** — the provided address is invalid #### Chain * **`ChainNotFoundError`** — no chain was provided to the request * **`ChainMismatchError`** — the action's chain doesn't match the client's chain * **`ClientChainNotConfiguredError`** — the client was created without a chain * **`InvalidChainIdError`** — the chain ID is not recognized #### Request & Transport * **`HttpRequestError`** — an HTTP request failed (includes `status`, `url`) * **`WebSocketRequestError`** — a WebSocket request failed * **`RpcRequestError`** — the RPC server returned an error (includes `code`, `data`) * **`TimeoutError`** — a request timed out * **`SocketClosedError`** — the WebSocket connection was closed unexpectedly * **`UrlRequiredError`** — a transport was created without a URL * **`HttpTransportRequiredError`** — the action requires an HTTP transport * **`WebSocketTransportRequiredError`** — the action requires a WebSocket transport #### RPC * **`RpcError`** — base class for JSON-RPC errors (includes `code`) * **`UnknownRpcError`** — an RPC error with an unrecognized code #### Simulation * **`SimulateFailedError`** — contract simulation returned no result (protocol error or insufficient gas) #### WIT * **`WitFunctionNotFoundError`** — the function name doesn't exist in the WIT * **`WitFunctionOutputsNotFoundError`** — the function has no outputs to decode * **`WitEncodingLengthMismatchError`** — argument count doesn't match the WIT definition * **`InvalidWitEncodingTypeError`** — an unsupported WIT type was used for encoding * **`WitErrorInputsNotFoundError`** — error variant inputs could not be resolved #### UTXO * **`NoUtxosProvidedError`** — no UTXOs were provided for a transaction that requires them ### `instanceof` Checking All errors can be checked with `instanceof`: ```ts import { AccountNotFoundError, HttpRequestError, } from "@kontor/kontor-sdk"; try { // ... some SDK call } catch (e) { if (e instanceof AccountNotFoundError) { console.log("Please provide an account"); } if (e instanceof HttpRequestError) { console.log("Request failed:", e.status, e.url); } } ``` ## Getting Started \[ Start interacting with Kontor in just a few lines of code ] ### Overview Kontor’s SDK is a TypeScript toolkit for building applications that interact with [Kontor](https://docs.kontor.network). It provides a structured, type-safe way to query contract state, compose contract calls, sign transactions, and broadcast them to the network. The SDK is designed around a small set of core concepts: * **Clients**: objects that know how to talk to the network. * **Accounts**: key material or wallet-backed signers used for transaction signing. * **Interfaces**: contract definitions described using **WIT**. ### Contract interfaces with WIT [Kontor contracts](https://docs.kontor.network/docs/sigil/reference/contract-structure#wit-files) are described using [WIT](https://component-model.bytecodealliance.org/design/wit.html) (WebAssembly Interface Types) definitions. Contract WITs define: * available contract functions, * argument and return types, * user defined records and enums The SDK uses WIT as the source of truth for interacting with contracts. From a WIT definition, it can: * expose typed function names and arguments, * encode function calls correctly, * decode responses into structured JavaScript values. This makes it possible to work with contracts in a predictable and type-safe way without manually handling low-level encoding details. ### Installation :::code-group ```bash [npm] npm install @kontor/kontor-sdk ``` ```bash [pnpm] pnpm add @kontor/kontor-sdk ``` ```bash [yarn] yarn add @kontor/kontor-sdk ``` ::: ### Quick Start #### 1. Define a contract The `kontor-sdk` knows how to interpret WITs and produce type safe interfaces to `view` and `proc` calls. Below is an example of the `native-token` contract which is included in the SDK. ```ts twoslash import { parseWit } from "@kontor/kontor-sdk"; export const nativeTokenRaw = [ "record balance { acc: string, amt: decimal }", "record transfer { src: string, dst: string, amt: decimal }", "record burn { src: string, amt: decimal }", "record mint { dst: string, amt: decimal }", "export mint: func(ctx: borrow, amt: decimal) -> result;", "export burn: func(ctx: borrow, amt: decimal) -> result;", "export transfer: func(ctx: borrow, dst: string, amt: decimal) -> result;", "export balance: func(ctx: borrow, acc: string) -> option;", "export balances: func(ctx: borrow) -> list;", "export total-supply: func(ctx: borrow) -> decimal;", "export attach: func(ctx: borrow, vout: u64, amt: decimal) -> result;", "export detach: func(ctx: borrow) -> result;", ] as const; export const nativeToken = parseWit(nativeTokenRaw); ``` #### 2. Create a indexer client The indexer client can be used to read contract state and compose Kontor transactions using a type-safe interface. ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ // [!code focus] chain: signet, // [!code focus] transport: http(), // [!code focus] }); // [!code focus] ``` #### 3. Create a contract object ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ // [!code focus] wit: nativeToken.wit, // [!code focus] contractAddress: "token_0_0", // [!code focus] client: indexerClient, // [!code focus] }) // [!code focus] ``` You know have a fully type safe interface to the contract. ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) // ---cut--- // @noErrors contract.view. // ^| ``` ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) // ---cut--- // @noErrors contract.proc. // ^| ``` #### 4. View contract state ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); // ---cut--- const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) const balances = await contract.view.balances(); // [!code focus] // ^? ``` #### 5. Compose a Kontor transaction ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) // ---cut--- const composeResponse = await contract.proc.transfer( ["dst-x-only-public-key", [42n, 18]], { utxos: ["txid:vout"], account: ["src-taproot-address", "src-x-only-public-key"], gas: 1000n, satsPerVByte: 1, }, ); ``` #### 6. Create a wallet client ```ts twoslash import { createKontorWalletClient, signet, custom, mnemonicToAccount } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, } ); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); ``` #### 7. Sign the commit and reveal ```ts twoslash import { createKontorWalletClient, signet, custom, mnemonicToAccount, createKontorIndexerClient, http, nativeToken, } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, } ); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); const composeResponse = await indexerClient.procContract({ account: ["taproot-address", "x-only-public-key"], wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10n, }) // ---cut--- const signedCommitHex = await walletClient.signCommit({ // [!code focus] psbt: composeResponse.result.commit_psbt_hex, // [!code focus] }) // [!code focus] const signedRevealHex = await walletClient.signReveal({ // [!code focus] psbt: composeResponse.result.reveal_psbt_hex, // [!code focus] participantScripts: composeResponse.result.per_participant, // [!code focus] }) // [!code focus] ``` ## decodeWitParameter `decodeWitParameter` is a low level helper for decoding wave expressions into strings. Rather, than rely on a WIT specification ( e.g. `nativeContract` ) for serialization, it accepts a type parameter explicitly. ```ts import { decodeWitParameter } from "@kontor/kontor-sdk"; const decimal = decodeWitParameter( "{r0: 7, r1: 0, r2: 0, r3: 0, sign: plus}", { type: "decimal" } ) // { decoded: [ 7n, 18 ] } ``` ## `encodeWitParameters` `encodeWitParameters` is a low-level helper for encoding typed values into a Wave expression string. Rather than rely on a WIT specification (e.g. `nativeToken`) for serialization, it accepts type parameters explicitly. ```ts import { encodeWitParameters } from "@kontor/kontor-sdk"; const wave = encodeWitParameters( [{ type: "string" }, { type: "decimal" }], ["bc1deadbeef", [7n, 0]], ); // "\"bc1deadbeef\", {r0: 7, r1: 0, r2: 0, r3: 0, sign: plus}" ``` Encoding a single parameter: ```ts import { encodeWitParameters } from "@kontor/kontor-sdk"; const wave = encodeWitParameters( [{ type: "bool" }], [true], ); // "true" ``` Encoding a record: ```ts import { encodeWitParameters } from "@kontor/kontor-sdk"; const wave = encodeWitParameters( [ { type: "record", components: [ { name: "acc", type: "string" }, { name: "amt", type: "decimal" }, ], }, ], [{ acc: "bc1deadbeef", amt: [42n, 18] }], ); // "{acc: \"bc1deadbeef\", amt: {r0: 42, r1: 0, r2: 0, r3: 0, sign: plus}}" ``` ## getWitItem `getWitItem` is useful for accessing a specific definitin in a contract `WIT`. ```ts twoslash import { nativeToken, getWitItem } from "@kontor/kontor-sdk"; const transfer = getWitItem({ wit: nativeToken.wit, name: "transfer", }); const burn = getWitItem({ wit: nativeToken.wit, name: "burn", }); ``` ## parseRawWit `parseRawWit` extracts WIT signature strings from a raw multi-line WIT document — the format returned by [`getContract`](/docs/actions/kontor-indexer/get-contract). The result is an array of signature strings that can be passed directly to [`parseWit`](/docs/wit/parse-wit). ```ts import { parseRawWit, parseWit } from "@kontor/kontor-sdk"; // The raw WIT string from getContract response const rawWit = ` package root:component; world root { import kontor:built-in/context; use kontor:built-in/context.{view-context, proc-context}; use kontor:built-in/error.{error}; use kontor:built-in/numbers.{decimal}; record balance { acc: string, amt: decimal, } export async mint: func(ctx: borrow, amt: decimal) -> result; export async get-balance: func(ctx: borrow, acc: string) -> option; } `; const signatures = parseRawWit(rawWit); // [ // "record balance { acc: string, amt: decimal }", // "export mint: func(ctx: borrow, amt: decimal) -> result;", // "export get-balance: func(ctx: borrow, acc: string) -> option;", // ] // Feed directly into parseWit const wit = parseWit(signatures); ``` The function handles the following automatically: * Extracts only statements inside the `world root { }` block * Skips `import` and `use` lines * Strips the `async` keyword * Normalizes multi-line definitions into single-line signatures * Cleans trailing commas in records ## parseWit `parseWit` is a crucial helper for parsing a WIT into a data structure that the SDK can understand. ```ts twoslash import { parseWit } from "@kontor/kontor-sdk"; const wit = parseWit([ "record greeting { name: string, warmth: u64 }", "export say-hello: func(ctx: borrow, name: string) -> result;", ]) ``` ## WIT & Wave Syntax WIT (WebAssembly Interface Types) defines the type system for Kontor contract interfaces. Wave is the text encoding used to serialize values in function calls. ### Primitive Types | WIT Type | TypeScript Type | Description | | ------------------ | ------------------ | ----------------------------------------- | | `bool` | `boolean` | `true` or `false` | | `string` | `string` | UTF-8 text | | `u8`, `u16`, `u32` | `number` | Unsigned integers (≤32-bit) | | `u64` | `bigint` | Unsigned 64-bit integer | | `s8`, `s16`, `s32` | `number` | Signed integers (≤32-bit) | | `s64` | `bigint` | Signed 64-bit integer | | `integer` | `bigint` | Arbitrary-precision integer | | `decimal` | `[bigint, number]` | Fixed-point decimal (significand + scale) | | `contract-address` | `string` | Contract address (e.g. `token_0_0`) | ### Compound Types #### `record` A named struct with typed fields. ```wit record balance { acc: string, amt: decimal, } ``` In TypeScript, records map to objects: `{ acc: string, amt: [bigint, number] }`. #### `variant` A discriminated union — each case may carry a payload. ```wit variant error { message(string), overflow(string), validation(string), } ``` In TypeScript, variants map to tagged tuples: `["message", string] | ["overflow", string]`. #### `enum` A simple union of string labels (no payload). ```wit enum sign { plus, minus, } ``` In TypeScript, enums map to string unions: `"plus" | "minus"`. #### `list` A variable-length array of type `T`. ```wit list ``` In TypeScript: `Array<{ acc: string, amt: [bigint, number] }>`. #### `option` A value that may or may not be present. ```wit option ``` In TypeScript: `["none"] | ["some", [bigint, number]]`. #### `result` A success-or-failure wrapper. ```wit result ``` In TypeScript: `["ok", { src: string, dst: string, amt: [bigint, number] }] | ["err", WitError]`. ### Function Signatures Contract functions are defined with `export` and `func`. The first parameter is always a context borrow that determines whether the function reads or writes state. #### `view` functions (read-only) ```wit export balance: func(ctx: borrow, acc: string) -> option; ``` #### `proc` functions (state-mutating) ```wit export transfer: func(ctx: borrow, dst: string, amt: decimal) -> result; ``` The SDK strips the context parameter — you only pass the remaining arguments: ```ts // view: pass [acc] const balance = await contract.view.balance(["some-address"]); // proc: pass [dst, amt] + compose options const result = await contract.proc.transfer( ["dst-address", [1n, 18]], { utxos: ["txid:vout"], account: ["addr", "pubkey"], gas: 1000n, satsPerVByte: 1 }, ); ``` ### Wave Expression Syntax Wave is the text encoding for WIT values, used in raw `composeTransaction` and `viewContractRaw` calls. #### Primitives ``` 42 // integer, u8–u64, s8–s64 true // bool "hello" // string ``` #### Records Fields are written as `{ field: value, ... }`: ``` {r0: 7, r1: 0, r2: 0, r3: 0, sign: plus} ``` #### Variants The active case, with its payload in parentheses: ``` message("something went wrong") ``` #### Enums Just the label name: ``` plus ``` #### Options ``` some(42) none ``` #### Lists ``` [1, 2, 3] ``` #### Function calls A function name with comma-separated arguments: ``` transfer("bc1deadbeef", {r0: 7, r1: 0, r2: 0, r3: 0, sign: plus}) balance("bc1deadbeef") ``` ## Chain A `Chain` defines the network configuration for a Bitcoin-based Kontor deployment. The SDK ships with `signet` as the built-in chain. ### `signet` ```ts twoslash import { signet } from "@kontor/kontor-sdk"; signet.name; // "Signet" ``` ### `defineChain` Use `defineChain` to create a custom chain configuration for a different network or a self-hosted Kontor indexer. ```ts import { defineChain } from "@kontor/kontor-sdk"; const myChain = defineChain({ name: "My Network", testnet: true, nativeCurrency: { name: "Bitcoin", symbol: "BTC", decimals: 8, }, networkConfig: { bech32: "tb", pubKeyHash: 0x6f, scriptHash: 0xc4, wif: 0xef, }, urls: { default: { http: ["https://my-indexer.example.com"], bitcoinRpc: ["https://my-bitcoin-rpc.example.com"], }, }, }); ``` The `Chain` type expects: * `name` — display name * `networkConfig` — Bitcoin network parameters (`bech32`, `pubKeyHash`, `scriptHash`, `wif`) * `nativeCurrency` — token metadata (`name`, `symbol`, `decimals`) * `urls` — indexer and Bitcoin RPC endpoints (must include a `default` key with `http` and `bitcoinRpc` arrays) * `testnet` — optional boolean * `blockExplorers` — optional block explorer URLs * `blockTime` — optional block time in seconds ## Decimal The `kontor-sdk` encodes decimal values as a tuple of `[ bigint, number ]`, where `bigint` encodes the significant digits, and `number` encodes the scale (i.e. number of digits to the right of the decimal point). This encoding is borrowed from the [dnum](https://github.com/bpierre/dnum) package. Accordingly, the library can be used together with the `kontor-sdk`. ```ts twoslash // @filename: indexer-client.ts import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const helloWorld = "Hi" export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), account: [ "p2tr", "x-only-public-key" ] }) // @filename: b.ts // ---cut--- import * as dn from "dnum" import { nativeToken } from "@kontor/kontor-sdk" import { indexerClient } from "./indexer-client" const composeResponse = await indexerClient.procContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", // args: ["dst-taproot-address", [1n, 18]], args: ["dst-taproot-address", dn.from(".000000000000000001") as [bigint, number]], // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ satsPerVByte: 1, utxos: [ "txid:vout" ], gas: 10n, }) console.log(indexerClient) ``` ## Option TS representations of the `WIT` `option` type have the following signature: ```ts twoslash export type Option = ["none"] | ["some", T]; ``` The following example illustrates the conversion of a raw wave expression into the `TypeScript` representation of the object. ```ts twoslash import { decodeWitParameter } from "@kontor/kontor-sdk"; const decoded = decodeWitParameter( "some({r0: 7, r1: 0, r2: 0, r3: 0, sign: plus})", // wave expression { type: "option", // wit type }, ); console.log(decoded) //[ "some", [7n, 18] ] // ts value ``` ## Result TS representations of the `WIT` `result` type have the following signature: ``` export type Result = ["ok", T] | ["err", E]; ``` ## Decode Function Result `decodeFunctionResult` parses the raw wave expression of function calls into more user friendly types. ```ts twoslash import { nativeToken, decodeFunctionResult } from "@kontor/kontor-sdk"; const decoded = decodeFunctionResult({ // ^? wit: nativeToken.wit, functionName: "total-supply", data: "raw-wave-expression" }) ``` ## Encode Function Data `encodeFunctionData` is useful for serializing contract call data into a raw wave expression. ```ts twoslash import { encodeFunctionData, nativeToken } from "@kontor/kontor-sdk"; const w1 = encodeFunctionData({ wit: nativeToken.wit, functionName: "mint", args: [[7n, 18]], }) // "mint({r0: 7, r1: 0, r2: 0, r3: 0, sign: plus})" const w2 = encodeFunctionData({ wit: nativeToken.wit, functionName: "transfer", args: ["bc1deadbeef", [7n, 18]], }) // `transfer("bc1deadbeef", {r0: 7, r1: 0, r2: 0, r3: 0, sign: plus})` ``` ## Contract Instance Instead of calling `viewContract` and `procContract` directly, you can create a contract instance which takes the WIT and `contractAddress`, resulting in a more terse syntax at the contract callsite. ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) // @noErrors contract.view. // ^| ``` ```ts twoslash import { getContractClient, signet, createKontorIndexerClient, http, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const contract = getContractClient({ wit: nativeToken.wit, contractAddress: "token_0_0", client: indexerClient, }) // ---cut--- // @noErrors contract.proc. // ^| ``` ## Introduction to Clients ### Clients The `kontor-sdk` exposes two clients for interfacing with Kontor: * The [Kontor Indexer Client](/docs/clients/kontor-indexer) * The [Kontor Wallet Client](/docs/clients/kontor-wallet) Broadly, the [Kontor Indexer Client](/docs/clients/kontor-indexer) exposes [Indexer Actions](/docs/actions/kontor-indexer/introduction) that do not require access to the user's private key, while the [Kontor Wallet Client](/docs/clients/kontor-wallet) exposes [Wallet Actions](/docs/actions/kontor-wallet/introduction) that do. ## Kontor Indexer Client The indexer client is an interface to a Kontor Indexer. It allows users to interface with smart contract data and compose transactions via [Kontor Indexer Actions](/docs/actions/kontor-indexer/introduction). ### Import ```ts twoslash import { createKontorIndexerClient } from "@kontor/kontor-sdk"; ``` ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ // [!code focus] chain: signet, // [!code focus] transport: http(), // [!code focus] }); // [!code focus] ``` From here, you can call [Kontor Indexer Actions](/docs/actions/kontor-indexer/introduction) such as [viewContract](/docs/actions/kontor-indexer/view-contract) to read contract state. ```ts twoslash import { createKontorIndexerClient, http, signet, nativeToken } from "@kontor/kontor-sdk"; const indexerClient = createKontorIndexerClient({ // [!code focus] chain: signet, // [!code focus] transport: http(), // [!code focus] }); // [!code focus] //---cut--- const totalSupply = await indexerClient.viewContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "total-supply", }) ``` ## With `webSocket` transport The indexer client can also be configured with a `webSocket` transport to enable web socket dependent actions. ```ts twoslash import { createKontorIndexerClient, http, webSocket, signet, nativeToken } from "@kontor/kontor-sdk"; const clientWithWebsocket = createKontorIndexerClient({ chain: signet, transport: webSocket(), }); clientWithWebsocket.watchEvents({ onEvent: (event) => { console.log(event); }, onError: console.log, }); // When the client is only configured with `webSocket` transport, // it is only decorated with `webSocket` actions // @noErrors clientWithWebsocket. // ^| const clientWithHttpAndWebsocket = createKontorIndexerClient({ chain: signet, transport: { http: http(), websocket: webSocket() }, }); clientWithHttpAndWebsocket.watchEvents({ onEvent: (event) => { console.log(event); }, onError: console.log, }); // When the client is only configured with `http` and `webSocket` // transport, it is decorated with `http` and `webSocket` actions. // @noErrors clientWithHttpAndWebsocket. // ^| ``` ## Kontor Wallet Client The wallet client is an interface to the necessary cryptographic operations that mediate transacting on the Kontor network via [Kontor Wallet Actions](/docs/actions/kontor-wallet/introduction) such as [signCommit](/docs/actions/kontor-wallet/sign-commit) and [signReveal](/docs/actions/kontor-wallet/sign-reveal). ### Import ```ts twoslash import { createKontorWalletClient } from "@kontor/kontor-sdk"; ``` ### JSON-RPC Accounts A JSON-RPC Account delegates cryptographic operations to browser extension wallets ( e.g. Horizon, XVerse, and Leather ). #### Usage Unfortunately, there is not a uniform standard for a Bitcoin Wallet extensions which means that it is necessary to shim browser extension APIs to provide a consistent interface which can be used internally by the SDK. Accordingly, `createKontorWallet` client expects a `custom` transport that is configured with a `request` method that conforms to the [WBIP001](https://wbips.netlify.app/wbips/WBIP001) specification. Below is an example of configuring a wallet client to work with the `Leather` browser extension. ```ts twoslash import { createKontorWalletClient, signet, custom } from "@kontor/kontor-sdk"; declare global { interface Window { LeatherProvider?: { request: (method: string, params?: any) => Promise; }; XverseProvider?: any; } } // ---cut--- const client = createKontorWalletClient({ chain: signet, transport: custom({ request: async ({ method, params }) => { if (method === "signPsbt") { const res = await window.LeatherProvider!.request("signPsbt", { hex: params.psbt, broadcast: params.broadcast, signAtIndex: params.signInputs, network: "signet", }); return { result: { psbt: res.result.hex } }; } return window.LeatherProvider!.request(method, params); }, }), }); const addresses = await client.getAddresses(); ``` ### Local Accounts It is also possible to instantiate a wallet client that has access to a local private key. #### `mnemonicToAccount` ```ts twoslash import { createKontorWalletClient, signet, custom, mnemonicToAccount } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const client = createKontorWalletClient({ account, chain: signet, // TODO: shouldn't need dummy transport transport: custom({ request: async (args: any) => {}, }), }); const addresses = await client.getAddresses(); ``` #### `hdKeyToAccount` ```ts import { HDKey } from "@scure/bip32"; import { createKontorWalletClient, signet, custom, hdKeyToAccount, } from "@kontor/kontor-sdk"; const seed = new Uint8Array([112, 111, 108, 121, 99, 114, 105, 115, 105, 115]); const key = HDKey.fromMasterSeed(seed); const account = hdKeyToAccount(key); const client = createKontorWalletClient({ account, chain: signet, // TODO: shouldn't need dummy transport transport: custom({ request: async (args: any) => {}, }), }); const addresses = await client.getAddresses(); ``` #### `privateKeyToAccount` ```ts twoslash import { createKontorWalletClient, signet, custom, privateKeyToAccount, } from "@kontor/kontor-sdk"; const account = privateKeyToAccount("0xdabdad"); const client = createKontorWalletClient({ account, chain: signet, // TODO: shouldn't need dummy transport transport: custom({ request: async (args: any) => {}, }), }); const addresses = await client.getAddresses(); ``` ## Introduction to Kontor Wallet Actions Kontor Wallet Actions require access to the user's private key. These actions are exposed via the [Kontor Wallet Client](/docs/clients/kontor-wallet). Kontor leverages a [P2TR](https://learnmeabitcoin.com/technical/script/p2tr/) commit-reveal scheme to encode contract data. The `kontor-sdk` handles idiosyncrasies that are particular to signing both the `commit` and `reveal` transactions via the [signCommit](/docs/actions/kontor-wallet/sign-commit) and [signReveal](/docs/actions/kontor-wallet/sign-reveal) actions. ## `signCommit` Signs the `commit` transaction in a `P2TR Commit Reveal Scheme`. ```ts twoslash import { createKontorIndexerClient, http, nativeToken, createKontorWalletClient, signet, custom, mnemonicToAccount } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); const composeResponse = await indexerClient.procContract({ account: ["taproot-address", "x-only-public-key"], wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10n, }) const signedCommitHex = await walletClient.signCommit({ // [!code focus] psbt: composeResponse.result.commit_psbt_hex, // [!code focus] }) // [!code focus] ``` ## `signReveal` Signs the `reveal` transaction in a `P2TR Commit Reveal Scheme`. ```ts twoslash import { createKontorIndexerClient, http, nativeToken, createKontorWalletClient, signet, custom, mnemonicToAccount } from "@kontor/kontor-sdk"; const account = mnemonicToAccount("mnemomic phrase", { networkConfig: signet.networkConfig, coinType: 1, }); const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const walletClient = createKontorWalletClient({ account, chain: signet, transport: custom({ request: async (args: any) => {}, }), }); const composeResponse = await indexerClient.procContract({ account: ["taproot-address", "x-only-public-key"], wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10n, }) const signedCommitHex = await walletClient.signCommit({ psbt: composeResponse.result.commit_psbt_hex, }) const signedRevealHex = await walletClient.signReveal({ // [!code focus] psbt: composeResponse.result.reveal_psbt_hex, // [!code focus] participantScripts: composeResponse.result.per_participant, // [!code focus] }) // [!code focus] ``` ## buildComposeQuery `buildComposeQuery` is a utility action that constructs a compose query object from an instruction, UTXOs, and fee rate. This is a lower-level building block that creates the query structure needed for composition. This action is typically used internally by higher-level actions like `composeTransaction`. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet, Instruction, } from "@kontor/kontor-sdk"; export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const composeQuery = indexerClient.buildComposeQuery({ account: ["taproot-address", "x-only-public-key"], utxos: ["txid:vout"], satsPerVByte: 1, instruction: Instruction.call({ contract: "token_0_0", expr: `balance()`, gasLimit: 10_000n, }), }); ``` ## buildInstructionQuery `buildInstructionQuery` is a low-level helper for constructing contract calls from raw wave expressions. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet, Instruction, } from "@kontor/kontor-sdk"; export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), account: ["taproot-address", "x-only-public-key"], }); const instructionQuery = indexerClient.buildInstructionQuery({ utxos: ["txid:vout"], instruction: Instruction.call({ contract: "token_0_0", expr: `transfer("bc1receiver", {r0: 100, r1: 0, r2: 0, r3: 0, sign: plus})`, gasLimit: 10_000n, }), }); ``` ## composeTransaction `composeTransaction` is a low-level action that passes a raw wave expression to the Kontor composer (together with other required arguments). It has no knowledge of a contract `WIT` specification. Accordingly, the response is not parsed. In the below, example, a `transfer` is composed on the `nativeToken` contract using a manually serialized wave expression. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet, Instruction, } from "@kontor/kontor-sdk"; export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), }); const composeOutputs = await indexerClient.composeTransaction({ account: ["taproot-address", "x-only-public-key"], utxos: ["txid:vout"], satsPerVByte: 1, instruction: Instruction.call({ contract: "token_0_0", expr: `transfer("bc1deadbeef", {r0: 7, r1: 0, r2: 0, r3: 0, sign: plus})`, gasLimit: 10_000n, }), }); ``` If you prefer not to pass the account at the `composeTransaction` call-site, it can be passed as an argument to the client. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet, Instruction, } from "@kontor/kontor-sdk"; export const indexerClient = createKontorIndexerClient({ account: ["taproot-address", "x-only-public-key"], chain: signet, transport: http(), }); const composeOutputs = await indexerClient.composeTransaction({ utxos: ["txid:vout"], satsPerVByte: 1, instruction: Instruction.call({ contract: "token_0_0", expr: `transfer("bc1deadbeef", {r0: 1, r1: 0, r2: 0, r3: 0, sign: plus})`, gasLimit: 10_000n, }), }); ``` ## `getBlock` Get a block by `hash` or `height` ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const block1 = await indexerClient.getBlock({ hash: "0000000" }) // OR const block2 = await indexerClient.getBlock({ height: 1_000_000 }) ``` ## `getContract` Returns the raw contract `WIT` as a string for a given contract address. ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const contract = await indexerClient.getContract({ contractAddress: "token_0_0" }) ``` ## getIndexerStatus `getIndexerStatus` retrieves the current status and health information of the Kontor indexer. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const status = await indexerClient.getIndexerStatus() ``` ## getLatestBlock `getLatestBlock` retrieves information about the most recent block in the blockchain. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const latestBlock = await indexerClient.getLatestBlock() ``` ## getResult `getResult` retrieves the execution result of a Kontor transaction by its result ID. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const result = await indexerClient.getResult({ id: "result_123_456" }) ``` ## getTransaction `getTransaction` retrieves detailed information about a specific transaction by its transaction ID. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transaction = await indexerClient.getTransaction({ txid: "1234567890abcdef..." }) ``` ## `inspectTransactionHex` `inspectTransactionHex` parses the Kontor `ops` contained within a hex serialized transaction. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const signedRevealHex = "..." const kontorOps = await indexerClient.inspectTransactionHex({ hex: signedRevealHex, }) ``` ## inspectTransaction `inspectTransaction` returns a list of Kontor operations for a given transaction ID. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const kontorOps = await indexerClient.inspectTransaction({ txid: "1234567890abcdef..." }) ``` ## Introduction to Kontor Indexer Actions A Kontor Indexer Action is an action that maps to a indexer http endpoint exposed by a Kontor Indexer. They do not depend on any cryptographic operations that would require the user's private key. The actions are exposed via the [Kontor Indexer Client](/docs/clients/kontor-indexer). ## listBlockTransactions `listBlockTransactions` retrieves all transactions contained in a specific block. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listBlockTransactions({ hash: "00000000000000000..." }) ``` ### By Block Height ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listBlockTransactions({ height: 1000000 }) ``` ### With Pagination ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listBlockTransactions({ hash: "00000000000000000...", limit: 10, offset: 100, order: 'desc' }) ``` ## listBlocks `listBlocks` retrieves a paginated list of blocks from the blockchain. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const blocks = await indexerClient.listBlocks({ limit: 10, offset: 0 }) ``` ### With Cursor-Based Pagination ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const blocks = await indexerClient.listBlocks({ cursor: 1000000, limit: 50, order: 'desc' }) ``` ### With Filtering ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const blocks = await indexerClient.listBlocks({ limit: 20, relevant: true, order: 'asc' }) ``` ## listContracts `listContracts` retrieves a list of deployed Kontor contracts. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const contracts = await indexerClient.listContracts() ``` ## listResults `listResults` retrieves a paginated list of Kontor transaction execution results. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ limit: 20, offset: 0 }) ``` ### With Cursor-Based Pagination ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ cursor: 1000000, limit: 50, order: 'desc' }) ``` ### Filter by Contract ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ contract: "token_0_0", limit: 50 }) ``` ### Filter by Contract and Function ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ contract: "token_0_0", func: "transfer", limit: 100 }) ``` ### Filter by Block Height ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ height: 850000, limit: 50 }) ``` ### Filter from Starting Height ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const results = await indexerClient.listResults({ start_height: 850000, limit: 50 }) ``` ## listTransactions `listTransactions` retrieves a paginated list of transactions from the blockchain. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listTransactions({ limit: 20, offset: 0 }) ``` ### With Cursor-Based Pagination ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listTransactions({ cursor: 1000000, limit: 50, order: 'desc' }) ``` ### Filter by Contract ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listTransactions({ contract: "token_0_0", limit: 100 }) ``` ### Filter by Block Height ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const transactions = await indexerClient.listTransactions({ height: 850000, limit: 50 }) ``` ## procContract The `procContract` enables a user to construct Kontor transactions in a type-safe manner. Below is an example of composing a `transfer` on the `nativeToken` contract. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) // ---cut--- const composeResponse = await indexerClient.procContract({ account: ["taproot-address", "x-only-public-key"], wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10_000n, }) // ---cut-after--- ``` If you prefer not to pass the account at the `procContract` call-site, it can be passed as an argument to the client. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ account: ["taproot-address", "x-only-public-key"], chain: signet, transport: http() }) const composeResponse = await indexerClient.procContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: "transfer", args: ["dst-taproot-address", [1n, 18]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10_000n, }) ``` ## simulateContract `simulateContract` simulates a type-safe contract function call without executing it on-chain. Unlike `simulateTransaction` which works with raw transaction hex, `simulateContract` uses WIT specifications to provide type-safe function calls and returns. ### Usage By default, `simulateContract` will return a typed `result` is specified by the contract `wit`. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), account: ["bc1sender...", "xonly-pubkey"] }) const simulation = await indexerClient.simulateContract({ wit: nativeToken.wit, contractAddress: "token_0_0", functionName: "transfer", args: ["bc1receiver...", [100n, 0]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10_000n, }) ``` ### Verbose Calling `simulateContract` with `verbose=true` will return additional metadata about the simulated call ( e.g. gas consumed ). ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http(), account: ["bc1sender...", "xonly-pubkey"] }) const simulation = await indexerClient.simulateContract({ wit: nativeToken.wit, contractAddress: "token_0_0", functionName: "transfer", args: ["bc1receiver...", [100n, 0]], satsPerVByte: 1, utxos: [ "txid:vout", ], gas: 10_000n, verbose: true }) ``` ## simulateTransaction `simulateTransaction` simulates the execution of a raw Kontor transaction without broadcasting it to the network. ### Usage ```ts twoslash import { createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const simulation = await indexerClient.simulateTransaction({ hex: "0x..." // Raw transaction hex }) ``` ## viewContractRaw `viewContractRaw` is a low-level action that passes a raw wave expression to the contract view endpoint. It has no knowledge of a contract `WIT` specification. Accordingly, the response is not parsed. In the below example, several `view` methods are called on the `nativeToken` contract using manually serialized wave expressions. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const totalSupply = await indexerClient.viewContractRaw({ contractAddress: 'token_0_0', wave: "total-supply()" }) const balance = await indexerClient.viewContractRaw({ contractAddress: 'token_0_0', wave: `balance("2c7b730daa0036e8276cdd8fabe844b2dd324a6d227dd209663805189d03e51f")` }) ``` ## viewContract The `viewContract` action makes it possible to query contract state in a fully type-safe manner. Below is an example of calling several `view` methods on the `nativeToken` contract. ```ts twoslash import { nativeToken, createKontorIndexerClient, http, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: http() }) const totalSupply = await indexerClient.viewContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', // @noErrors functionName: ' // ^| }) const totalSupply = await indexerClient.viewContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: 'total-supply', }) const userBalance = await indexerClient.viewContract({ wit: nativeToken.wit, contractAddress: 'token_0_0', functionName: 'balance', args: [ "2c7b730daa0036e8276cdd8fabe844b2dd324a6d227dd209663805189d03e51f" ] }) ``` ## watchEvents `watchEvents` subscribes to real-time Kontor indexer events via WebSocket connection. This enables applications to receive live updates about blockchain activity. It requires configuring the indexer client with `webSocket` transport. ### Usage ```ts twoslash import { createKontorIndexerClient, webSocket, signet } from '@kontor/kontor-sdk' export const indexerClient = createKontorIndexerClient({ chain: signet, transport: webSocket() }) const unsubscribe = indexerClient.watchEvents({ onEvent: (event) => { console.log('New event:', event) }, onError: (error) => { console.error('WebSocket error:', error) } }) ```