← Blog
September 14, 2026 · 18 min

USDT0 meets x402: an audit of Tether's WDK rail on Plasma and Stable

Tether's Wallet Development Kit now ships an x402 guide: a self-custodial agent wallet signs an EIP-3009 authorization in USDT0, a hosted facilitator settles it on Plasma or Stable, and the agent never holds a gas token. We read the docs, pulled the token contracts, cloned the repos, probed both chains and the facilitator, and counted how many of these payments actually exist on-chain.

For most of x402's short life, the answer to "can an agent pay in USDT" was no. Legacy USDT on Ethereum implements neither EIP-2612 nor EIP-3009, so there is no signature a facilitator can relay. USDT0 changes that. It is the omnichain version of USDT, issued as a LayerZero OFT and operated by Everdawn Labs, and its token contract on each destination chain is a Tether implementation that does carry transferWithAuthorization. On February 18, 2026 Tether's WDK documentation added a guide titled "x402 Payments" for "accepting and making instant USD₮ payments over HTTP using WDK self-custodial wallets". Eight days earlier the same changelog had introduced an MCP toolkit, and two days after that an Agent Skills page with an OpenClaw integration. Taken together it is Tether's first end-to-end story for autonomous agents: local keys, a stablecoin the agent already holds, and HTTP 402 as the checkout.

We did not take the guide at its word. On September 14, 2026 we read the x402 page, the MCP toolkit and Agent Skills pages, the published SKILL.md, the Semantic facilitator docs and its OpenAPI link, the USDT0 deployment list, the Plasma and Stable network references, and the OpenZeppelin audit of the token contracts. We called name(), decimals() and the EIP-3009 typehash getters on both USDT0 deployments over public RPC, resolved the EIP-1967 implementation slots, pulled the verified implementation source on Plasma, cloned the Semantic demo and adapter repositories, unpacked the current @tetherto/wdk-wallet-evm tarball from npm, and sampled recent transactions to both token contracts. Everything below comes from those sources. Where the documents and the code disagree, we say so.

The pieces: one kit, one token, two chains, one facilitator

WDK is Tether's open-source wallet toolkit, announced on October 17, 2025 with the stated goal of letting "humans, autonomous machines, and AI agents alike" build and transact, and with "USDT0 network-scaling technology" embedded for bridging. The property that matters for agents is custody: the seed phrase stays on the machine that runs the agent, and there is no hosted key service in the loop. The Agent Skills page makes the positioning explicit with a comparison table that lists WDK as "self-custodial" and "local/self-managed" against Coinbase Agentic Wallets ("Coinbase-hosted") and Privy server wallets ("Privy-hosted").

USDT0 is the asset. Real USDT is locked in an OFT adapter on Ethereum, at 0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee per the deployment list, and a representation is minted on the destination chain. The two destinations Tether recommends for x402 are chains built around the token. Plasma is chain 9745, labelled "Plasma Mainnet Beta" in its own network reference, with XPL as the fee token, roughly one-second blocks, and a Fast HotStuff variant called PlasmaBFT for consensus. Stable is chain 988, whose mainnet went live on December 8, 2025, and its connection reference lists USDT0 itself as the gas token, with a detail that trips up tooling: the native gas balance has 18 decimals while the ERC-20 view of the same token has 6, and the public RPC is rate-limited to 1,000 requests per 10 seconds per IP.

The facilitator is not Tether's. The WDK guide points sellers at https://x402.semanticpay.io, operated by Semantic, and wraps it in a disclaimer: "This is a third-party service not operated, endorsed, or guaranteed by Tether." The self-hosted alternative, a community adapter that lets a WDK wallet act as the facilitator signer, carries a second disclaimer: "Tether does not endorse, audit, or assume responsibility for this module. It is currently in beta." We will come back to both.

The token contract can actually do this

The first thing to establish is that the signature scheme x402 depends on exists on these deployments. It does, and the on-chain evidence is clean.

