OurGlass

Analytics

On-chain, verifiable analytics — and the attribution problem it has to solve.

OurGlass aims for a decentralized, verifiable analytics surface: charge count and token volume over time, broken down by agreement, receiver, payer, and token — all derived from public on-chain data, with no private backend required.

The attribution problem

OurGlass has no contract of its own, and it is local-first (agreements live in the payer's localStorage). A charge is a call to the shared DelegationManager plus an ERC-20 Transfer. Nothing on-chain says "OurGlass": the enforcer addresses are shared across every app on the Delegation Framework, parties vary per agreement, and the salt is unguessable. So every analytics approach reduces to one question: how do we plant an OurGlass-attributable marker on-chain that needs no central registry?

The marker: redeploy the audited enforcers

Deploy OurGlass's own instances of MetaMask's audited enforcers (unmodified bytecode) and route new agreements to them, then index those contracts' events. The emitter address of a caveat event is the enforcer instance — so attribution becomes a one-key filter (WHERE contract_address = <our enforcer>) with no central list of delegation hashes. This works precisely because the app is local-first.

This now spans both payment shapes, so OurGlass maintains two self-deployed instances:

The security implications of self-deploying audited bytecode are covered in Security.

The on-chain trace

Two sources carry everything the dashboard needs.

1. DelegationManager.RedeemedDelegation — once per redemption, for both shapes. Carries the root delegator (payer), the redeemer (receiver), and the full delegation struct including caveats and the salt (= the pinned-agreement hash).

2. The enforcer's per-charge event — filtered by our enforcer address:

  • Subscriptions: ERC20PeriodTransferEnforcer.TransferredInPeriod. The per-charge amount is the in-period delta of the cumulative transferredInCurrentPeriod, which resets each period — handle the period-boundary reset when computing it.
  • Streams: the streaming enforcer's transfer/claim event. A stream is claim-based, so the per-claim amount is read directly rather than via a period delta.

Confirm the exact streaming event name and field layout against @metamask/delegation-abis before building the indexer — do not assume it mirrors the period enforcer. Streams accrue and are claimed, so the amount semantics differ from the period enforcer's cumulative-with-reset counter.

Deriving the dashboard

From these events, filtered to our enforcer instances:

MetricDerivation
Charge / claim countcount of per-charge events
Amountperiod delta (subscriptions) or claimed amount (streams)
Volume over timesum of amounts bucketed by timestamp
Per agreementgroup by delegationHash
Per receivergroup by redeemer
Per payerjoin delegationHashRedeemedDelegation.rootDelegator
Per tokenthe token field
Active agreementsdistinct delegationHash charged in window, cross-referenced with DisabledDelegation for revokes

Indexing

  • Primary: a subgraph keyed on the per-charge events from our enforcer addresses (plus RedeemedDelegation / DisabledDelegation). Works on testnets and is the decentralized-friendly indexer.
  • Secondary: a Dune dashboard once on mainnet, decoding the same events.

The UI reads the subgraph over GraphQL — no private backend, no dependency on any single client's localStorage.

Status

This is the planned analytics design, updated to cover streams alongside subscriptions. It is not yet implemented; only new agreements routed to the self-deployed enforcers would be attributable.

On this page