A browser-based testnet harness for the @kwespay/client SDK. Connect a wallet, pick a network and token, and run a $0.01 end-to-end payment against the testnet backend.
kwespay-testnet/
├── index.html # Shell, markup, tab layout
├── style.css # All styles
├── config.js # API key, vendor ID, test amount
├── networks.js # Chain definitions, token addresses, getTokenInfo()
├── utils.js # formatUnits(), fetchNativeBalance(), fetchTokenBalance()
├── ui.js # Every DOM read/write — no business logic
├── main.js # App entry point — wires wallet, SDK, UI together
└── wallet.js # WalletConnector + WalletError (EIP-1193 wrapper)
Single source of truth for environment values.
Set apiKey and vendorIdentifier before running.
visit https://app.kwespay.xyz/ to create a vendor and generate API keys
Static registry of supported testnets.
Each entry holds chainId, native currency metadata, RPC/explorer URLs, and a tokens map of { address, decimals }.
Exports getTokenInfo(network, token) — safe fallback to the zero address if a token is unknown.
Pure, stateless helpers with no DOM or SDK imports.
| export | description |
|---|---|
formatUnits(raw, decimals) |
BigInt → human-readable string |
fetchNativeBalance(wallet, address) |
eth_getBalance via EIP-1193 |
fetchTokenBalance(wallet, address, tokenAddress, zeroAddress) |
ERC-20 balanceOf or native fallback |
All DOM writes are funnelled through here.
main.js calls these functions; it never touches document directly.
| export | description |
|---|---|
log(msg, type) |
Appends a timestamped line to the log panel |
setWalletConnected(address) |
Updates dot, address, button visibility, pay button state |
setWalletDisconnected() |
Resets wallet UI and hides fee section |
updateNetworkDisplay(network) |
Syncs the params panel network/chain-id fields |
updateTokenAddr(network, token) |
Updates the token address display |
renderTokenPicker(network, token, onSelect) |
Re-renders token buttons, attaches click handler |
updateBalanceDisplay(network, token, tokenBal, nativeBal) |
Writes balance rows |
updateFeeBreakdown(amountBaseUnits, tokenBalance, decimals, token) |
Shows/updates the fee breakdown section |
showResults({ txHash, blockNumber, ... }) |
Populates and reveals the result grid |
setResultStatus(status) |
Updates only the status cell during polling |
setPayButton(state) |
"running" / "idle" / "complete" |
Entry point. No DOM writes — delegates everything to ui.js.
Owns selectedNetwork, selectedToken, and lastQuoteAmount as module-level state.
Sequence on Run Payment Test:
- Switch chain if needed
client.validateKey()client.quote()client.pay()withonStatusforwarded tolog()pollStatus()— callsclient.getTransactionStatus()every 3 s untilcompleted,failed, orexpired
EIP-1193 wrapper. Emits connect, disconnect, accountsChanged, chainChanged.
Exposes wallet.connect(), wallet.disconnect(), wallet.switchChain(), wallet.request(), wallet.address, wallet.chainId, wallet.provider, wallet.connected.
Throws WalletError with a typed code on user rejections and connectivity failures.
- Open
config.jsand fill inapiKeyandvendorIdentifier. - Serve the folder over HTTP (e.g.
npx serve .). - Open in a browser with MetaMask or any EIP-1193 wallet.
- Select a network and token, connect wallet, click Run Payment Test.
| network | chain id | native |
|---|---|---|
sepolia |
11155111 | ETH |
baseSepolia |
84532 | ETH |
polygonAmoy |
80002 | MATIC |
liskTestnet |
4202 | ETH |