Pellet Network

05Methodology

How Wallet decodes autonomous economic activity on Tempo. Every datapoint here comes from on-chain state — no off-chain sources, no self-reporting. The pipeline is open and reproducible.
01

Event ingestion

cron @ :00 hourly

A Vercel cron at /api/cron/ingest sweeps Tempo for new logs from watched contracts (TIP-20 stables) using viem against rpc.tempo.xyz. Logs are stored raw in the events table, keyed by (tx_hash, log_index) for idempotency.

We watch the Transfer event (topic 0xddf252ad…) plus a few admin events (Approval, Role*, SupplyCapUpdated). Tempo's stable-native AA tx envelope (type 0x76) is parsed by reading tx.calls[] rather than the standard tx.input field.

02

Agent matching

methodology v0.2

A second cron at /api/cron/match joins ingested events to agents rows by walking the event's indexed topics and looking for a wallet hit. One agent_event row is written per (event, matched agent) pair — the same event can match multiple agents (e.g. both sides of a Transfer if both are watched).

Each match captures the economic primitive: amount_wei from the Transfer's data field, token_address from the contract, and counterparty_addressfrom whichever indexed topic isn't the matched agent.

03

Gateway attribution

cron @ :10 hourly

The Tempo MPP Gateway settles to a single address (0xca4e835f…4779Fe) for many underlying providers, so per-service attribution requires extra decoding. A third cron at /api/cron/attribute walks unprocessed gateway txs and tries two paths.

Pattern A · Settlement event

When the gateway routes funds onward to a provider, its escrow contract 0x33b9…4f25 emits a custom event keyed at topic 0x92ed5fe0…. The provider address sits at topic[2]. We read the tx receipt, find the matching log, and persist routed_to_address.

Coverage: ~9% of gateway txs. The rest don't go through the settlement path because the user paid the gateway directly and the gateway batches settlement off-cycle.

Pattern B · Calldata fingerprint

User→gateway txs use the USDC.e 0x95777d59 selector with args (address recipient, uint256 amount, bytes32 ref). The bytes32 ref has stable structure:

0xef1ed71201 + <10-byte service fingerprint> +
             0000000000000000 + <7-byte per-call nonce>

Bytes 5–14 are a deterministic per-service fingerprint set by Tempo's MPP client. We persist them as routed_fingerprintso all gateway txs cluster by service even when the provider address can't be recovered.

Coverage: ~91% of gateway txs (combined with Pattern A: essentially 100%). Fingerprints aren't human-readable until a row is added to address_labelsmapping the fingerprint to a model name; the UI lights up automatically once it's there.

04

Provenance

Every row in Wallet carries a methodology_version tag plus a source_block reference. The ringed ◍ badge throughout the UI exposes both. Re-deriving any number is a matter of running the matcher against the raw events table — no opaque steps, no off-chain inputs.

Time windows on the dashboard (?w=24h|7d|30d|all) are also surfaced; every leaderboard, chart, and aggregate is derived from the same SQL filter.

05

What's not yet decoded

  • Provider identities for the 2 attributed addresses (0xc95c4f0d…, 0x3fee0b02…) and 7 fingerprint groups. These are stable on-chain — only labels are missing.
  • Non-MPP services (the long tail we couldn't probe at seed time).
  • Cross-tx flow tracing (e.g., a payer's fund-out path through multiple hops).

Source: the pelletnetwork/pellet repo on GitHub. SQL lives in lib/wallet/queries.ts; attribution lives in lib/ingest/gateway-attribution.ts.