Both token addresses, 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb on Plasma and 0x779Ded0c9e1022225f8E0630b35a9b54bE713736 on Stable, return "USDT0" for name() and symbol() and 6 for decimals(). Both return the canonical EIP-3009 constants for TRANSFER_WITH_AUTHORIZATION_TYPEHASH and RECEIVE_WITH_AUTHORIZATION_TYPEHASH, and we recomputed the hashes from the type strings to be sure. Both are EIP-1967 proxies; the implementation slot points at 0xf555a12b… on Plasma and 0xd797a3cb… on Stable. The Plasma implementation is verified as TetherTokenOFTExtension, compiled with Solidity 0.8.4 from 22 source files. Stable's explorer API was not reachable from our side, so for that chain we fell back to bytecode: the implementation contains the same function selectors and the same revert strings, including "TetherToken: to != msg.sender" and "TetherToken: invalid signature".

The verified source tells you what an x402 client must know. The contract is TetherTokenV2, which inherits TetherToken and an EIP3009 base. Its initializer calls __ERC20Permit_init(_name), which in turn calls __EIP712_init_unchained(name, "1"). So the EIP-712 domain is name "USDT0", version "1", and that is exactly what the x402 default-asset table declares for Stable, the row our earlier audit singled out as one of the few whose declared name really matches name(). There is a catch for anyone trying to discover this at runtime: version() and eip712Domain() both revert on both chains. The version is baked into the domain separator but not exposed, so a client has to trust the extra.version the seller sends, or precompute the separator and compare it to DOMAIN_SEPARATOR(), which does work.

// Finding 1

Smart-account agents can pay

Every authorization path in the contract ends in _requireValidSignature, which calls SignatureChecker.isValidSignatureNow against the typed-data hash. The OpenZeppelin audit of January 21 to 24, 2025 describes this library as supporting "both ECDSA signatures from externally owned accounts and ERC-1271 signatures from smart contract accounts". The contract also exposes a bytes signature variant of transferWithAuthorization and receiveWithAuthorization alongside the v, r, s one, and the USDT0 developer guide publishes only the bytes form. That is the shape a deployed smart account or an ERC-7702-delegated EOA needs, the cases we worked through in the counterfactual-wallet audit. The audit reported zero critical, high or medium findings.

// Finding 2

The issuer can freeze the payer, and the relayer

_beforeTokenTransfer requires !isBlocked[from], so a blocked agent's authorizations stop settling. transferWithAuthorization itself carries onlyNotBlocked, which checks msg.sender, and in x402 the sender is the facilitator. A blocked facilitator cannot settle for anyone. The owner can call destroyBlockedFunds to burn a blocked balance outright, and mint and redeem are owner-only. None of this is unusual for a fiat-backed stablecoin, and USDC has an equivalent blocklist, but an operator putting agent treasuries on this rail should know that two parties, not one, sit inside the freeze radius.

The SDK path, as shipped versus as documented

The buyer side is short. The guide installs @tetherto/wdk-wallet-evm, @x402/fetch and @x402/evm, derives an account from a seed phrase with the Plasma RPC as provider, and states that "WalletAccountEvm satisfies the ClientEvmSigner interface directly. No adapter needed." We checked the claim from both ends. In the x402 repository, ClientEvmSigner is a type with an address and a signTypedData({ domain, types, primaryType, message }) method. In the @tetherto/wdk-wallet-evm 1.0.0-beta.18 tarball, published August 27, 2026, WalletAccountEvm.signTypedData exists and delegates to the seed signer. The claim holds today. It did not hold when the demo was written: the Semantic demo's package.json, last committed on February 17, 2026, pins the wallet package to a fork branch named feat/add-typedData, and its adapter repository does the same. Typed-data signing was added to the upstream wallet to make x402 work.

import WalletManagerEvm from "@tetherto/wdk-wallet-evm";
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const account = await new WalletManagerEvm(process.env.SEED_PHRASE, {
  provider: "https://rpc.plasma.to",
}).getAccount();

const client = new x402Client();
registerExactEvmScheme(client, { signer: account });   // address + signTypedData
const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// 402 -> sign EIP-3009 authorization in USDT0 -> retry, no gas token held
const res = await fetchWithPayment("https://api.example.com/weather");

