Frontend
Static HTML, vanilla JavaScript, and two wallet transports. No framework, no build step, no backend.
Shape of the site
| File | Role |
|---|---|
index.html | Home: drawings, run, buy, verify, FAQ |
app.js | Design grid, simulator wiring, live stats |
buy.js | Quote, transaction assembly, wrap/unwrap, market |
wallet.js | Provider discovery and WalletConnect |
cards.js | My cards, holdings rendering, actions |
run.js | Netlist decoding and evaluation |
Wallet transports
Two paths, no dependency on one vendor:
- EIP-6963 — browsers announce installed wallets; the page listens for
eip6963:announceProviderand shows each as a tile. Falls back towindow.ethereumfor older extensions. - WalletConnect — a self-hosted bundle, used for mobile wallets. It does not load from a CDN, so the page has no third-party script dependency at runtime.
Transaction assembly
Before eth_sendTransaction the page fills every field a strict wallet may require:
{
from, to, value, data,
nonce: eth_getTransactionCount(from, "pending"),
gasPrice: eth_gasPrice,
gas: estimate × 1.3, floor 700,000,
chainId: "0x38",
type: "0x0"
}
The estimate comes from a public node; the 30% margin covers small state differences between simulation and inclusion. If a wallet rejects the payload, the page retries once with only from, to, value, data.
Reads
All reads go to public RPC endpoints with fallbacks, and are batched through a multicall where possible. Nothing is proxied through our server, so the page works even if the site's own backend is down.
Receipts and errors
Every write waits for a receipt and checks status. A reverted receipt is surfaced as a failure with the step named — mint, tapeout, claim — rather than as a generic error.
No router, by design
There is no contract of ours between the buyer and the protocol. That costs one extra signature per card and removes an entire class of custody bugs.