On-Chain Competitive Analysis

BSC x402: Who Actually Built It, and How

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.

Published April 5, 2026 · Updated April 6, 2026 (added Permit2) · All data independently verifiable via BSC RPC
Methodology: binary search on nonce, bytecode decompilation via Heimdall v0.9.2, source analysis of cloned repos, upstream @x402/evm source analysis

Read the announcement: blog post · Integration guide: BSC chain docs

Why EIP-3009 Doesn't Work on BSC

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.

Base / Polygon / Arbitrum Payer transferWithAuthorization USDC Contract funds move Seller BSC — USDT / USDC Payer transferWithAuthorization REVERTS USDT (no EIP-3009) Four ways around Permit2: approve Permit2, sign PermitWitnessTransferFrom (standard) AEON: wrap EIP-3009 into own contract, fork SDK Milady: use $U token (has EIP-3009 natively) Dexter: approve + custom EIP-712, on-chain security (exact-approval)

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 Ways to Solve It

Four approaches exist, each with a different tradeoff.

Permit2 (Standard)

Upstream x402 / Coinbase

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.

Standard 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.

EIP-3009 Wrapper

AEON

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.

Requires a forked SDK. Client doesn't know it's not talking to the real token.

Use a Token That Has It

Milady BSC

Use $U by United Stables — a stablecoin that natively implements EIP-3009. The standard x402 exact scheme works as-is.

Users must hold $U. Does not solve the problem for USDT/USDC holders.

Hardened Approval Scheme

Dexter

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.

One-time approval tx (~$0.02). Requires custom scheme handler. On-chain fee caps, token allowlist, and pause that Permit2 does not enforce.

Permit2

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.

Deployed on BSC

Permit2: 0x000000000022D473030F116dDEE9F6B43aC78BA3 (9,152 bytes)

x402ExactPermit2Proxy: 0x402085c248EeA27D92E8b30b2C58ed07f9E20001 (2,913 bytes)

How it works

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.

What Permit2 doesn't enforce

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

AEON is a BNB Chain MVB Season 10 graduate. Their facilitator has been processing BSC payments since December 19, 2025.

573,792
Transactions on BSC
~223/hr
Current throughput
Dec 2025
First settlement

Bytecode Analysis

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.

The Forked SDK

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
}
Key finding

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

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.

DateAmountMethodTX
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.

Claims Without On-Chain Evidence

ProjectClaimWhat 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: Permit2 + exact-approval

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.

DexterBSCFacilitator — Source Public

Proxy: 0x3D56A1A196aC81c959A1be21ABC28c173fB063B8

Implementation: 0x4fC9f4340c72fCD238A61De314D7F5c4401a981a (6,837 bytes)

Source: DexterBSCFacilitator.sol

Security (exact-approval contract)

OpenZeppelin v5. Every feature verifiable in source:

FeatureDetail
ReentrancyGuardnonReentrant on executePayment
PausableOwner-callable pause() and unpause()
Token allowlistallowedTokens mapping, owner setTokenAllowed()
Fee capsminFee floor + MAX_FEE_BPS hard cap (5%)
Fee separationFees go to feeRecipient, not the executor wallet
Nonce trackingusedNonces[user][nonce] mapping, random 128-bit nonces
Access controlFacilitator-only on executePayment
SafeERC20All transfers — required because BSC USDT doesn't return bool
ProxyTransparentUpgradeableProxy — upgradeable without re-approval

Verified Settlements (exact-approval)

TokenAmountTX
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.

Test Suite

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.

Feature Comparison

Architecture

Permit2AEONMilady BSCDexter (exact-approval)
Custom contractx402 proxy (2.9KB, open)Yes (14.8KB, closed)NoYes (6.8KB, open)
Non-custodialYesYesYesYes
Scheme nameexactexactexactexact-approval
SDK requirementStandard SDKForked SDKStandard SDKPlugin handler
Works with existing tokensYes (any ERC-20)YesNo ($U only)Yes (allowlisted)

Security (from bytecode / source / contract)

Permit2AEONMilady BSCDexter (exact-approval)
PausableNoConfirmedN/AConfirmed
ReentrancyGuardN/ANot in bytecodeN/AConfirmed
Token allowlistAny ERC-20Not exposedN/APublic mapping
Fee modelNone at contract levelNot exposedN/AminFee + MAX_FEE_BPS
Contract sourcePublicClosedN/APublic

"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.

Verify It Yourself

Every claim in this report can be reproduced with a BSC RPC endpoint. No API keys needed. No explorer accounts. Just standard JSON-RPC.

1. Confirm USDT lacks EIP-3009

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.

2. Confirm Permit2 is deployed on BSC

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.

3. Confirm x402ExactPermit2Proxy is deployed on BSC

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.

4. Check any address's transaction count

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)

5. Find transactions via binary search on nonce

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.

6. Read EIP-1967 implementation slot

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

7. Extract function selectors from bytecode

# Get bytecode
cast code 0xd3326dd0933b013e78e5be6a4263480f526ce6c3 --rpc-url YOUR_BSC_RPC > bytecode.hex

# Extract selectors (requires Foundry)
cast selectors $(cat bytecode.hex)

8. Check for ReentrancyGuard

# OZ ReentrancyGuard uses storage slot:
# 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00
# Search for this value in the bytecode.
# If absent: no ReentrancyGuard.
grep "9b779b17" bytecode.hex

9. Hit facilitator /supported endpoints

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