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 / configAddress / value
Chain ID8453
GridzResolver (UUPS proxy)0x73c5e3944B780D4927c403d351A4F94875DC57B3
EAS0x4200000000000000000000000000000000000021
EAS SchemaRegistry0x4200000000000000000000000000000000000020
gridz.cell.v1 schema UID0x394d8e67b1470cbdb7fa6c7d15d15d295ca81d822b55267939751a8a686abb87
Registrar (server publish)0xEBE4ceb499Ad95DC1e5662E3a223Ec8cc0a555d9
Public RPChttps://base.publicnode.com
EAS explorerbase.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.eth

The 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:

  1. Fetch the EAS attestation by UID from Base RPC
  2. Confirm schema UID matches gridz.cell.v1
  3. Decode on-chain fields and compare to cell + envelope
  4. Cross-check resolver mapping for (subject, key) → same UID
  5. 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.

ContractAddress
GridzResolver (UUPS proxy)0x190a9c0D29bCca03efeA85dcDF8F4b283e32dc52
EAS0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587

Sepolia (testnet)

ContractAddress
EAS0xC2679fBD37d54388Ce493F1DB75320D236e1815e
EAS SchemaRegistry0x0a7E2Ff54e576B096E04665717A6C3B2a33b9e4a

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>