Kache SDK
@kache/sdk is a tiny, dependency-free TypeScript library for integrating the
Kache wallet into a web app. It covers both surfaces the extension exposes:
Kaspa L1 via window.kache, and the Kasplex / Igra EVM L2s via a standard
EIP-1193 window.ethereum. It handles the injection race for you, so you can
call connect() on page load without waiting.
If you'd rather talk to the raw providers directly, see How to Integrate.
Install
npm install @kache/sdk
Quick start
import { connect, getAccount, getBalance, signMessage, sendKaspa, kasToSompi } from '@kache/sdk';
// Opens the Kache approval popup; resolves once the user approves.
const { address } = await connect();
const account = await getAccount(); // 'kaspa:…' (or null if not connected)
const balance = await getBalance(); // sompi as a string
const sig = await signMessage('Login to Acme #42');
const { txid } = await sendKaspa(address, kasToSompi('1.5')); // 1.5 KAS
The top-level helpers wait for the extension to inject (they listen for the
kache#initialized event), so calling connect() immediately on page load
won't race the injection.
Detect and wait explicitly
For finer control — showing an "install Kache" prompt, or a custom timeout — use
isInstalled() and getProvider():
import { isInstalled, getProvider } from '@kache/sdk';
if (!isInstalled()) {
// Prompt the user to install Kache.
}
const kache = await getProvider(5000); // wait up to 5s for injection, else throws
await kache.connect();
Grab the provider once with getProvider() when you need to subscribe to events
from the very first tick, or unsubscribe synchronously — the top-level on/off
helpers await the provider, so an event fired in that gap could be missed.
API
| Function | Description |
|---|---|
connect() | Request connection. Opens an approval popup. → { address } |
disconnect() | Forget this site's connection. |
getAccount() | Active kaspa: address if connected, else null. No popup. |
getBalance() | Confirmed balance in sompi (string). No popup. |
signMessage(msg) | Sign a message (KIP-0005). Opens an approval popup. → hex |
sendKaspa(to, amountSompi) | Request a KAS transfer. Opens an approval popup. → { txid } |
getProvider(timeoutMs?) | Resolve the raw window.kache provider once injected (default 3000ms). |
isInstalled() | true if Kache injected its provider. |
kasToSompi(kas) / sompiToKas(sompi) | Unit helpers (1 KAS = 100,000,000 sompi). |
Every function is exported both as a top-level helper and, for the wallet methods,
on the object returned by getProvider().
Units
Amounts are always in sompi (bigint or string), never floating-point KAS.
Convert at the edges:
import { kasToSompi, sompiToKas, SOMPI_PER_KAS } from '@kache/sdk';
kasToSompi('1.5'); // 150000000n
sompiToKas('150000000'); // '1.5'
SOMPI_PER_KAS; // 100000000n
kasToSompi throws on more than 8 decimal places — it never silently
truncates a send amount. Prefer passing a string for user-entered amounts; a
JS number can't represent every 8-decimal value exactly.
EVM L2 (Kasplex / Igra)
On the Kaspa L2s, Kache injects a standard EIP-1193 window.ethereum provider and
announces it via EIP-6963. The SDK's EVM helpers discover Kache specifically
(by its com.kache.wallet rdns), so they never return another wallet's provider.
import { connectEvm, getChainId, switchChain, IGRA_MAINNET } from '@kache/sdk';
const [account] = await connectEvm(); // eth_requestAccounts → 0x… address
const chainId = await getChainId(); // e.g. 202555 (Kasplex)
await switchChain(IGRA_MAINNET.id); // hop to Igra
You can also hand the raw provider to any EIP-1193 library (viem, wagmi, ethers):
import { getEthereumProvider } from '@kache/sdk';
import { createWalletClient, custom } from 'viem';
const provider = await getEthereumProvider();
const client = createWalletClient({ transport: custom(provider) });
| Function | Description |
|---|---|
connectEvm() | Request L2 connection. Opens a popup. → string[] of 0x accounts |
getEvmAccounts() | Authorized 0x accounts (empty if not connected). No popup. |
getChainId() | Active L2 chain id as a decimal number. |
switchChain(id) | Switch the active L2 (Kasplex ↔ Igra). |
personalSign(msg, addr) | personal_sign with the active account. Opens a popup. |
sendEvmTransaction(tx) | eth_sendTransaction. Opens a popup. → tx hash |
getEthereumProvider(ms?) | Kache's raw EIP-1193 provider once injected. |
isEvmInstalled() | true if Kache injected its EVM provider. |
getChain(id) | Look up a supported chain by decimal or hex id. |
The chain constants KASPLEX_MAINNET, IGRA_MAINNET, KASPLEX_TESTNET, and
IGRA_TESTNET (plus KACHE_EVM_CHAINS) carry each network's id, hex id, RPC URL,
explorer, and native currency — so you never hardcode them.
Subscribe to EVM events (accountsChanged, chainChanged, disconnect) on the
provider from getEthereumProvider(). accountsChanged carries a string[]
(empty when disconnected) — unlike the L1 accountsChanged below, which carries a
single address or null.
Events (Kaspa L1)
Subscribe through the provider so you never miss the first event:
import { getProvider } from '@kache/sdk';
const kache = await getProvider();
kache.on('accountsChanged', () => { /* re-read getAccount() */ });
kache.on('disconnect', () => { /* user disconnected the site */ });
accountsChanged fires with the new address, or null when the newly-selected
wallet hasn't approved your site — treat null as disconnected until it
reconnects.
Authentication & security
The SDK is a thin client over the injected provider and never sees your keys — you only ever get an address, a signature, or a txid, and every signature or transfer requires explicit user approval in Kache.
An address from connect()/getAccount() is not proof of identity. For
login, always verify a signMessage signature server-side against the claimed
address — don't trust the address alone. Likewise, confirm a txid on-chain
before crediting anything.
When the real extension is installed it defines window.kache as non-writable at
document_start, so it can't be overridden by the page — but a look-alike could
exist if Kache isn't installed, which is why server-side signature verification
matters.
Links
- npm:
@kache/sdk - Source & issues: github.com/KacheWallet/kache-sdk