Skip to content

Loan indexing ​

Fuel Credit uses a hybrid Cloudflare indexer so wallets can recover loan history without scanning every Fuel block. Fuel contract state remains the financial source of truth; D1 is a materialized query cache. See Architecture for the complete system map and glossary.

Components ​

  • Indexer Worker: versioned public reads and transaction-report ingestion.
  • D1: loan snapshots, account/protocol projections, sync cursor, observed receipts, and idempotency records.
  • Queue: at-least-once discovery, hydration, active-loan reconciliation, pool refresh, and transaction verification.
  • Durable Object: one coordinator for each chain and contract, preventing overlapping scheduled discovery runs.
  • Cron: schedules discovery and active-loan reconciliation every five minutes.

No indexer component has a funded wallet. It cannot fund pools, finalize loans, or change contract state.

Discovery and freshness ​

The active testnet contract has contiguous loan IDs but no public loan-count getter. The indexer stores next_loan_id, calls get_loan(id) from that cursor, and stops at the first missing loan. It never repeats the historical range. A future contract release should expose loan_count() to make this bound explicit.

Active loans and fully repaid loans with unclaimed collateral are reread when their borrower requests My Loans. Repaid collateral remains counted as locked until a separate borrower claim at or after maturity. Defaulted and fully claimed loans are immutable and need no periodic calls. Pool statistics come from pool_stats().

The Worker uses a small WASM-free Fuel reader in workers/indexer/src/fuel-reader.ts. It submits pinned, ABI-specific unsigned read transactions through Fuel GraphQL assembleTx, patches only the fixed-width loan ID argument, and decodes verified RETURN_DATA receipts from the configured contract. Fixture and live parity tests guard the transaction layout and ABI decoding. A new contract or ABI requires regenerating and revalidating these templates before activation.

User reports ​

After a wallet transaction confirms, the app may report its transaction ID:

http
POST /v1/transactions/report
Content-Type: application/json

{"transactionId":"0x…"}

The report is only a hint. The Worker accepts only a successful Fuel transaction whose receipts involve the configured Fuel Credit contract, records receipts with the unique key (chain_id, transaction_id, receipt_index), and then schedules discovery and reconciliation. Missed reports are recovered by cron.

API ​

text
GET  /v1/health
GET  /v1/accounts/:address/loans
GET  /v1/loans/:loanId
GET  /v1/stats
POST /v1/transactions/report

Account and transaction identifiers are normalized lowercase 0x b256 values. Token amounts are stored as base-unit strings. Loan uniqueness is enforced by (chain_id, contract_id, loan_id) and transaction reports by (chain_id, transaction_id), making queue retries safe.

Operations ​

The testnet implementation lives in workers/indexer/. Provision and deploy with:

bash
bunx wrangler d1 create fuel-credit-testnet-index
# Put the returned database ID in workers/indexer/wrangler.jsonc.
bunx wrangler queues create fuel-credit-testnet-index-jobs
bunx wrangler queues create fuel-credit-testnet-index-dlq
bunx wrangler d1 migrations apply fuel-credit-testnet-index --remote --config workers/indexer/wrangler.jsonc
bunx wrangler deploy --config workers/indexer/wrangler.jsonc

Cloudflare Queue delivery is at least once. D1 primary keys and upserts provide idempotency. Structured Worker errors expose failed job type and retry attempts without wallet or secret material.

The mainnet indexer is isolated and active at https://fuel-credit-mainnet-indexer.nick-j-alexander.workers.dev for the dormant contract. It uses D1 database fuel-credit-mainnet-index (eb9d03ac-aa48-4c54-b3a2-6e9221af10c1), queues fuel-credit-mainnet-index-jobs and fuel-credit-mainnet-index-dlq, a separate Durable Object namespace, and mainnet-specific raw-reader templates. Live health and statistics reconcile to zero onchain loans and balances. This does not activate borrowing; the app and oracle remain fail-closed.

Open-source infrastructure on Fuel.