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.
Every KleverChain studio re-implements the same four things. KleverKit is the reference, tested against real product outputs.
Klever extension & K5 mobile webview, balance reads, and a message sign-in — no signing keys ever touch your page.
Integer smallest-unit math. Floor the platform cut, remainder to the counterparty — platform + remainder === gross, always.
Pure, storage-agnostic grant/check keyed by (studio, wallet). Works behind KV, D1, or a Map. Multi-tenant by design.
One guard: money moves only when NETWORK==='testnet' and your LIVE flag is on. Secrets from env only. No mainnet path in v1.
No build step. Import the ES module in a <script type="module"> or from your Cloudflare Function.
// browser (no bundler)
import { connectWallet, feeSplit, checkEntitlement } from './kleverkit.js';const address = await connectWallet();
const session = await signIn(); // signs a login messageconst s = feeSplit(100, 300); // 100 KLV @ 3%
// → platform 3, remainder 97, grossUnits 100000000import { gate } from '../../sdk/kleverkit.js';
const g = gate(env, { liveKey: 'MINT_LIVE' });
if (g.gated) return mockReceipt(g.reason); // no money movesThis demo imports the very same kleverkit.js you'd ship. Connect a wallet, split a fee, grant a mock entitlement — no money moves.
wallet browser only · pure no I/O, runs anywhere · server env/gating
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();The currently connected address, or null. Pure read of wallet state.
const addr = getAddress();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 */ }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 }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 ] }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' });Read-only ownership check. Also available: owns(), quantityOf(), summarize(), tenantKey().
checkEntitlement(grants, 'starter-pass'); // { owns: true, quantity: 1 }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);~30 lines each. The full source is in examples/.
MintForge — buyer pays, 3% platform / 97% creator, owner-signer mint gated server-side.
examples/mint-checkout.js
PlayVault — one buyer-signed transfer, fee as royalty, multi-tenant entitlement grant & check.
examples/store-purchase.js
ArenaChain — entry fees into a pool, floored rake, zero-dust payout split, escrow-signer settle.
examples/tournament-buyin.js