@insumermodel/wdk-protocol-wallet-auth
v0.2.8
Published
WDK protocol module for wallet auth — cryptographically signed, pre-transaction condition-based access. OAuth proves who you are; wallet auth proves what you hold. Powered by InsumerAPI.
Maintainers
Readme
@insumermodel/wdk-protocol-wallet-auth
Wallet auth for WDK wallets. OAuth proves who you are. Wallet auth proves what you hold.
The wallet auth primitive (read → evaluate → sign) packaged for Wallet Development Kit apps. Pre-transaction, condition-based access. Given a wallet and a set of on-chain conditions, it returns a cryptographically signed pass/fail (attest) or a multi-dimensional trust profile (trust). Results are ECDSA P-256 signed and verifiable offline against a public JWKS — no secrets, no identity-first, no static credentials. It composes with WDK's transaction policy engine as a signed condition, and works standalone anywhere else.
Powered by InsumerAPI. attest() covers 37 chains: 31 EVM networks (Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, BNB, Robinhood Chain, and the rest of the major EVM set) plus Solana, XRPL, Bitcoin, Tron, Stellar, and Sui. (Bitcoin is token_balance on native BTC only; Tron, Stellar, and Sui are token_balance only.) trust() is a curated profile spanning the 27 to 29 chains where its dimensions live (see below). Works today on every WDK surface that overlaps: wdk-wallet-evm, wdk-wallet-solana, and wdk-wallet-btc. TON and Lightning/Spark are on the roadmap. WDK apps on those runtimes can still call attest() / trust() against any supported address the user holds.
Why this exists
WDK shipped a local transaction policy engine in beta.11 (wdk.registerPolicy(...)) — the enforcement layer that gates write-facing operations before a wallet signs. A policy rule's ALLOW/DENY decision runs a condition: a function that answers "should this operation proceed?" The engine deliberately leaves that function to you.
This package is that condition. attest() is an async, on-chain, cryptographically signed check you drop straight into a policy rule — so apps don't hand-roll balance / NFT / staking reads per policy. The engine is default-deny on governed accounts, so the idiomatic shape is an ALLOW gated on the check passing (which is also fail-closed for free: if the call throws, the ALLOW simply doesn't match and the op is denied). This snippet targets WDK 1.0.0-beta.16 and later, where conditions receive the call's arguments as args:
import WalletAuth from '@insumermodel/wdk-protocol-wallet-auth'
const walletAuth = new WalletAuth({ apiKey: process.env.INSUMER_API_KEY })
wdk.registerPolicy({
id: 'counterparty-trust',
name: 'Counterparty must pass wallet auth',
scope: 'project',
rules: [{
name: 'allow-transfer-if-counterparty-passes',
operation: 'transfer',
action: 'ALLOW',
// Conditions read the call's arguments from `args`; a transfer's recipient is args[0].recipient
conditions: [async ({ args }) =>
(await walletAuth.attest({
address: args[0].recipient,
conditions: [{ type: 'token_balance', contractAddress: '0xA0b8...', chainId: 1, threshold: '1000' }]
})).passed
]
}]
})It also works standalone, with or without WDK — call attest() / trust() directly before broadcasting:
import InsumerWalletAuthProtocol from '@insumermodel/wdk-protocol-wallet-auth'
const walletAuth = new InsumerWalletAuthProtocol({ apiKey: process.env.INSUMER_API_KEY })
const { passed, sig, kid } = await walletAuth.attest({
address: '0xCounterparty...',
conditions: [
{ type: 'token_balance', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', chainId: 1, threshold: '1000', label: 'USDC >= 1000' }
]
})
if (!passed) throw new Error('counterparty failed wallet auth check')
// `sig` and `kid` are the audit trail: anyone can verify this later against the JWKS.Use cases:
- Agent-wallet guardrails. WDK explicitly targets "humans, machines and AI agents." When an autonomous agent holds keys, the operator wants programmable constraints the agent can't argue its way around — and a cryptographic audit trail the operator can verify after the fact.
- Receive-side trust display. Before a creator accepts a payment, show a trust profile on the sending wallet. Native fit for products like Rumble Wallet.
- Compliance cover for consumer apps built on WDK. Drop-in Travel Rule / sanctions / counterparty-risk screen.
Install
npm install @insumermodel/wdk-protocol-wallet-authProvisioning a key
Two ways to provision an API key. Either flow ships 10 free attestation credits, enough to exercise the module end-to-end before paying anything.
- Email signup (human-managed wallet apps):
POST /v1/keys/createwith{ email, appName, tier: "free" }, or use the form at insumermodel.com. No credit card. - On-chain (autonomous agent operating its own WDK wallet): send USDC, USDT, or BTC to the platform wallet, then
POST /v1/keys/buywith the transaction hash. The transaction sender wallet is the identity, the payment is the auth. No email, no human in the loop.
Set the resulting key as INSUMER_API_KEY in your runtime.
Topping up credits
Top up an existing key on-chain via POST /v1/credits/buy — no Stripe, no fiat. Supported payment rails:
- USDC or USDT on any major EVM chain (Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, BNB, and more) — the endpoint auto-detects which stablecoin you sent.
- USDC on Solana.
- BTC on Bitcoin mainnet.
Send the transfer to the platform wallet for your chosen chain, then POST /v1/credits/buy with { txHash, chainId, amount }. Credits post as soon as the transaction is verified on-chain. See the OpenAPI spec for the full request shape.
API
The package exports:
InsumerWalletAuthProtocol(default export) — the InsumerAPI implementationWalletAuthProtocol— the abstract base class (implement your own backend)IWalletAuthProtocol— the interface
new InsumerWalletAuthProtocol(options)
| Option | Type | Description |
|-----------|-----------|-------------|
| apiKey | string | Required. InsumerAPI key. |
| account | object | Optional WDK wallet account. When bound, its getAddress() is used as the default subject. |
| baseUrl | string | Override the API base URL. Defaults to https://api.insumermodel.com. |
| fetch | fetch | Override the fetch implementation (useful in Bare / React Native runtimes). |
attest(options) → Promise<AttestResult>
Evaluates one to ten on-chain conditions against a wallet and returns a cryptographically signed pass/fail. Maps to POST /v1/attest.
const result = await walletAuth.attest({
address: '0x1234...', // defaults to bound account
conditions: [
{ type: 'token_balance', contractAddress: '0xA0b8...', chainId: 1, threshold: '1000' },
{ type: 'nft_ownership', contractAddress: '0xBC4C...', chainId: 1 }
],
// Non-EVM conditions need their matching address field:
// solanaAddress, xrplAddress, bitcoinAddress, tronAddress, stellarAddress, suiAddress
jwt: true, // optional: also return an ES256 JWT
merkleProof: true // optional: include EIP-1186 Merkle storage proofs (2 credits instead of 1)
})
// result.passed — true only if every condition is met
// result.attestation — full attestation object (per-condition results, block info, condition hash)
// result.sig / result.kid — ECDSA P-256 signature + key id (verify against JWKS)
// result.pqSig / pqKid — ML-DSA-65 post-quantum companion + its key id (additive)
// result.jwt / pqJwt — ES256 JWT form and its post-quantum sibling, when requested
// result.creditsRemaining — credits remaining on the API keySupported condition types: token_balance, nft_ownership (33 of the 37 chains: 31 EVM + Solana + XRPL), eas_attestation, farcaster_id, evm_view_call, ratio_to_amount, ratio_to_supply, erc8004_agent (agent registration on Base), and erc7710_delegation (delegation validity on Base). Supported chains: 37 (31 EVM networks plus Solana, XRPL, Bitcoin, Tron, Stellar, and Sui). Each non-EVM chain needs its address passed in the matching option (solanaAddress, xrplAddress, bitcoinAddress, tronAddress, stellarAddress, suiAddress). decimals on a condition is optional and best left out: the token's own decimals are always read from the chain, and if sent it is only a cross-check (a value that differs from the token's own decimals is rejected with a 400). See the InsumerAPI OpenAPI spec for the full schema.
trust(options) → Promise<TrustResult>
Returns a multi-dimensional trust profile: 145 base checks across 27 chains in 9 dimensions (stablecoins, governance, nfts, staking, institutional_stablecoins, tokenized_treasuries, stablecoin_deposits, wrapped_bitcoin, names), rising to up to 166 checks across 29 chains in 13 dimensions when the optional solanaAddress, xrplAddress, bitcoinAddress and tronAddress are supplied (each adds its own dimension: solana 14 checks, xrpl 3, bitcoin 1, tron 3). stellarAddress and suiAddress add no dimension: their rows are already among the 145, inside institutional_stablecoins (and tokenized_treasuries for USDY on Sui), and are evaluated once the matching address is supplied; until then each stays in the signed profile with evaluated: false. The Solana and XRPL rows inside the base dimensions behave the same way. Every check is a presence check. trust.conditionSetVersion is a dated set id (currently "2026-10"), signed with the profile, that names the check list run: log it, never reject on it. The profile is signed as a whole. Maps to POST /v1/trust.
const { trust, sig, kid, pqSig, pqKid } = await walletAuth.trust({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
solanaAddress: '...', // optional, adds the 14-check solana dimension
xrplAddress: '...', // optional, adds the xrpl dimension (RLUSD, USDC, OUSG)
bitcoinAddress: '...', // optional, adds the bitcoin dimension (native BTC)
tronAddress: '...', // optional, adds the tron dimension (USDT, USD1, WBTC)
stellarAddress: '...', // optional, lets the Stellar rows evaluate (no new dimension)
suiAddress: '...' // optional, lets the Sui rows evaluate (no new dimension)
})
// trust.id — TRST-XXXXX profile id
// trust.dimensions: per-dimension checks (one signature covers the whole profile)
// trust.summary — totalChecks, totalPassed, dimensionsWithActivity
// pqSig / pqKid : ML-DSA-65 post-quantum companion + its key id (insumer-trust-pq1), additiveVerification
Every attestation and trust result is ECDSA P-256 signed, and since September 2026 also carries an ML-DSA-65 post-quantum companion (pqSig, pqKid; pqJwt beside jwt). The signature (sig) and key id (kid) let any party verify the result offline, without calling the API, using the public JWKS, which holds the EC key under three kids and the post-quantum key under two RFC 9964 AKP entries; insumer-verify 1.8.1+ reports the companion as a fifth verdict:
https://insumermodel.com/.well-known/jwks.jsonUse any standard JOSE/JWT library, or npm install insumer-verify for a convenience wrapper.
Supported environments
- Node.js ≥ 18 (uses the built-in
fetch) - Bare / React Native runtimes (pass a
fetchimplementation in the constructor) - Browsers (CORS is enabled on
api.insumermodel.com)
License
Apache-2.0. See LICENSE.
Maintainer
Built by Douglas Borthwick. Issues and contributions welcome at the GitHub repo.
