Skip to content

Source Adapters

Griffen Fargo edited this page May 3, 2026 · 4 revisions

Source Adapters

Source adapters live in packages/sources/. Each adapter has one job: produce RawEvent[] from its source. Adapters do not classify intent — that's the classifier's job.

Coinbase CSV Adapter

Location: packages/sources/src/coinbase/

Parses Coinbase "All Transactions" CSV exports. Handles all 13 transaction types including Buy, Sell, Convert, Send, Receive, staking income, and internal moves.

Key Features

  • Notes parsing — extracts structured data from the free-form Notes column (Convert second leg, Send destination address, Advanced Trade details)
  • Pair merging — groups Retail Staking Transfer and Retail Eth2 Deprecation rows by (timestamp, abs(quantity)) into single internal_move events
  • Deterministic IDscoinbase:{rowId} for singles, composite IDs for pairs

Usage

daybook sync --source coinbase --file ~/Downloads/Coinbase-All-Transactions.csv

Supported Transaction Types

Type RawEvent Type Notes
Buy trade Two legs (fiat out, crypto in) + fee
Sell trade Two legs (crypto out, fiat in) + fee
Convert trade Second leg parsed from Notes column
Send crypto_out Destination address parsed from Notes
Receive crypto_in Source often unknown
Staking Income income Single positive leg
Reward Income income Single positive leg
Inflation Reward income Single positive leg
Deposit fiat_deposit USD only
Withdrawal fiat_withdrawal USD only
Retail Staking Transfer internal_move Paired by timestamp + amount
Retail Eth2 Deprecation internal_move Paired by timestamp + amount
Advanced Trade Buy trade Like Buy with different note format

Kraken CSV Adapter

Location: packages/sources/src/kraken/

Parses Kraken "Export Ledger" CSV files. Kraken uses a true double-entry ledger where trades are represented as two rows sharing a refid.

Key Features

  • Trade pairing — groups rows by refid, pairs of exactly 2 trade rows become one trade event
  • Asset normalization — maps Kraken's internal names to canonical symbols (XXBT→BTC, XETH→ETH, ZUSD→USD, ZEUR→EUR, ETH2→ETH, etc.)
  • Fee handling — non-zero fees produce a separate AssetLeg with feeFlag: true
  • Deterministic IDskraken:{refid} for trades, kraken:{txid} for singles
  • Idempotent — same CSV parsed twice produces identical event IDs

Usage

daybook sync --source kraken --file ~/Downloads/kraken-ledger.csv

Supported Row Types

Kraken Type RawEvent Type Notes
trade trade Paired by refid (2 rows → 1 event)
deposit crypto_in Single positive leg
withdrawal crypto_out Single negative leg
staking income Single positive leg
Unknown types unknown Warning emitted

Asset Normalization

Kraken uses non-standard asset names. The adapter normalizes them:

Kraken daybook
XXBT BTC
XETH ETH
XLTC LTC
XXRP XRP
ZUSD USD
ZEUR EUR
ZGBP GBP
ETH2, ETH2.S ETH

Assets not in the map pass through unchanged.

EVM Adapter

Location: packages/sources/src/evm/

Fetches on-chain transfers for EVM wallets (Ethereum, Polygon) via provider interfaces.

Providers

Alchemy (primary)

Location: packages/sources/src/evm/providers/alchemy.ts

Uses alchemy.core.getAssetTransfers to fetch all transfer types in a single paginated call:

  • External transfers (ETH sends/receives)
  • Internal transfers (contract-to-contract)
  • ERC-20 token transfers
  • ERC-721 / ERC-1155 NFT transfers

Uses rawContract.value (hex) + rawContract.decimal (hex) for precise amounts — never the SDK's value: number field which loses precision above 2^53.

Etherscan (failed transactions)

Location: packages/sources/src/evm/providers/etherscan.ts

Fetches the normal transaction list from Etherscan's txlist endpoint. Only emits transfers for failed transactions (isError === '1'), capturing gas costs that Alchemy doesn't report.

  • Gas cost computed as gasUsed × gasPrice / 1e18 using decimal.js
  • Provider ID: etherscan-failed:{txHash}
  • Auto-paginates until all results retrieved
  • Exponential backoff on rate limits (429)

Block Resolver

Location: packages/sources/src/evm/block-resolver.ts

Resolves --from values to block numbers:

  • Numeric strings pass through as BigInt
  • ISO 8601 dates are resolved to the nearest block via binary search using Alchemy's getBlock

Usage

# Full sync
daybook sync --source eth
daybook sync --source polygon

# Incremental sync
daybook sync --source eth --from 2024-01-01
daybook sync --source polygon --from 50000000

# Include failed transaction gas
daybook sync --source eth --include-failed-gas

Adapter Behavior

The adapter (packages/sources/src/evm/adapter.ts) translates RawTransfer objects from any provider into RawEvent objects:

  • category: native/erc20 with from = usercrypto_out (negative leg)
  • category: native/erc20 with to = usercrypto_in (positive leg)
  • category: erc721/erc1155nft_event placeholder
  • Bidirectional dedup by providerId (self-transfers appear in both directions)

Clone this wiki locally