Tokens and networks
Exported from tokens.ts and networks.ts.
Token
TokenSchema/Token — currently 'USDC' | 'USDT'. Payment availability is resolved per token, network, and environment. live currently enables both tokens on Base, Optimism, Polygon, Ethereum, Arbitrum, Avalanche, and BNB Chain, USDC only on Arc, and USDT only on TRON. test has USDC on Base Sepolia, Optimism Sepolia, Ethereum Sepolia, and Arc Testnet, and USDT on TRON's Nile testnet — no other configured test deployments beyond those (BNB Chain has no test deployment at all — 0xSplits has no BNB testnet). An unconfigured or disabled pair is rejected with 422 token_not_supported. Use GET /v1/networks for the current server's accepted matrix before creating a charge.
Arc has no USDT deployment at all (Circle's own chain; only USDC/EURC/USYC are supported there) — getTokenDeployment('USDT', 'arc', ...) always returns undefined, same as querying any other never-configured combination. TRON is the mirror case — no USDC deployment researched/added there yet, only USDT (TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t on mainnet, TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf on Nile testnet, both 6 decimals, both independently verified live against the real chains). Arc's USDC is also structurally different from every other network's: it's Arc's own native gas asset, not a separately-deployed contract — the address recorded in TOKEN_DEPLOYMENTS is a fixed system address exposing an "optional ERC-20 interface" over that native balance (identical on Arc mainnet and testnet). Its recorded decimals is 6, matching that ERC-20 interface — not the native balance's own 18 decimals, which this package's TokenDeployment never exposes.
Resolve the contract and its decimals together
TokenDeployment is { address: `0x${string}`; decimals: number }. TOKEN_DEPLOYMENTS maps Token → Network → Environment to this metadata. Network and environment entries are optional: an absent entry means the combination is unknown, with no default contract or decimal count.
getTokenDeployment(token, network, environment) returns that metadata or undefined. isPaymentDeploymentEnabled(token, network, environment) returns whether the cataloged deployment is enabled by this package's payment policy. The API's GET /v1/networks remains authoritative for the running server; clients can be on an older package version.
ts
import {
getTokenDeployment,
isPaymentDeploymentEnabled,
} from '@klappay/types/constants'
const deployment = getTokenDeployment('USDC', 'base', 'live')
if (!deployment || !isPaymentDeploymentEnabled('USDC', 'base', 'live')) {
throw new Error('Payment deployment unavailable')
}
const tokenContract = deployment.address
const decimals = deployment.decimalsEvery configured deployment outside BNB Chain uses 6 decimals. Both configured BNB Chain contracts use 18 decimals:
| Token | BNB Chain live contract | Decimals | Payments enabled |
|---|---|---|---|
| USDC | 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d | 18 | Yes |
| USDT | 0x55d398326f99059fF775485246999027B3197955 | 18 | Yes |
Both addresses are Binance-Peg assets, with Binance custody/backing risk; neither entry should be represented as direct Circle or Tether issuance. The BNB Chain token catalog identifies these addresses and their 18-decimal precision. Token symbols alone do not identify a contract, issuer, or decimal count.
Compatibility exports
TOKEN_ADDRESSES: Record<Token, Partial<Record<Network, Partial<Record<Environment, `0x${string}`>>>>> is a compatibility address-only view derived from TOKEN_DEPLOYMENTS. An address being present is not sufficient to offer a payment method: resolve the metadata and check availability with isPaymentDeploymentEnabled separately.
TOKEN_DECIMALS (6) is deprecated and unsafe for general token conversion. It remains exported for source compatibility with older consumers, but BNB's configured tokens do not use that precision. Migrate payment preparation, amount formatting, and raw-value validation to the resolved TokenDeployment.decimals. Removing this legacy export requires a future breaking release.
Index TOKEN_ADDRESSES[token][network]?.[environment] and handle undefined. Test and live refer to different chains, so metadata must never fall back from one environment to the other.
Network
NetworkSchema/Network — 'base' | 'optimism' | 'polygon' | 'ethereum' | 'arbitrum' | 'avalanche' | 'bnb' | 'tron' | 'arc'. This is the full type — every one of these values is a valid Network for reading/filtering (e.g. ListChargesInput.network). solana used to be part of this type but was removed entirely (not just left non-operational) once there was no near-term plan to wire it. tron and arc were onboarded at the type/schema level before either joined OPERATIONAL_NETWORKS — the deliberate "accepted but not yet operational" pattern the next genuinely new chain should reuse too. Both are operational now — see OPERATIONAL_NETWORKS below.
OPERATIONAL_NETWORKS (readonly ['base', 'arbitrum', 'optimism', 'polygon', 'ethereum', 'avalanche', 'bnb', 'arc', 'tron']) and its matching OperationalNetwork type describe the networks wired into the code. CreateChargeSchema.acceptedPayments checks membership, but this list does not override per-deployment payment availability — a pair must also exist for the API key's environment and pass isPaymentDeploymentEnabled; otherwise creation rejects it with 422 token_not_supported. tron accepts POST /v1/charges requests, but its actual self-hosted node infrastructure (tron-nodes) isn't deployed to a real VPS yet — a TRON charge fails cleanly with 503 rpc_unavailable until it is (see docs/payments.md's "TRON detection" section in the main klap-core docs).
NETWORK_FAMILIES (Record<Network, 'evm-official' | 'tron'>) — which split-address family a network belongs to. A charge predicts one split address up front and reuses it across every network it accepts, which is only safe when they all resolve that address through the same split factory. acceptedPayments can only ever list networks from one family — mixing them is rejected with 400 validation_error. Every officially-supported 0xSplits network is 'evm-official' — Arc included, since 0xSplits deployed its official contracts there — so Arc can be mixed with any other EVM network in one charge. Tron has its own, temporary, self-hosted split factory instead, so it's never interchangeable with an 'evm-official' network.
EVM_NETWORKS (readonly ['base', 'optimism', 'polygon', 'ethereum', 'arbitrum', 'avalanche', 'bnb', 'arc']) and its matching EvmNetwork type. tron is the one Network value not in this list — everything else is EVM-based (Arc included; see NETWORK_FAMILIES). Use this to guard any logic that assumes an EVM-style address/RPC.
NETWORK_LABELS: Record<Network, string> — display names ('Base', 'Optimism', ...) for UI use.
NETWORK_EXPLORERS: Record<Network, string> — each network's block explorer base URL (e.g. https://basescan.org), used to build a direct transaction link yourself from Charge.txHash (e.g. ${NETWORK_EXPLORERS[network]}/tx/${charge.txHash}).
CHAIN_IDS: Record<EvmNetwork, Partial<Record<Environment, number>>> — the numeric chain ID for each network/environment pair (e.g. 8453 for Base mainnet, 84532 for Base Sepolia) — the same IDs a wallet's wallet_switchEthereumChain or an RPC provider expects (EIP-155). Partial on Environment for the same reason as TOKEN_ADDRESSES: not every network has a test chain ID (only base, optimism, ethereum, and arc do — see Token above for why).
Zero-dependency constants: @klappay/types/constants
Every plain constant and resolver on this page (TOKEN_DEPLOYMENTS, getTokenDeployment, isPaymentDeploymentEnabled, TOKEN_ADDRESSES, TOKEN_DECIMALS, ALT_TOKEN_ADDRESSES, ALT_TOKEN_DECIMALS, EVM_NETWORKS, OPERATIONAL_NETWORKS, NETWORK_FAMILIES, NETWORK_LABELS, NETWORK_EXPLORERS, CHAIN_IDS) is also available from a second entry point, @klappay/types/constants, that carries zero Zod in its bundle — useful for a browser/wallet-side bundle that only needs the plain values and doesn't want to pay for the schema-validation code that ships with the main @klappay/types entry. Everything it exports is identical to (and stays in sync with) the same name imported from @klappay/types — the subpath is a smaller bundle of the same values, not a separate or alternate copy:
ts
import { CHAIN_IDS, ALT_TOKEN_ADDRESSES } from '@klappay/types/constants'See also
charges.md— whereToken/Networkare actually used (CreateChargeInput.acceptedPayments,Charge.acceptedPayments/paidWith), andGET /v1/networks(CapabilitiesSchema) — the live version of this same matrix, scoped to your API key'senvironment, rather than the full type-level listing on this page.
