Ethereum and EVM Chains
Accept ETH, USDC, USDT, PYUSD, and EURC on Ethereum, Base, Polygon, and BNB Chain. Paste one EVM address and every invoice gets its own forwarder address that sweeps to your treasury.
All EVM chains share the same wallet type and address format. One wallet works across every EVM chain - and across mainnet and testnet.
Networks
| Network | Chain key | EVM ID | Block time | Min invoice |
|---|---|---|---|---|
| Ethereum | ETH | 1 | ~12s | $5.00 |
| Base | BASE | 8453 | ~2s | $1.00 |
| Polygon | MATIC | 137 | ~2s | $1.00 |
| BNB Smart Chain | BSC | 56 | ~0.45s | $1.00 |
| Ethereum Sepolia (testnet) | ETH_SEPOLIA | 11155111 | ~12s | $0.10 |
Finality uses each chain's finalized block tag - roughly 13-15 minutes on Ethereum and Base, a few minutes on Polygon, and a few seconds on BNB Smart Chain.
Supported coins
| Chain | Coins |
|---|---|
ETH | ETH (native), USDC, USDT, PYUSD |
BASE | ETH (native), USDC, EURC |
MATIC | POL (native), USDC, USDT |
BSC | BNB (native), USDC, USDT |
ETH_SEPOLIA | ETH (native), USDC |
The dashboard shows live contract addresses for each coin when you start a payment, so you can verify the token before paying.
Wallet setup
Paste an EVM address - 0x + 40 hex, with valid EIP-55 checksum. The dashboard validates the checksum before saving.
Do not paste a custodial exchange deposit address. Exchange deposits are shared across many users - you can't prove which payment belongs to which invoice.
Compatible wallets:
- MetaMask
- Coinbase Wallet
- Rabby
- Ledger Live
- Safe (multisig)
- Mobile wallets via their in-app browser (open the checkout link inside the wallet app)
Smart-contract wallets (Safe, Argent, Ambire) are supported. A preflight check rejects treasuries that can't receive ETH inline.
The same 0x address is valid on every EVM chain, and on their testnets, so you can reuse one address across the EVM chains you enable instead of a separate wallet per chain. See Choosing your wallets for how to keep your total wallet count low.
Open your wallet and copy the receive address.
Screenshot
MetaMask account view with the Copy address control highlighted
add image at public/images/guides/evm-metamask-copy-address.png
EVM wallets use the CREATE2 forwarder. Optionally tick Also accept gasless stablecoin payments.
Save, then complete the on-screen CREATE2 onboarding: you sign one typed-data message in your wallet, with no gas to pay, and the platform broadcasts the transactions.
CREATE2 forwarder (unique address per payment)
Every invoice gets a unique on-chain address, so there is nothing to disambiguate and the customer pays the quoted amount exactly. The platform sweeps to your registered treasury within minutes after confirmation.
The forwarder's destination is welded into its bytecode via Solady CWIA immutable args - the platform cannot redirect funds.
The wallet becomes payable only once the onboarding below is finished. Until then the chain stays out of the customer's picker.
One-time onboarding (per wallet, per chain):
Register Treasury - Prepare - the dashboard fetches the EIP-712 typed-data envelope.
Register Treasury - Submit - your wallet (MetaMask, Rabby, Ledger, or any injected EVM wallet) signs the typed-data with your control key. Default expiry 24 hours.
Finalise - after on-chain confirmation, the wallet is ready. The dashboard polls automatically and resumes after a page reload.
Treasury rotation: call Register Treasury again with a new address. The new version applies to new payments. Old versions stay readable so historical addresses always remain sweepable.
See Payment modes for how the forwarder compares with the other chain families.
Sweep state
| State | Meaning |
|---|---|
auto_pending | Confirmed. Awaiting sweep (~5 min). |
swept | Funds delivered to treasury. |
auto_failed | Sweep failed. The platform retries. |
stuck_needs_manual | Repeated failures - use Sweep manually on the payment detail page. |
manual_in_flight | You signed a manual sweep. Awaiting confirmation. |
When a payment hits stuck_needs_manual, the dashboard shows a Sweep manually button. Click it, sign the returned calldata with your own wallet, and the funds sweep to your treasury.
Native gas tokens (ETH/POL/BNB) auto-sweep inline during forwarder deployment - they cannot reach stuck_needs_manual under normal operation.
Gasless stablecoins (EIP-3009)
Customers pay supported stablecoins without holding gas. They sign a typed-data message in their wallet, and the platform relay broadcasts transferWithAuthorization on-chain. The signed message names your address as the destination - the relay cannot redirect funds.
| Chain | Gasless-eligible tokens |
|---|---|
ETH | Circle USDC, PYUSD (PayPal USD) |
ETH_SEPOLIA | Circle USDC |
BASE | Circle USDC, EURC (Euro Coin) |
MATIC | Circle USDC |
BSC | None - Binance-Peg USDC is bridged and does not implement EIP-3009 |
The signing deadline is the invoice expiry itself. On Ethereum-family chains the payment window defaults to 20 minutes from chain selection (your operator can tune it per chain). After the invoice expires, the signed authorization is no longer accepted and the customer creates a new payment.
Stackable on the CREATE2 forwarder. Enable per wallet via Also accept gasless stablecoin payments. Where your operator enables direct settlement, a gasless payment lands straight in your treasury with no sweep. See Gasless USDC.
Gas economics (CREATE2 + Gasless)
For CREATE2 and gasless stablecoin payments, the platform pays operator gas first and charges the actual cost to your Prepaid Credit. Where customer-facing pass-through is supported, each wallet has these settings:
| Setting | Default | What it does |
|---|---|---|
gas_handling_mode | smart | smart, always_absorb, or always_pass |
auto_markup_above_pct | 2.00% | In smart mode, markup customer above this percentage of payment |
always_absorb and always_pass skip the smart-mode percentage logic. Customer-facing pass-through is based on quote-time estimates. The actual operator gas cost is charged through Prepaid Credit after settlement.
Testnet (ETH_SEPOLIA)
Use a separate test wallet. Sepolia ETH and Sepolia USDC have no value.
Faucets (verified working):
- ETH: ghostchain (no auth), Chainlink (requires ~1 LINK).
- USDC: Circle (pick
ETH_SEPOLIA, 10 USDC per request). - Base Sepolia: bridge from Sepolia ETH via superbridge.app/base-sepolia or testnet.brid.gg/base-sepolia.
- BNB Smart Chain testnet: testnet.bnbchain.org/faucet-smart.
- Polygon Amoy: faucet.polygon.technology.
Common errors
| Code | When |
|---|---|
PAYMENT_MODE_CONFLICT | A legacy shared-address wallet already exists on this chain - retire it first |
INFLIGHT_CAP_EXCEEDED | Per-merchant CREATE2 in-flight USD cap exceeded - contact support |
REGISTER_TREASURY_SIG_INVALID / _HIGH_S / _MISMATCH | Signature wasn't signed by the control key, or non-canonical |
REGISTER_TREASURY_NONCE_DRIFT | On-chain nonce moved between Prepare and Submit - re-run Prepare |
TREASURY_IS_FORWARDER | Treasury cannot be a NoHoldPay forwarder address |
X402_AUTHORIZATION_EXPIRED | Customer waited too long to sign |
X402_NONCE_ALREADY_USED | Customer's authorisation was already consumed |
See also
- Choosing your wallets
- Payment modes
- Gasless USDC
- Recovery Kit - offline recovery of CREATE2 forwarders
- Payment States - lifecycle, statuses, and timing
- Webhooks - event subscriptions and signature verification
- Trust Model - what NoHoldPay can and cannot do