◆ KleverChain SDK · v1

Ship a KleverChain product in an afternoon.

KleverKit packages the plumbing every KleverChain product re-writes — wallet connect & sign-in, zero-dust fee-split math, multi-tenant entitlements, and testnet/live gating — into one importable module. Extracted from three shipping products, consolidated to a single source.

4 core primitives
0 dust, integer units
1 ES-module import
~30 lines per checkout
What's in the box

The plumbing, already solved.

Every KleverChain studio re-implements the same four things. KleverKit is the reference, tested against real product outputs.

🔌

Wallet connect + sign-in

Klever extension & K5 mobile webview, balance reads, and a message sign-in — no signing keys ever touch your page.

🧮

Zero-dust fee split

Integer smallest-unit math. Floor the platform cut, remainder to the counterparty — platform + remainder === gross, always.

🎟️

Entitlements

Pure, storage-agnostic grant/check keyed by (studio, wallet). Works behind KV, D1, or a Map. Multi-tenant by design.

🛡️

Testnet/live gating

One guard: money moves only when NETWORK==='testnet' and your LIVE flag is on. Secrets from env only. No mainnet path in v1.

Quickstart

From zero to a gated checkout.

No build step. Import the ES module in a <script type="module"> or from your Cloudflare Function.

Import the SDK

// browser (no bundler)
import { connectWallet, feeSplit, checkEntitlement } from './kleverkit.js';

Connect the wallet

const address = await connectWallet();
const session = await signIn();  // signs a login message

Split the fee (zero dust)

const s = feeSplit(100, 300);  // 100 KLV @ 3%
// → platform 3, remainder 97, grossUnits 100000000

Gate the write on the server

import { gate } from '../../sdk/kleverkit.js';
const g = gate(env, { liveKey: 'MINT_LIVE' });
if (g.gated) return mockReceipt(g.reason); // no money moves
Live · testnet · gated

Run the SDK, right here.

This demo imports the very same kleverkit.js you'd ship. Connect a wallet, split a fee, grant a mock entitlement — no money moves.

Not connected testnet
Enter an amount and press “Compute fee split”.
Connect a wallet, then grant & check an entitlement.
🛡️ Gated by design. Everything here is testnet + mock. A real grant needs NETWORK==='testnet', your LIVE flag on, and an on-chain tx to verify — see the gating model in the README.
API reference

Every function, copy-paste ready.

wallet browser only · pure no I/O, runs anywhere · server env/gating

connectWallet() → Promise<string>
wallet

Connect the Klever extension or K5 mobile webview and return the address. Throws with a .code (NOT_INSTALLED, NO_ADDRESS, …) on failure.

const addr = await connectWallet();
getAddress() → string | null
wallet

The currently connected address, or null. Pure read of wallet state.

const addr = getAddress();
signIn(message?) → Promise<{ address, message, signature, mocked }>
wallet

Connect (if needed) and sign a login message to prove wallet ownership. Falls back to a mocked session if the provider can't signMessage, so testnet flows still work.

const session = await signIn();
if (session.signature) { /* verified sign-in */ }
feeSplit(amount, bps=300, { quantity=1, precision=6 }) → Split
pure

Split amount in integer smallest-units. The platform takes bps basis points (floored); the counterparty gets the exact remainder. platformUnits + remainderUnits === grossUnits — zero dust.

feeSplit(100, 300);
// { grossUnits: 100000000, platformUnits: 3000000,
//   remainderUnits: 97000000, platform: 3, remainder: 97, pct: 3 }
splitPool(pool, bps=800, weights=[50,30,20], { precision=6 }) → PoolSplit
pure

Distribute a pool N ways after a floored rake — largest-remainder so the winners' amounts sum EXACTLY to the distributable. The tournament payout leg.

splitPool(80, 800, [50, 30, 20]);
// { rake: 6.4, distributable: 73.6, payouts: [ …3 places ] }
grantEntitlement(grants, { studioId, wallet, itemId, itemType?, qty=1, txHash?, ts? }) → { grants, grant }
pure

Validate and merge a grant into a tenant's list (qty accumulates by itemId). Returns a NEW list — persist it behind KV/D1/Map. No Date.now() inside: pass ts to stay pure.

let { grants } = grantEntitlement([], {
  studioId: 'onyxrealms', wallet: addr, itemId: 'starter-pass' });
checkEntitlement(grants, itemId) → { owns: boolean, quantity: number }
pure

Read-only ownership check. Also available: owns(), quantityOf(), summarize(), tenantKey().

checkEntitlement(grants, 'starter-pass'); // { owns: true, quantity: 1 }
gate(env, { liveKey='LIVE' }) → { network, testnet, live, gated, reason, nodeApi, platformBps, platformAddress }
server

The shared safety gate. gated===true means: do not move money, return a mock. Live requires NETWORK==='testnet' AND your product's LIVE flag on. Pair with readSigner(env, 'MINT_SIGNER_KEY') — keys from env only.

const g = gate(env, { liveKey: 'STORE_LIVE' });
if (g.gated) return mock(g.reason);
Examples

Three products, rebuilt on the SDK.

~30 lines each. The full source is in examples/.

⛏️

Mint checkout

MintForge — buyer pays, 3% platform / 97% creator, owner-signer mint gated server-side.

examples/mint-checkout.js

🎮

Store purchase

PlayVault — one buyer-signed transfer, fee as royalty, multi-tenant entitlement grant & check.

examples/store-purchase.js

🏆

Tournament buy-in

ArenaChain — entry fees into a pool, floored rake, zero-dust payout split, escrow-signer settle.

examples/tournament-buyin.js