@confidentialkit/sdk
v0.2.0
Published
Ergonomic TypeScript SDK for Solana Token-2022 Confidential Balances.
Maintainers
Readme
@confidentialkit/sdk
Ergonomic TypeScript SDK for Solana Token-2022 Confidential Balances, built on
the audited @solana/zk-sdk WASM
module. It parses the on-chain confidential-transfer account state and decrypts
balances — the read/inspect path that powers debugging (the missing
spl-token --decrypt, token-2022#145).
All cryptography is delegated to
@solana/zk-sdk. This package never implements ElGamal/AES itself — it provides parsing, ergonomics, and lifecycle management around the audited primitives.
Install
npm install @confidentialkit/sdkNetwork-free. This package makes no network calls — pass it account bytes you already have. To fetch from an RPC, use
@confidentialkit/kit'sinspectConfidentialAccount, or your own RPC client +decodeConfidentialAccount.
Usage
Decode account bytes (offline / browser)
import { decodeConfidentialAccount } from "@confidentialkit/sdk";
// Inspector mode — raw ciphertexts, no keys needed:
const raw = await decodeConfidentialAccount(accountData);
console.log(raw.state.ciphertexts);
// With owner keys — decrypted balances:
const result = await decodeConfidentialAccount(accountData, { keys: { aeKey, elgamalSecret } });
console.log(result.availableBalance, result.pendingBalance);Fetch + decode via RPC (using @confidentialkit/kit)
import { createSolanaRpc } from "@solana/kit";
import { inspectConfidentialAccount } from "@confidentialkit/kit";
const rpc = createSolanaRpc("http://127.0.0.1:8899");
const result = await inspectConfidentialAccount(rpc, accountAddress, { aeKey });
console.log(result.availableBalance);Decrypt a single ciphertext
import { decryptAeCiphertext, decryptElGamalCiphertext } from "@confidentialkit/sdk";
const available = await decryptAeCiphertext(aeCiphertext, aeKey);
const pendingLo = await decryptElGamalCiphertext(elgamalCiphertext, elgamalSecret);Derive keys from a wallet signature
import {
elgamalSignerMessage,
deriveElGamalSecretFromSignature,
} from "@confidentialkit/sdk";
const message = await elgamalSignerMessage(accountAddressBytes);
const signature = await wallet.signMessage(message); // 64-byte ed25519
const elgamalSecret = await deriveElGamalSecretFromSignature(signature);Browser usage
The Node WASM build loads automatically. In a browser, inject the bundler/web build once at startup:
import { setZkModule } from "@confidentialkit/sdk";
setZkModule(await import("@solana/zk-sdk/bundler"));Notes
- Available balance is read from the AES "decryptable" ciphertext (instant,
exact) using the AES key. Pending balance is reconstructed from the
lo/hiElGamal ciphertexts using the ElGamal secret (a bounded discrete-log search — fast for small pending balances). - Confidential transfers hide amounts, not identities.
- This SDK covers the read path. On-chain transfer construction is gated on the ZK ElGamal proof program being re-enabled — see the repo roadmap.
MIT