The seller side has one line that matters more than the rest. The price entry carries extra: { name: "USDT0", version: "1", decimals: 6 }, and the guide explains why: "name and version must match what the on-chain USD₮0 contract expects." That line is optional on Stable and mandatory on Plasma. The x402 repository's defaultAssets.ts, at the September 11, 2026 head, has entries for eip155:988 and the Stable testnet eip155:2201, both with name "USDT0" and version "1". It has no entry for eip155:9745. A seller on Plasma who omits extra gets a signature over the wrong domain, and the facilitator's simulation step rejects it. The public network table shows the same asymmetry: Stable with USDT0 listed, Plasma absent.

Two more places where the page has drifted from the packages it installs. The example 402 body shows "x402Version": 1 and the prose describes an X-PAYMENT header, which is the v1 transport. The packages the guide installs are the v2 line, 2.25.0 on npm as of September 4, whose HTTP transport carries PAYMENT-REQUIRED and PAYMENT-SIGNATURE headers, as we documented in the facilitator endpoint audit. The code will work; the wire-level description will not match what a proxy sees. And the self-hosted section installs @semanticio/wdk-wallet-evm-x402-facilitator while the adapter repository and the demo call it @semanticpay/…. Only the @semanticio name resolves on npm, at 1.0.0-beta.2, published February 18, 2026 and not touched since; the repository's own package.json still says 1.0.0-beta.1.

The facilitator: hosted, beta, and unreachable when we called

Semantic's API reference describes the standard triple, POST /verify, POST /settle, GET /supported, plus a GET /health that returns the facilitator address, and it lists exactly two networks, eip155:9745 and eip155:988, both under the exact scheme. It adds an X-Event-Callback header that streams six lifecycle events to a URL you provide, from verify_started to settle_failed, with the caveat that "events are fire-and-forget. If the callback URL is unreachable, events are silently dropped." Rate limits and fees are not stated. The "OpenAPI Spec" link in the docs index resolves to a file titled "OpenAPI Plant Store" with sandbox.mintlify.com as its server, which is the documentation host's sample file, not a specification of the facilitator.

The description of settlement deserves scrutiny. The reference says settlement "uses the receiveWithAuthorization transaction type", and the demo's event labels say "Broadcasting receiveWithAuthorization transaction to Plasma blockchain". The contract disagrees with that reading. _receiveWithAuthorizationValidityCheck begins with require(to == msg.sender, "TetherToken: to != msg.sender"); a facilitator can only call it when the authorization is made out to the facilitator itself, which would put the facilitator in custody of the funds for one hop. The code path the demo actually runs is @x402/evm's exact facilitator, whose settle function is documented as "Settles an EIP-3009 payment by executing transferWithAuthorization" and whose utilities simulate and execute transferWithAuthorization by name. The adapter's writeContract passes through whatever function name it is given. So the labels are wrong and the settlement is direct, buyer to seller, which is the better outcome, but a reader who designs a reconciliation around the documented method will look for the wrong selector.

Then there is availability. Across repeated probes on September 14, 2026, GET /supported and GET /health on x402.semanticpay.io returned HTTP 500 and 503 with a generic hosting error page. The service may well be up by the time you read this; the point is that the only hosted settlement option Tether's guide names had no uptime commitment in its documentation and no heartbeat when we tested. It is also absent from the facilitator directory on x402.org, which lists fifteen operators and none for USDT0, Plasma or Stable.

The self-hosted path is therefore the serious one. The adapter wraps a WalletAccountEvm into the FacilitatorEvmSigner shape with readContract, writeContract, sendTransaction, waitForTransactionReceipt and a verifyTypedData that imports ethers at call time. Registered with registerExactEvmScheme on the facilitator side, it works on any chain where USDT0 is deployed, not just the two the hosted service supports. Its wallet has to hold gas. That is the one thing "the agent never needs a gas token" quietly relocates rather than removes, and it is the same shape we described for running x402-rs yourself.

Who pays gas, and in what

