Skip to content

[Test] E2E Indexer Verification Script — Validate Web App Indexes Mainnet Transactions #374

@realproject7

Description

@realproject7

Summary

Create a Node.js script that runs after the contract E2E test (plotlink-contracts#27) and verifies the web app correctly indexes every transaction into Supabase.

This is the "contract test" layer — it catches ABI drift between plotlink-contracts and plotlink by verifying that real mainnet events are decoded and stored correctly.

Run command:

npx tsx scripts/e2e-verify.ts --from-file ../plotlink-contracts/e2e-results.json

Depends On

  • plotlink-contracts#27 — the contract E2E script must run first and produce tx hashes + storyline IDs

Verification Scenarios

Group V1: Storyline Indexing

For each storyline created by the contract script:

# Check How
V1.1 POST tx hash to /api/index/storyline Should return 200
V1.2 Query Supabase storylines table by storyline_id Record must exist
V1.3 Verify writer_address matches deployer wallet Field accuracy
V1.4 Verify token_address is non-zero Token was created on MCV2
V1.5 Verify title matches what was sent to contract String decoded correctly
V1.6 Verify has_deadline matches contract param Bool decoded correctly
V1.7 Verify plot_count = 1 (genesis only, before chainPlot indexing) Initial state correct
V1.8 Verify block_timestamp is a valid ISO date Timestamp conversion correct
V1.9 Verify tx_hash and log_index stored correctly Dedup keys present
V1.10 Verify writer_type = 0 (deployer is not a registered agent) ERC-8004 detection works

Group V2: Plot Indexing

For each plot chained by the contract script:

# Check How
V2.1 POST tx hash to /api/index/plot Should return 200
V2.2 Query Supabase plots table by storyline_id + plot_index Record must exist
V2.3 Verify content_cid matches CID sent to contract CID decoded correctly
V2.4 Verify content_hash matches keccak256 of actual content Hash integrity
V2.5 Verify content field is non-empty (fetched from IPFS or fallback) Content retrieval works
V2.6 Verify plot_index is sequential (0 = genesis, 1, 2, 3...) Ordering correct
V2.7 After all plots indexed, verify parent storyline plot_count reconciled Reconciliation works
V2.8 Verify last_plot_time on storyline matches latest plot timestamp Reconciliation accurate

Group V3: Trade Indexing

For each mint/burn from the contract script's trading scenarios:

# Check How
V3.1 POST tx hash + token address to /api/index/trade Should return 200
V3.2 Query Supabase trade_history by tx_hash Record(s) must exist
V3.3 Verify event_type is "mint" or "burn" correctly Event classification
V3.4 Verify price_per_token is > 0 and reasonable Price calculation correct
V3.5 Verify total_supply changes correctly after each trade Supply tracking
V3.6 Verify reserve_amount matches what the contract reported Amount accuracy
V3.7 Verify user_address matches the trader (deployer) User attribution
V3.8 Verify storyline_id resolved from token_address lookup Token → storyline mapping

Group V4: Donation Indexing

For each donation from the contract script:

# Check How
V4.1 POST tx hash to /api/index/donation Should return 200
V4.2 Query Supabase donations by tx_hash Record must exist
V4.3 Verify donor_address matches deployer wallet Donor decoded correctly
V4.4 Verify amount matches donation amount (stored as wei string) Amount precision
V4.5 Verify storyline_id matches the donated-to storyline Routing correct

Group V5: Price & TVL Reads

After all trades are indexed:

# Check How
V5.1 Call getTokenPrice(tokenAddress) from lib/price.ts Returns non-null
V5.2 Verify pricePerToken is > 0 Price reads work
V5.3 Verify totalSupply matches expected after all buys/sells Supply accurate
V5.4 Call getTokenTVL(tokenAddress) Returns non-null
V5.5 Verify tvl is > 0 (reserve deposited from buys) TVL reads work

Group V6: Content Hash Verification

# Check How
V6.1 For each indexed plot, compute keccak256(content) locally Use lib/content.ts hashContent
V6.2 Compare local hash to stored content_hash Must match exactly
V6.3 Test with Unicode content (Korean + emoji) in at least one plot Unicode hashing consistent between Solidity and TS

Group V7: Idempotency

# Check How
V7.1 POST the same tx hash to storyline indexer twice Second call returns 200, no duplicate records
V7.2 POST the same tx hash to plot indexer twice No duplicate plots
V7.3 POST the same tx hash to trade indexer twice No duplicate trades
V7.4 POST the same tx hash to donation indexer twice No duplicate donations

Group V8: Error Handling

# Check How
V8.1 POST invalid tx hash (random hex) to storyline indexer Should return 4xx, not 500
V8.2 POST valid tx hash from unrelated contract Should return 4xx (no matching event)
V8.3 POST empty body to each indexer route Should return 400

Data Flow Between Scripts

plotlink-contracts/              plotlink/
┌──────────────────┐            ┌──────────────────────┐
│  E2ETest.s.sol   │            │  e2e-verify.ts       │
│                  │            │                      │
│  Runs on mainnet │──writes──▶ │  Reads results JSON  │
│  Real txs        │  JSON file │  Calls indexer APIs  │
│  Logs tx hashes  │            │  Queries Supabase    │
│                  │            │  Verifies all fields │
└──────────────────┘            └──────────────────────┘

The contract script outputs a JSON file (e2e-results.json) with all tx hashes, storyline IDs, token addresses, and expected values. The verification script reads this and validates the full pipeline.


Output Format

=== V1: Storyline Indexing ===
[V1.1] POST /api/index/storyline (id=5)      PASS  200 OK
[V1.2] Supabase record exists                 PASS
[V1.3] writer_address matches                 PASS  0x4d34...
[V1.4] token_address non-zero                 PASS  0xABC...
...
=== V7: Idempotency ===
[V7.1] Double-index storyline                 PASS  no duplicates
...
=== ALL VERIFICATIONS PASSED ===

Acceptance Criteria

  • Script reads tx data from contract E2E results (JSON file or CLI args)
  • All V1–V8 verification groups implemented and logged
  • Passes when run against freshly created mainnet storylines
  • Idempotency checks confirm no duplicate records
  • Error handling checks confirm proper HTTP status codes
  • Content hash verification works with Unicode text
  • Clear PASS/FAIL output for each individual check

Branch

task/{issue-number}-e2e-indexer-verify

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/T3Assigned to T3 builder agenttest

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions