BSC stablecoins lack EIP-3009. Four approaches to x402 on BSC exist. We investigated each on-chain, tracing transactions, decompiling bytecode, reading source code, and verifying deployed contracts. Dexter supports two.
The default x402 EVM settlement uses EIP-3009 — transferWithAuthorization. A user signs an off-chain message. A facilitator submits it to the token contract. Tokens move. The user never pays gas.
This works on Base, Polygon, Arbitrum, Optimism, and Avalanche because Circle deployed USDC with EIP-3009 on each of those chains.
BSC has no Circle USDC. The two dominant stablecoins — Binance-Peg USDT and Binance-Peg USDC — are bridge wrappers. Standard ERC-20. No transferWithAuthorization. No permit. Calling either function reverts.
Both BSC stablecoins use 18 decimals instead of the 6 that every other chain's USDC uses, which adds another layer of incompatibility beyond the missing function.
Four approaches exist, each with a different tradeoff.
Uniswap's canonical Permit2 contract works with any ERC-20. User approves Permit2 once, then signs PermitWitnessTransferFrom authorizations. The x402ExactPermit2Proxy settles on behalf of the facilitator.
exact scheme, no SDK changes. Dexter sponsors the Permit2 approval gas — user never needs BNB. No on-chain fee caps or token restrictions at the settlement layer.Embed transferWithAuthorization into a custom contract. The client signs an EIP-3009-style authorization against the contract instead of the token. The contract then calls transferFrom on the underlying token.
Use $U by United Stables — a stablecoin that natively implements EIP-3009. The standard x402 exact scheme works as-is.
New exact-approval scheme. User approves the DexterBSCFacilitator contract once, then signs a custom EIP-712 Payment message for each transaction. On-chain fee caps, token allowlist, pause mechanism.
Permit2 was added to the upstream @x402/evm SDK in January 2026 (PR #769). It uses Uniswap's canonical Permit2 contract, deployed at the same CREATE2 address on every EVM chain, to transfer any ERC-20 regardless of whether it implements EIP-3009 or EIP-2612.
Permit2: 0x000000000022D473030F116dDEE9F6B43aC78BA3 (9,152 bytes)
x402ExactPermit2Proxy: 0x402085c248EeA27D92E8b30b2C58ed07f9E20001 (2,913 bytes)
The user signs an approve(Permit2, maxUint256) transaction locally (no gas). The Dexter facilitator broadcasts it on their behalf via the erc20ApprovalGasSponsoring extension, paying the BNB gas. The user never needs BNB. For each payment after that, the user signs an EIP-712 PermitWitnessTransferFrom message against the Permit2 contract. The signature includes a witness field containing the seller address and a time bound. The facilitator calls settle() on the x402ExactPermit2Proxy, which calls Permit2.permitTransferFrom(), which moves tokens from payer to seller.
The ExactEvmScheme class in @x402/[email protected]+ routes between EIP-3009 and Permit2 automatically based on payload type. The client checks requirements.extra.assetTransferMethod — if it's "permit2", the client builds a Permit2 payload. If absent, it builds an EIP-3009 payload. Developers using the standard SDK don't need any BSC-specific code.
Permit2 is a generic transfer mechanism. The x402ExactPermit2Proxy verifies the witness (recipient and time bounds) but does not enforce:
For most payments, Permit2's signature-based security is sufficient. For high-value or regulated settlements, the DexterBSCFacilitator contract enforces these properties on-chain.
Dexter's facilitator supports Permit2 on BSC as the standard path. The /supported endpoint returns scheme: "exact" with extra.assetTransferMethod: "permit2" for eip155:56. The facilitator also advertises erc20ApprovalGasSponsoring and eip2612GasSponsoring extensions, enabling fully gasless BSC payments from the first transaction.
AEON is a BNB Chain MVB Season 10 graduate. Their facilitator has been processing BSC payments since December 19, 2025.
Facilitator: facilitator.aeon.xyz/supported
Signer: 0xe91e0E6080B0c19C71B616E628d7B715313D5036
Proxy: 0x555e3311a9893c9b17444c1ff0d88192a57ef13e (EIP-1967)
Implementation: 0xd3326dd0933b013e78e5be6a4263480f526ce6c3 (14,846 bytes)
AEON's contract source is not public. We decompiled the implementation bytecode using Heimdall v0.9.2 and extracted all function selectors via Foundry's cast selectors.
Confirmed from bytecode constants: OpenZeppelin v5 OwnableUpgradeable, PausableUpgradeable, Initializable, SafeERC20. The contract has full EIP-3009 functions built in (transferWithAuthorization, receiveWithAuthorization, cancelAuthorization, authorizationState).
Not found in bytecode: ReentrancyGuard. The OZ ReentrancyGuard storage slot (0x9b779b17...) is absent from the entire bytecode.
We cloned AEON's public repo at github.com/AEON-Project/bnb-x402 and read the source. They fork the entire x402 SDK — their own versions of @x402/core, @x402/evm, @x402/fetch, and every HTTP framework package.
The critical code is in exact/client/scheme.ts. Their ExactEvmScheme class has two signing paths:
// Path 1: standard EIP-3009 (for tokens that support it) private async signAuthorization(authorization, requirements) { // Signs against the token contract address // Standard x402 behavior } // Path 2: BSC fallback (for tokens without EIP-3009) private async signAuthorizationNoSuperEip3009(authorization, requirements) { // Checks allowance, auto-approves if needed const domain = { name: "Facilitator", version: "1", chainId, verifyingContract: getAddress("0x555e3311a9893c9B17444C1Ff0d88192a57Ef13e"), }; // AEON's contract address, hardcoded in client source }
The standard Coinbase @x402/evm package cannot be used with AEON on BSC. It signs against the token contract address. AEON's BSC path signs against AEON's contract. Developers must install AEON's forked SDK.
The contract address is not configurable — it's a string literal in the source. The file also contains console.log debug statements in production code.
AEON has the most BSC x402 volume by a wide margin. Their contract is 14,846 bytes of compiled logic. The tradeoffs: closed source, forked SDK, no ReentrancyGuard in the bytecode, and the scheme name exact doesn't distinguish their custom BSC flow from standard EIP-3009 chains.
Milady BSC runs a facilitator at x402.milady-app.com using $U by United Stables — a stablecoin that natively implements EIP-3009 on BSC.
We traced their signer's entire transaction history using binary search on nonce count. Three transactions total.
| Date | Amount | Method | TX |
|---|---|---|---|
| Mar 7, 2026 | 0 $U (test) | transferWithAuthorization |
0x2240f0...cade03 |
| Mar 7, 2026 | 1 $U | transferWithAuthorization |
0xc8b404...c665ba |
| Mar 16, 2026 | 1 $U | transferWithAuthorization |
0xc8da01...aa1e62 |
All three are direct calls to transferWithAuthorization on the $U token contract itself. No custom contract. Standard x402 exact scheme. Works with the unmodified Coinbase SDK.
The limitation: $U is a niche stablecoin. This approach doesn't help BSC users whose funds are in USDT or USDC.
| Project | Claim | What We Found |
|---|---|---|
| Pieverse | pieUSD with EIP-3009, "first enterprise Web payment standard on BNB" | pieUSD deployed on BSC testnet only. No mainnet contract. GitHub repo is docs, not code. README from Oct 2025 promises specs "soon." |
| Unibase | "First x402 facilitator on BSC," XUSD wrapped stablecoin | No deployment. No GitHub. No contract. No evidence of any kind. |
| B402 | "First AI Agent payment standard on BNB Chain" | Referenced in trade press. No deployed contracts. No code. |
Dexter supports both paths on BSC. The facilitator registers two schemes for eip155:56:
Permit2 via the standard exact scheme with assetTransferMethod: "permit2". This uses the upstream ExactEvmScheme from @x402/[email protected], which automatically routes Permit2 payloads. No custom code on the facilitator side.
exact-approval via the DexterBSCFacilitator smart contract with on-chain fee caps, token allowlist, and pause.
Proxy: 0x3D56A1A196aC81c959A1be21ABC28c173fB063B8
Implementation: 0x4fC9f4340c72fCD238A61De314D7F5c4401a981a (6,837 bytes)
Source: DexterBSCFacilitator.sol
OpenZeppelin v5. Every feature verifiable in source:
| Feature | Detail |
|---|---|
| ReentrancyGuard | nonReentrant on executePayment |
| Pausable | Owner-callable pause() and unpause() |
| Token allowlist | allowedTokens mapping, owner setTokenAllowed() |
| Fee caps | minFee floor + MAX_FEE_BPS hard cap (5%) |
| Fee separation | Fees go to feeRecipient, not the executor wallet |
| Nonce tracking | usedNonces[user][nonce] mapping, random 128-bit nonces |
| Access control | Facilitator-only on executePayment |
| SafeERC20 | All transfers — required because BSC USDT doesn't return bool |
| Proxy | TransparentUpgradeableProxy — upgradeable without re-approval |
| Token | Amount | TX |
|---|---|---|
| USDT | 0.1 USDT | 0xdfb827...c61f23 |
| USDC | 0.1 USDC | 0xa177e4...48241b |
Both tokens. Both settled on BSC mainnet through the DexterBSCFacilitator contract. Non-custodial — safeTransferFrom(payer, seller) directly.
24 Foundry tests (Solidity) covering happy path, replay protection, expired deadline, invalid signature, access control, token allowlist, fee validation, pause/unpause, reentrancy, non-standard ERC-20, proxy initialization. 18 Vitest tests (TypeScript) for the scheme class. 95 total facilitator tests with zero regressions.
| Permit2 | AEON | Milady BSC | Dexter (exact-approval) | |
|---|---|---|---|---|
| Custom contract | x402 proxy (2.9KB, open) | Yes (14.8KB, closed) | No | Yes (6.8KB, open) |
| Non-custodial | Yes | Yes | Yes | Yes |
| Scheme name | exact | exact | exact | exact-approval |
| SDK requirement | Standard SDK | Forked SDK | Standard SDK | Plugin handler |
| Works with existing tokens | Yes (any ERC-20) | Yes | No ($U only) | Yes (allowlisted) |
| Permit2 | AEON | Milady BSC | Dexter (exact-approval) | |
|---|---|---|---|---|
| Pausable | No | Confirmed | N/A | Confirmed |
| ReentrancyGuard | N/A | Not in bytecode | N/A | Confirmed |
| Token allowlist | Any ERC-20 | Not exposed | N/A | Public mapping |
| Fee model | None at contract level | Not exposed | N/A | minFee + MAX_FEE_BPS |
| Contract source | Public | Closed | N/A | Public |
"Not exposed" means the function is not accessible via public selectors. It may exist internally. Without source code, we cannot confirm or deny. This is distinct from "Not in bytecode" which means the expected storage slot or opcode pattern is definitively absent.
Every claim in this report can be reproduced with a BSC RPC endpoint. No API keys needed. No explorer accounts. Just standard JSON-RPC.
curl -X POST YOUR_BSC_RPC -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{
"to":"0x55d398326f99059fF775485246999027B3197955",
"data":"0xe3ee160e"}, "latest"],"id":1}'
# Returns: {"error":{"code":3,"message":"execution reverted"}}
# The function does not exist on BSC USDT.
curl -X POST YOUR_BSC_RPC -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getCode","params":[
"0x000000000022D473030F116dDEE9F6B43aC78BA3","latest"],"id":1}'
# Returns non-empty bytecode (9,152 bytes). Permit2 is deployed.
curl -X POST YOUR_BSC_RPC -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getCode","params":[
"0x402085c248EeA27D92E8b30b2C58ed07f9E20001","latest"],"id":1}'
# Returns non-empty bytecode (2,913 bytes). The x402 proxy is deployed.
curl -X POST YOUR_BSC_RPC -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionCount",
"params":["0xe91e0E6080B0c19C71B616E628d7B715313D5036","latest"],"id":1}'
# AEON signer: returns 573,792+ (hex)
Standard JSON-RPC has no "get transactions by address." Use binary search:
# 1. Get nonce at different block heights to find when it incremented # 2. getBlock(blockNumber, includeTransactions=true) # 3. Find tx where from === address # 4. getTransactionReceipt(hash) for status and logs # This works on any EVM chain. No explorer API needed.
curl -X POST YOUR_BSC_RPC -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getStorageAt","params":[
"0x555e3311a9893c9b17444c1ff0d88192a57ef13e",
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
"latest"],"id":1}'
# Returns the implementation address behind AEON's proxy
# Get bytecode cast code 0xd3326dd0933b013e78e5be6a4263480f526ce6c3 --rpc-url YOUR_BSC_RPC > bytecode.hex # Extract selectors (requires Foundry) cast selectors $(cat bytecode.hex)
# OZ ReentrancyGuard uses storage slot: # 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00 # Search for this value in the bytecode. # If absent: no ReentrancyGuard. grep "9b779b17" bytecode.hex
curl -s https://facilitator.aeon.xyz/supported | jq .
curl -s https://x402.milady-app.com/supported | jq .
curl -s https://x402.dexter.cash/supported | jq '.kinds[] | select(.network == "eip155:56")'
# Dexter returns two kinds for BSC: exact (permit2) and exact-approval