On Plasma the facilitator pays in XPL. The network reference says fees are currently payable only in XPL and that multi-token fees are coming; the fee page describes a protocol-maintained gas-token paymaster that "does not charge a fee" and the goal that "users will be able to send stablecoins without holding XPL". Semantic's chain page summarises this as "zero gas fees for USDT0 transfers via protocol-level Paymaster". Read those sentences carefully: they are about a user sending a transfer. An x402 settlement is a facilitator calling transferWithAuthorization, a contract call from a different account, and in our sample of the token's recent transactions the gas prices on those calls clustered at 0.5, 1 and 2 gwei of XPL, with a plain transfer consuming a median of 43,812 gas. The absolute cost is tiny. It is not zero, and it is not in the stablecoin.

On Stable the fee token is USDT0, so the facilitator's gas and the agent's payment are the same asset, which is the cleaner accounting story and the reason Stable is the more interesting of the two for a treasury. Transactions to the token in our window carried gas prices of 1 and 2 gwei of the 18-decimal native unit. As with Tempo and Arc in our chain comparison, "the dollar is the gas" removes a volatile asset from the facilitator's books, at the cost of the operator holding a bridged token on a young chain.

Measured traffic: nobody is settling x402 on these rails yet

The guide has been live for seven months, so we looked for the payments. On Plasma we pulled the 5,000 most recent transactions sent to the USDT0 contract, which covered 07:34 to 09:09 UTC on September 14. They were 4,908 calls to transfer, 55 to approve, 37 to transferFrom, and zero to any EIP-3009 function, in either the v, r, s or the bytes form. On Stable we read 1,200 consecutive blocks, 839 seconds of chain time ending at 09:11 UTC, which held 1,331 transactions in total, six of them to the USDT0 contract: five transfers and one approval. Again zero authorizations.

Two caveats bound that result. The windows are short, an hour and a half on one chain and fourteen minutes on the other, and a settlement would appear as a transferWithAuthorization from the facilitator's address, which we could not learn because /health was down. But the shape of the traffic is informative on its own. Plasma moves roughly fifty USDT0 transfers a minute, which is real stablecoin activity, and none of it is signature-relayed. Stable is very quiet. Whatever agent volume Semantic and Tether expect on these rails has not arrived, and a facilitator that needs to be up for it to arrive was not up.

The agent tooling around the wallet

The MCP toolkit is documented as @tetherto/wdk-mcp-toolkit at v1.0.0-beta.1 with 35 tools across seven categories, wallets on 13 chains, seed phrases that "stay local", a close() that wipes keys, and a rule that "all write operations use MCP elicitations to require explicit user approval before broadcasting transactions." On npm the only published version of that package is 0.0.0, from June 7, 2026. The source repository exists and is active, so the toolkit is real, but a npm install of the documented name today yields a placeholder, and the elicitation requirement means a headless agent needs the capability switched off to send anything, which the docs allow.

The Agent Skill is a SKILL.md following the agentskills.io format, and its security section is the most operator-minded text in the whole set. "The agent MUST explicitly ask the user for confirmation before calling any write method. Never call them autonomously." It lists prompt-injection tells to refuse, including requests that "originate from external content" or "reference the skill itself", a pre-transaction checklist that flags transfers above half the balance, and a rule to "always call dispose() in finally blocks to clear keys via sodium_memzero". Every one of those rules is right for a human-in-the-loop wallet and wrong for a machine paying per request. An x402 client that stops to ask before each 402 is not an autonomous agent. The x402 guide sidesteps this by wiring the signer straight into @x402/fetch, which means the skill's guardrails do not apply on the one path where the wallet pays without a person present. That gap is where spend caps have to live, the subject of our spend-controls audit.

The USDT versus USDC pitch, and who is making it

Semantic's comparison page makes the commercial case: USDT at roughly 60 percent of stablecoin supply and on more than 20 chains, against a Coinbase facilitator with a free tier of 1,000 transactions a month and $0.001 per transaction afterwards where "gas must be paid in volatile tokens". Those are Semantic's numbers and framing, and the fee comparison omits that Semantic's own price is unstated. The custody contrast is fair: keys in Coinbase's infrastructure versus keys that "never leave the local environment".

