How Boon indexes onchain events into the entities that back board, points, profile, receipt, and graph reads.
Data layer (subgraph)
Section titled “Data layer (subgraph)”Almost every Boon read — board, points, profile, receipt, gratitude graph — is served by the Worker reading a Goldsky-hosted subgraph that indexes the Boon contract on Base. Understanding the entity model is the fastest way to debug “data looks stale” or to integrate a new endpoint.
Indexed events
Section titled “Indexed events”The contract emits four events that the subgraph consumes:
| Event | What it produces |
|---|---|
Tip(indexed bytes32 handleHash, indexed address from, uint256 amount, string displayHandle, string note) | A Tip entity (status starts as ESCROWED), Recipient + Tipper rollups, and Boon Points attributions. |
Pushed(indexed bytes32 handleHash, indexed address to, uint256 amount) | Flips matching Tip entities to PUSHED and updates the Recipient pushed/escrowed split. |
Linked(indexed bytes32 handleHash, indexed address wallet, string canonicalHandle) | Sets Recipient.linkedWallet, creates a Link audit entry, populates the HandleHashIndex, updates Stats. |
Claimed(indexed bytes32 handleHash, indexed address to, uint256 amount) | Creates a Claim entity and flips prior ESCROWED tips for the handle to CLAIMED. |
Entities
Section titled “Entities”- Tip — every tip event, with
status∈ESCROWED | PUSHED | CLAIMEDand points-attribution fields. - Recipient — aggregated per canonical handle:
totalReceived, pushed/escrowed/claimed splits,linkedWallet, recipient-side public points. - Tipper — aggregated per sender wallet:
totalSent,tipCount, sender-side public points. - Link — discrete handle ↔ wallet binding events.
- Claim — discrete claim sweeps for audit/history.
- HandleHashIndex — reverse lookup from
handleHashto canonical handle (needed becauseClaimedonly carries the hash). - Stats — global singleton:
totalTipped,tipCount,uniqueRecipients,uniqueTippers,linkedRecipients, current points policy version. - TipperRecipientDay, RecipientSender, RecipientEpochBonus — persistent rollups for anti-farming and independent-sender accounting. These must live in the subgraph (not in-memory AssemblyScript maps) so the rules stay deterministic.
Which endpoints read which entities
Section titled “Which endpoints read which entities”| Endpoint | Source |
|---|---|
GET /api/v1/board (and /api/leaderboard alias) | Recipient (top by totalReceived) + Tipper + Stats |
GET /api/v1/handles/:handle/points | Recipient (handle points) + join to Tipper via linkedWallet for sentPoints |
GET /api/v1/handles/:handle/profile | Points envelope + Recipient aggregates |
GET /api/v1/receipts/:txHash | Tip by tx hash + Recipient + Tipper |
GET /api/v1/handles/:handle/boons (paid) | Tip filtered by handle |
GET /api/v1/graphs/gratitude (paid) | Tip traversed into handle / repo-filtered graph |
If a handle has no linkedWallet, the Worker reports sentPointsSource: "unlinked" rather than silently zeroing the sender-side points.
Deploy and provenance
Section titled “Deploy and provenance”The subgraph manifest is rendered from subgraph.template.yaml plus
subgraph/networks.json on every build. The build script intentionally
fails on zero addresses so a placeholder subgraph cannot be deployed by
accident. Mainnet and Sepolia each have their own deploy command:
npm --prefix subgraph run build:mainnetnpm --prefix subgraph run build:sepoliaThe ABI at subgraph/abis/Boon.json is extracted from the Foundry build
artifact and must be refreshed whenever the contract changes.
”Data looks stale” — diagnose before assuming contract bugs
Section titled “”Data looks stale” — diagnose before assuming contract bugs”Index lag is the most common cause of a read that does not match the chain. Before assuming the contract is wrong:
- Look up the tx on BaseScan to confirm the block.
- Query the subgraph’s
_meta { block { number } }to see how far behind it is. - Wait a block or two, then re-fetch.
If the lag persists or Stats totals look wrong, that’s a subgraph issue,
not a contract issue. See Troubleshooting → Data looks stale.
Reference
Section titled “Reference”The full entity schema, deploy commands, and the example leaderboard query
live in subgraph/README.md. Treat it as the operator-side companion to this page.