On-chain (Base)
gridz.bio production runs on Base mainnet (chain id 8453). Subject names remain *.gridz.eth; the app reads GridzResolver and EAS directly on Base via RPC. Full deployment table: deployments.md.
Base mainnet (production)
| Contract / config | Address / value |
|---|---|
| Chain ID | 8453 |
| GridzResolver (UUPS proxy) | 0x73c5e3944B780D4927c403d351A4F94875DC57B3 |
| EAS | 0x4200000000000000000000000000000000000021 |
| EAS SchemaRegistry | 0x4200000000000000000000000000000000000020 |
gridz.cell.v1 schema UID | 0x394d8e67b1470cbdb7fa6c7d15d15d295ca81d822b55267939751a8a686abb87 |
| Registrar (server publish) | 0xEBE4ceb499Ad95DC1e5662E3a223Ec8cc0a555d9 |
| Public RPC | https://base.publicnode.com |
| EAS explorer | base.easscan.org |
Schema string (same on all EAS networks; UID differs per chain): bytes32 gridId, string key, string valueHashHex, uint64 expiresAt, bytes32 widgetTypeHash
GridzResolver
The resolver is the on-chain index for Gridz profiles on a chain. For each ENS name (via wildcard *.gridz.eth) it stores:
- Per-cell EAS attestation UID mapped by
(gridId, key) - Nonce tracking to prevent replay of superseded cell values
- Links to the EIP-712 verifying contract used for signatures on that chain
Reading a profile: resolve ENS → fetch cell UIDs from resolver → load EAS attestations → decode gridz.cell.v1 fields → assemble Grid JSON. This is what loadGrid() and GET /api/profile/{subject} do on gridz.bio.
Publish pipeline
Wallet (EIP-712 GridzCell)
│
▼
POST /api/publish { subject, key, signature, typed data, … }
│
▼
Registrar EOA/contract
├─ EAS.attest(gridz.cell.v1, …)
└─ GridzResolver.setCellAttestation(ensNode, key, uid, nonce)
│
▼
Profile live at alias.gridz.bio + GET /api/profile/alias.gridz.ethThe user signs; the registrar submits transactions and pays gas. Gridz never holds the user's private key. The registrar cannot forge signatures — it only wraps already-signed attestations on-chain.
Publish errors like replacement transaction underpriced are handled with nonce clearing and gas-bump retries in the gridz.bio editor.
Verification on-chain
verifyGrid in @gridz/core performs local hash + signature checks first, then for eas-onchain cells:
- Fetch the EAS attestation by UID from Base RPC
- Confirm schema UID matches
gridz.cell.v1 - Decode on-chain fields and compare to cell + envelope
- Cross-check resolver mapping for
(subject, key)→ same UID - Check revocation status if applicable
gridz.bio exposes this via GET /api/verify/{subject} because browsers cannot reliably call Base RPC (CORS). See Verification.
Legacy & testnet
Ethereum mainnet (legacy)
Earlier publishes used L1 before the Base migration.
| Contract | Address |
|---|---|
| GridzResolver (UUPS proxy) | 0x190a9c0D29bCca03efeA85dcDF8F4b283e32dc52 |
| EAS | 0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587 |
Sepolia (testnet)
| Contract | Address |
|---|---|
| EAS | 0xC2679fBD37d54388Ce493F1DB75320D236e1815e |
| EAS SchemaRegistry | 0x0a7E2Ff54e576B096E04665717A6C3B2a33b9e4a |
Deploy a fresh resolver with forge script script/Deploy.s.sol and register the cell schema with node scripts/register-cell-schema.mjs.
Contract upgrades
GridzResolver is UUPS-upgradeable. Upgrades require UPGRADER_ROLE on the proxy:
PROXY_ADDRESS=<proxy> forge script script/Upgrade.s.sol \ --rpc-url <rpc> --broadcast --private-key <key>