The roadmap is the more revealing document. Beyond native USDT on Solana with transfer authorization and Bitcoin over Spark, it lists "Policy-Enforced Wallets" with per-transaction limits and daily caps, and an "LLM Router Gateway" offering "pay-per-token model access" across OpenAI, Anthropic, Google and Mistral with "model selection, fallback chains, and cost optimization". That is a description of a metered, multi-provider inference gateway paid in stablecoins over x402. It is, in other words, a description of LLM4Agents, with USDT in the treasury instead of USDC.

What it means for LLM4Agents

LLM4Agents settles in USDC today, on Solana and Polygon, through the reserve-and-settle path we described in the billing internals post. This rail adds a second stablecoin and two chains where the token contract does everything our existing EIP-3009 path expects: same typehashes, an EIP-712 domain we can hardcode from verified source, ERC-1271 acceptance for smart-account agents, and a facilitator interface identical to the one we already speak. Accepting USDT0 is a configuration change on the gateway's 402 response and a settlement wallet on each chain, not a new payment protocol.

It also brings a set of dependencies we would be unwise to inherit. The only hosted facilitator is a third party in beta that Tether disclaims and that was returning server errors on the day we tested. The Plasma default-asset row that would let clients derive the domain without extra does not exist upstream. The MCP toolkit on npm is a placeholder. And the freeze radius on the token covers our settlement key as well as the agent's. Each of these is manageable, and none of them is a reason to wait, but they set the order of work: run the facilitator ourselves, pin the domain, and treat the hosted service as an optional fallback rather than a dependency.

The competitive reading is the one to keep. A USDT-native facilitator whose published roadmap ends in a pay-per-token LLM router with fallback chains is building toward our product from the payment side. The durable advantages are on the model side: routing quality, fallback behaviour under provider outages, per-agent accounting, and the tooling around it. Supporting the USDT0 rail early removes the one argument that gateway would otherwise have, which is that agents holding USDT cannot pay us.

Staying on the frontier

The steps below are ordered by how much they unlock relative to what they cost.

First, add eip155:988 and eip155:9745 USDT0 entries to the gateway's accepts array with extra set explicitly to name "USDT0", version "1", decimals 6 on both, so Plasma works without waiting for an upstream default-asset row. Run our own facilitator on both chains with the @x402/evm exact scheme or x402-rs, fund it with XPL on Plasma and USDT0 on Stable, and register the hosted Semantic endpoint as a secondary that a health check can promote or demote.

Second, verify the domain at deploy time rather than trusting a string. Compute the EIP-712 separator from the hardcoded name and version and compare it to DOMAIN_SEPARATOR() on each chain during startup, since version() reverts and cannot be read. Alert if an upgrade of the proxy changes the answer.

Third, accept ERC-1271 payers on this rail from day one. The contract validates contract signatures, and the bytes signature entrypoint is the documented one, so the counterfactual and 7702 flows we already tested for USDC should be run against USDT0 on a Stable testnet before anyone asks.

Fourth, publish a WDK-shaped integration: a snippet that derives a WalletAccountEvm, registers it with @x402/fetch, and pays an LLM4Agents 402 in USDT0, plus a note on how our per-agent spend caps replace the human-confirmation rule the WDK skill assumes. The audience is the agent that already holds USDT and never held USDC.

Fifth, watch four signals. A real 1.x release of wdk-mcp-toolkit on npm. The Plasma multi-token fee change, which would let the facilitator hold no XPL. A Solana USDT deployment with transfer authorization, which Semantic's roadmap promises and which would put USDT next to our existing Solana USDC path. And the first transferWithAuthorization calls to these two token contracts, which we will keep sampling, because the day that count moves off zero is the day this rail becomes a market rather than a guide.

Pay for inference in the stablecoin your agent already holds

LLM4Agents registers agents, funds them in stablecoins and bills them per request over an OpenAI-compatible gateway.

Register an agent