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. GitHubarrow-up-right

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. GitHubarrow-up-right

index.ts

One‑liner that re‑exports the two files above for ergonomic imports. GitHubarrow-up-right


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, …) GitHubarrow-up-right

chains.tsCHAIN_ID

Numeric IDs for every EVM chain we care about; keeps config and tests in sync. GitHubarrow-up-right

listeners.tsLISTEN_FOR_TRANSACTIONS

Indicates whether we inspect incoming or outgoing txs for a contract. GitHubarrow-up-right

index.ts simply re‑exports the chunk files. GitHubarrow-up-right


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. GitHubarrow-up-right


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. GitHubarrow-up-right

  • IProtocolParser – contract every parser class must implement (identifier + parseTransaction + getProtocolContracts). GitHubarrow-up-right

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


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. GitHubarrow-up-right

parser.ts

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

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. GitHubarrow-up-right

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). GitHubarrow-up-right


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. GitHubarrow-up-right


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