Understanding the codebase

Repo structure

the‑parsoor/
├── .github/                ← CI & templates
├── .vscode/               ← local dev helpers
├── .env.example
├── jest.config.js
├── package*.json
├── tsconfig.json
├─┬ src/                    ← **all production TypeScript**
│ ├─┬ config/               ← global registries
│ │ ├── chainConfig.ts
│ │ ├── protocols.ts
│ │ └── index.ts
│ ├─┬ enums/                ← string/number enums shared project‑wide
│ │ └── index.ts
│ ├─┬ helpers/              ← pure utility functions
│ │ ├── ProtocolHelper.ts
│ │ └── …
│ ├─┬ lib/                  ← **one folder per protocol parser**
│ │ ├─┬ Across/             ← ✧ *focus of this tour*
│ │ │ ├─┬ abis/
│ │ │ │ └── SpokePool.json
│ │ │ ├── contracts.ts      ← address + event signature map
│ │ │ ├── parser.ts         ← core parsing logic
│ │ │ └── index.ts          ← tiny export wrapper
│ │ ├── Curve/
│ │ ├── Uniswap/
│ │ ├── … (~15 other dApps)
│ │ └── index.ts            ← collects **every** protocol parser into a map
│ ├─┬ types/                ← strict domain interfaces
│ │ ├─┬ chunks/             ← granular sub‑interfaces
│ │ │ ├── IProtocolParser.ts
│ │ │ └── …
│ │ └── index.ts
│ └── index.ts              ← library entry‑point
└─┬ tests/                  ← mirrors `src/lib` one‑for‑one
  ├─┬ lib/
  │ ├─┬ Across/
  │ │ ├── data.ts           ← sample on‑chain tx hashes
  │ │ └── index.test.ts     ← Jest unit tests
  │ └── …                   ← other protocol test suites
  └── index.ts              ← test boot‑strap
  

1. config/ — global registries

chainConfig.ts

A simple map from CHAIN_ID → RPC URL. Environment variables override the public defaults so contributors can drop in their own Alchemy/Infura keys without touching code. GitHub

protocols.ts

Canonical metadata for every dApp OpenRep understands: human‑readable name, logo, website, protocol type, and the action‑tags that matter for reputation scoring. New parsers only need to add one JSON‑ish entry here. GitHub

index.ts

One‑liner that re‑exports the two files above for ergonomic imports. GitHub


2. enums/ — shared constants

Tiny, dependency‑free enums that keep magic strings out of business logic:

file
purpose

actions.tsACTION_ENUM

High‑level actions a parser can emit (SINGLE_SWAP, BRIDGE_OUT, …) GitHub

chains.tsCHAIN_ID

Numeric IDs for every EVM chain we care about; keeps config and tests in sync. GitHub

listeners.tsLISTEN_FOR_TRANSACTIONS

Indicates whether we inspect incoming or outgoing txs for a contract. GitHub

index.ts simply re‑exports the chunk files. GitHub


3. helpers/ — pure utility code

ProtocolHelper.ts

A 150‑line Swiss‑army knife used by every parser:

  • decode calldata (parseTransaction) and logs (parseLog) with the right ABI

  • quick checks like “is txn.to one of my listener contracts?”

index.ts

Just re‑exports ProtocolHelper. GitHub


4. types/ — strongly‑typed domain model

All interfaces live here so parsers stay 100 % type‑safe:

  • ITransaction – normalized block‑data record

  • ITransactionAction (+ variants) – the output of a parser: swap, bridge‑in/out, etc. GitHub

  • IProtocolParser – contract every parser class must implement (identifier + parseTransaction + getProtocolContracts). GitHub

The chunked layout keeps each interface tiny and tree‑shakeable; types/index.ts gathers them for downstream imports. GitHub


5. lib/<Protocol> — the actual protocol parsers

Every dApp gets its own folder; let’s zoom into Across as a template.

file
what it holds

abis/SpokePool.json

Minimal ABI for the contract(s) we parse — only the events/functions we need, nothing else.

contracts.ts

1️⃣ enum of internal contract IDs 2️⃣ address map per chain & listen‑direction 3️⃣ event signatures → ABI fragments — all nested under IProtocolContractDefinitions. GitHub

parser.ts

Pure, stateless functions that inspect logs and build IBridgeIn / IBridgeOut actions. It leans on ProtocolHelper.parseLog so ABI decoding is one‑liner. GitHub

index.ts

A small class that wires the pieces together: • sets protocolIdentifier from config/protocols • decides if the tx is relevant (using helper) • delegates to parser.ts and returns the array of actions. GitHub

lib/index.ts instantiates every parser and exports a lookup map keyed by the identifiers defined in config/protocols.ts. When the indexer hands a raw tx to OpenRep, it just does parsers[protoId].parseTransaction(tx). GitHub


6. Root src/index.ts

Five export lines that fan‑out the public surface of the SDK — effortless consumption from other Mercle services or external dApps. GitHub


How it all clicks together

  1. Indexer forwards a raw ITransaction to the parser layer.

  2. Top‑level code picks the right parser via lib/index.ts.

  3. The parser uses its contract map + ProtocolHelper to decide if the tx is for it, decode logs, and emit ITransactionAction[].

  4. Actions flow downstream to the scoring engine you described earlier.

With this structure contributors can add a new protocol by touching just four places:

  1. config/protocols.ts – one metadata entry.

  2. lib/<Protocol>/ – the four‑file mini‑module.

  3. lib/index.ts – add an import + line in the parsers map.

  4. (Optional) tests/lib/<Protocol>/ – real‑TX unit tests.

That’s the whole puzzle — no global singleton state, no hand‑rolled type unions, just clean, modular TypeScript ready for fast community contributions.

Last updated