Skip to content

About

WDK protocol module for wallet auth: pre-transaction, condition-based access for tetherto/wdk wallets. Powered by InsumerAPI.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

25 Commits

Folders and files

@insumermodel/wdk-protocol-wallet-auth

npm License: Apache-2.0

Wallet auth for WDK wallets. OAuth proves who you are. Wallet auth proves what you hold.

The wallet auth primitive (read → evaluate → sign → keep) 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-auth

Provisioning 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/create with { 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 to the platform wallet, then POST /v1/keys/buy with the transaction hash and senderSignature, the paying wallet's signature over a short text naming the payment (a call without it returns the exact text). The wallet that paid is the identity. 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. Purchases are paid in USDC only, on Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, BNB Chain or Solana. USDT, Bitcoin and Tron are not accepted.

Send the USDC to the platform wallet for your chosen chain, then POST /v1/credits/buy with { txHash, chainId, amount }. A first top-up, or one that changes the registered wallet, also carries senderSignature from the wallet that paid. 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 implementation
  • WalletAuthProtocol: 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 signature + its key id (additive)
// result.jwt / pqJwt: ES256 JWT form and its post-quantum sibling, when requested
// result.creditsRemaining: credits remaining on the API key

Supported 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), erc7710_delegation (delegation validity on Base), and account_code (the code state of the wallet address itself on any EVM chain: expect is "none" for a plain key account, "eip7702" for the EIP-7702 delegation designator, or "contract" for any other code; with "eip7702" an optional delegate address is met only when the designator points at it; the code and the delegation target are never returned). 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: 155 base checks across 27 chains in 10 dimensions (stablecoins, governance, nfts, staking, institutional_stablecoins, tokenized_treasuries, stablecoin_deposits, wrapped_bitcoin, names, account), rising to up to 176 checks across 29 chains in 14 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 155, 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. The account dimension has two rows per chain on Ethereum, Base, Arbitrum, Optimism and Polygon, "Contract code on X" and "EIP-7702 delegation on X"; a plain key reads false on both, and which contract is there is never named. Dimensions come back in a fixed order: the base ten as listed, then solana, xrpl, bitcoin, tron when switched on. trust.conditionSetVersion is a dated set id (currently "2026-10-08"), 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 (155 here, 176 with every optional address), totalPassed, totalFailed, totalNotEvaluated, dimensionsWithActivity, dimensionsChecked (10 here, 14 with every optional address)
// pqSig / pqKid    : ML-DSA-65 post-quantum signature + its key id (insumer-trust-pq1), additive

Verification

Every attestation and trust result is signed twice: ES256 and a post-quantum ML-DSA-65 signature (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 post-quantum signature as a fifth verdict:

https://insumermodel.com/.well-known/jwks.json

Use 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 fetch implementation 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.

About

WDK protocol module for wallet auth: pre-transaction, condition-based access for tetherto/wdk wallets. Powered by InsumerAPI.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages