Tether's Wallet Development Kit ships Swap, Bridge, Lending, and Fiat protocols. It does not ship a pre-transaction policy layer. Here is one, as a first-class WDK protocol module, installable from npm.
The gap
Tether's Wallet Development Kit (WDK) is the open-source toolkit that powers tether.wallet, Rumble Wallet, and any other multi-chain self-custodial wallet built on its modular plug-in framework. It is explicitly designed for "humans, machines, and AI agents."
Out of the box, WDK exposes four protocol categories alongside its wallet modules: Swap (Velora), Bridge (USDT0/LayerZero), Lending (Aave), and Fiat (MoonPay). Each is a typed interface that wallet apps compose into their UX.
What is missing is the layer that runs before any of those: a pre-transaction check. Given a wallet and a set of on-chain conditions, return a cryptographically signed yes or no. Before signing a transfer, before approving a contract call, before letting an autonomous agent broadcast anything at all. That primitive is what wallet auth already provides for backends — we just hadn’t yet packaged it as a native WDK module. For the pre-transaction framing in an agent context specifically, see Before an Agent Pays: Wallet Auth for Agentic Commerce.
The fifth protocol
We shipped @insumermodel/wdk-protocol-wallet-auth — a WDK protocol module that adds a new category: Wallet Auth. Same shape as Swap, Bridge, Lending, and Fiat. Two methods, two jobs:
attest({ address, conditions })— evaluate 1–10 on-chain conditions against a wallet, get back a signed pass/fail attestation. Maps to POST /v1/attest.trust({ address })— get a multi-dimensional trust profile: 36+ signed checks across stablecoins, governance, NFTs, and staking. Maps to POST /v1/trust.
Install it like any other WDK protocol module:
npm install @insumermodel/wdk-protocol-wallet-auth
And use it before any state-changing call:
import WalletAuth from '@insumermodel/wdk-protocol-wallet-auth'
const walletAuth = new WalletAuth({ apiKey: process.env.INSUMER_API_KEY })
// Before broadcasting a transfer, verify the counterparty:
const { passed, sig, kid } = await walletAuth.attest({
address: counterparty,
conditions: [
{
type: 'token_balance',
contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
chainId: 1,
threshold: 1000,
decimals: 6,
label: 'USDC >= 1000'
}
]
})
if (!passed) throw new Error('counterparty failed wallet auth check')
// sig + kid are the audit trail: verifiable offline against the JWKS.
That is the complete surface. Twenty lines is generous — the real surface is three: construct, call, check the boolean. Everything else the module does — bound account resolution, multi-chain address routing, error envelope unwrapping, optional JWT output, optional EIP-1186 Merkle proofs — is plumbing.
The napkin version, collapsed into one line:
if (!(await walletAuth.attest({ address, conditions })).passed) block()
Same operation. Block is whatever your app does when a check fails — throw, redirect, refund, tell the user to top up. The protocol itself doesn’t prescribe the reject path. It just tells you, with a signature, what the right answer is.
Why this matters for WDK wallets
There are three distinct buyers for a pre-transaction check inside a self-custodial wallet, and WDK touches all three:
1. Agent wallets. WDK's own framing puts "machines and AI agents" alongside humans. When an autonomous agent holds keys, the operator wants programmable constraints the agent cannot argue its way around — and a cryptographic audit trail the operator can verify after the fact. "Only send to counterparties that pass trust check X" is a real constraint. The signed attestation is the receipt.
2. Consumer apps on WDK rails. A creator-payment tool like Rumble Wallet, a remittance app, a treasury product — any WDK-based app that serves end users and wants compliance cover needs something between "user clicks send" and "transaction broadcasts." Travel Rule. Sanctions. Counterparty risk. A drop-in module that returns a cryptographically verifiable attestation is cheaper than building it in-house and, crucially, portable — the attestation survives outside the wallet.
3. Receive-side trust display. The most interesting call is not on your own send, it is on someone else's incoming payment. A creator wants to know the wallet sending them money is not freshly funded from a mixer. A merchant wants to know the incoming USDT is not about to be frozen. That is trust() on the inbound address, surfaced in the UI before the user accepts the payment.
Why it fits WDK's shape
WDK's protocol modules are not hooks or middleware. They are typed interfaces that wallet apps compose into their own flow. Swap has quoteSwap() and swap(). Lending has supply(), borrow(), repay(). Each is a verb the app calls when it needs that capability.
WalletAuthProtocol follows the same pattern. The app calls attest() or trust() before the action it wants to gate. The protocol itself never touches private keys, never signs transactions, never broadcasts. It runs before the signing flow, not inside it. This matters: it means the module is additive and composable with every other WDK protocol, not a replacement or a wrapper.
The abstract base class (WalletAuthProtocol) is shape-compatible with WDK's existing SwapProtocol, BridgeProtocol, LendingProtocol, and FiatProtocol base classes in @tetherto/wdk-wallet/protocols. It is intentionally structured so that it can be proposed upstream as a blessed fifth protocol category. The reference implementation (InsumerWalletAuthProtocol) is a clean subclass that any WDK app can install from npm today.
What gets signed
Every attest() result carries an ECDSA P-256 signature and a key ID. Every trust() result does the same. Verification is offline — any JOSE or JWT library can check the signature against the public JWKS at insumermodel.com/.well-known/jwks.json. There is no server call, no account, no API key required to verify. Only to create.
If you ask for jwt: true, the attestation also comes back as a standard ES256 JWT with the signed result as JWT claims. That turns the output into a drop-in bearer token: Kong, Nginx, Cloudflare Access, or AWS API Gateway can verify it the same way they verify any other JWT, without knowing anything about wallet auth at all.
Supported chains
InsumerAPI covers 33 chains today: 30 EVM networks (Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, BNB, and the rest of the major EVM set), plus Solana, XRPL, and Bitcoin. WDK’s own chain coverage overlaps heavily with this — every EVM chain you hit via wdk-wallet-evm is already attestable today, same with wdk-wallet-solana and wdk-wallet-btc, and the module also covers XRPL natively even though WDK doesn’t yet ship an XRPL wallet module.
Three WDK surfaces do not yet have InsumerAPI coverage: TRON, TON, and Lightning/Spark. Apps on those runtimes can still use attest() and trust() against EVM, Solana, XRPL, or Bitcoin addresses the user holds — they just can’t yet condition on, say, a TRC-20 balance. Those three chains are on our roadmap and the request shape will stay identical when they land.
The request shape is already identical across everything that is covered. EVM, Solana, Bitcoin, and XRPL addresses ride in their own fields (wallet, solanaWallet, bitcoinWallet, xrplWallet) and the module routes them automatically based on each condition’s chainId. For the deeper rationale on why the interface stays the same across four completely different chain architectures, see Native Bitcoin Support: Verify BTC Holdings Across All Address Formats.
Paying for it
The free tier ships 10 attestation credits to every new key so you can kick the tyres end-to-end before spending anything. When a wallet app needs more, credits are purchased on-chain — no Stripe, no fiat rails, no signup flow. The POST /v1/credits/buy endpoint accepts transfers of USDC or USDT on any major EVM chain (auto-detected from the transaction), USDC on Solana, or BTC on Bitcoin, and credits post as soon as the transaction confirms on-chain. Same rails the wallets themselves run on.
Where next
The package is public on npm and GitHub, and the README has the full API reference. Three things on the roadmap:
- Upstream proposal. The
WalletAuthProtocolbase class is intentionally a clean extension of the@tetherto/wdk-wallet/protocolspattern. The next step is proposing it upstream as a blessed fifth protocol category on the WDK repo. - React Native and Bare runtimes. The module uses
globalThis.fetchby default and accepts afetchoverride, so it already works in WDK's React Native and Bare Kit environments. A first-party example in wdk-starter-react-native is the natural next doc. - Receive-side widget. The most visually obvious use case — a small trust badge surfaced in the wallet UI when a payment comes in — is a UI component, not a protocol. That will ship separately, layered on top of the protocol module.
If you are building a wallet on WDK and any of the three buyer profiles above apply, the module is one install away. And if you are on Tether's side of the fence and want to see Wallet Auth land in the official protocol base classes, open an issue on the repo and let us know.
OAuth proves who you are. Wallet auth proves what you hold. WDK now has both sides of the flow.
Install it now
npm install @insumermodel/wdk-protocol-wallet-auth. Get a free API key with 10 credits, try one attest() call in under a minute.