Skip to content

Conversation

@JasoonS
Copy link
Contributor

@JasoonS JasoonS commented Sep 11, 2025

TODO:

  • add tests
  • manually test some scenarios
  • think of more edge cases
  • get feedback on config file layout. For example Denham was keen to make this under a 'subgraph_compatibility' section in the config. I feel like it could also just be a general flag that someone uses so maybe it shouldn't be completely tied only to subgraphs?

Summary by CodeRabbit

  • New Features

    • Optional lowercase formatting for Ethereum addresses across generated projects; address helpers now validate/return lowercased addresses and clients forward checksum/lowercase choice.
  • Configuration

    • New address_format option (checksum or lowercase) in configs and schema.
    • Generated runtime flags: lowercaseAddresses, shouldUseHypersyncClientDecoder, and allEventSignatures; templates updated to emit and thread them.
  • Validation

    • Runtime checks prevent incompatible combinations of lowercaseAddresses and decoder settings.
  • Tests

    • Added tests for address lowercasing and updated config/generation expectations.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

Walkthrough

Adds opt-in EVM address-format support (checksum|lowercase): new Address.Evm lowercase helpers, config surface (address_format), runtime flags (lowercaseAddresses, shouldUseHypersyncClientDecoder), and wiring through HyperSync/RPC/Ethers paths; updates templates, schema, tests, and generated code signatures.

Changes

Cohort / File(s) Summary
EVM address helpers
codegenerator/cli/npm/envio/src/Address.res
Adds external fromStringLowercaseOrThrow binding and wrapper helpers: fromStringLowercaseOrThrow, fromAddressLowercaseOrThrow, fromStringOrThrow (rethrows with descriptive message), and fromAddressOrThrow.
HyperSync client & source
codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res, codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
Adds lowercaseAddresses option to HyperSyncSource.options; forwards as ~enableChecksumAddresses = !lowercaseAddresses to HyperSyncClient.make; toggles checksummed-address behavior and decoder config accordingly.
RPC source & Ethers binding
codegenerator/cli/npm/envio/src/sources/RpcSource.res, codegenerator/cli/npm/envio/src/bindings/Ethers.res
Extends RpcSource options with allEventSignatures, shouldUseHypersyncClientDecoder, lowercaseAddresses; adds optional HyperSync decoding path; threads lowercase handling into block/tx fields. Ethers.makeGetTransactionFields gains ~lowercaseAddresses and conditionally lowercases tx addresses.
Human config & schema
codegenerator/cli/src/config_parsing/human_config.rs, codegenerator/cli/npm/envio/evm.schema.json, codegenerator/cli/src/cli_args/init_config.rs, codegenerator/cli/src/config_parsing/graph_migration/mod.rs
Introduces AddressFormat enum (checksum
System config & template wiring
codegenerator/cli/src/config_parsing/system_config.rs, codegenerator/cli/src/hbs_templating/codegen_templates.rs, codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs, codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
Adds lowercase_addresses and should_use_hypersync_client_decoder to SystemConfig / ProjectTemplate; emits lowercaseAddresses / shouldUseHypersyncClientDecoder into generated YAML/code and updates generated Config.make signature to accept them.
Static generated runtime
codegenerator/cli/templates/static/codegen/src/Config.res, codegenerator/cli/templates/static/codegen/src/UserContext.res, codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res, codegenerator/cli/templates/static/codegen/src/Env.res
Adds Config.t.lowercaseAddresses and make(~lowercaseAddresses) param; runtime validation forbids using lowercaseAddresses when decoder is incompatible; threads lowercaseAddresses into HyperSyncSource/RpcSource; removes Env binding for shouldUseHypersyncClientDecoder.
Templates & example configs
codegenerator/cli/templates/static/*_template/*/config.yaml, codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
Adds address_format: lowercase examples in template config.yaml files and ensures generated YAML includes lowercaseAddresses.
Tests, scenarios & mocks
scenarios/test_codegen/test/*, scenarios/test_codegen/config.yaml, scenarios/test_codegen/rescript.json, scenarios/test_codegen/test/__mocks__/MockConfig.res
Updates tests and mocks to include new flags (lowercaseAddresses, shouldUseHypersyncClientDecoder, allEventSignatures); adds AddressLowercase_test.res; updates expected generated config and scenario config (event_decoder).
Internal Rust cleanup
codegenerator/cli/src/config_parsing/entity_parsing.rs
Adjusts lifetimes in internal types/test helpers (TypeDef<'>, Document<', String>, ObjectType<'_, String>) without changing public API signatures.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as User config.yaml
  participant CLI as CLI Parser (Rust)
  participant Gen as Codegen Templates
  participant App as Generated App
  participant NS as NetworkSources.evm
  participant HS as HyperSyncSource
  participant RPC as RpcSource
  participant Eth as Ethers/Viem

  User->>CLI: sets evm.address_format, event_decoder
  CLI->>Gen: produce SystemConfig with lowercase_addresses & should_use_hypersync_client_decoder
  Gen->>App: emit Config.make(~lowercaseAddresses, ~shouldUseHypersyncClientDecoder)
  App->>NS: evm(~lowercaseAddresses, ~shouldUseHypersyncClientDecoder, ...)
  alt shouldUseHypersyncClientDecoder = true
    NS->>HS: make({ lowercaseAddresses, ... })
    HS->>Eth: HyperSyncClient.make(~enableChecksumAddresses = !lowercase)
  else
    NS->>RPC: make({ lowercaseAddresses, shouldUseHypersyncClientDecoder=false, ... })
    RPC->>Eth: JsonRpcProvider.makeGetTransactionFields(~lowercaseAddresses)
  end
  Note over App,Eth: Address.Evm.fromStringLowercaseOrThrow / fromStringOrThrow used where applicable
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • JonoPrest

Poem

A nibble of bytes, a hop through the chain,
I trim every case, lowercase I maintain.
Checksums or not? Just set it, don’t fret—
My whiskers pick the decoder to get.
Flags in my paws, configs snug and bright. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately describes the primary enhancement of adding a configurable option to output lowercase addresses, and it is concise, single-sentence, and directly reflects the main change in the pull request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch lower-case-address

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🧪 Early access (Sonnet 4.5): enabled

We are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience.

Note:

  • Public repositories are always opted into early access features.
  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.

Comment @coderabbitai help to get the list of available commands and usage tips.

@JasoonS JasoonS requested a review from DZakh September 11, 2025 13:19
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
codegenerator/cli/npm/envio/src/Address.res (1)

39-48: Critical: infinite recursion due to name shadowing of fromStringOrThrow

The local let fromStringOrThrow calls itself, not the external viem binding. This will recurse until stack overflow.

Apply this diff to disambiguate the external and fix the call site:

-  @module("viem")
-  external fromStringOrThrow: string => t = "getAddress"
+  @module("viem")
+  external viemGetAddress: string => t = "getAddress"
...
-  let fromStringOrThrow = string => {
+  let fromStringOrThrow = string => {
     try {
-      fromStringOrThrow(string)
+      viemGetAddress(string)
     } catch {
     | _ =>
       Js.Exn.raiseError(
         `Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
       )
     }
   }
🧹 Nitpick comments (4)
codegenerator/cli/npm/envio/src/Address.res (1)

14-18: Input validation source — consider regex to decouple from viem (optional)

isAddress is fine; if you want to avoid the viem dep here, a fast anchored regex would suffice given hex-only input.

-  @module("viem") @private
-  external isAddress: string => bool = "isAddress"
+  // Optional: replace viem dep with a strict, anchored regex
+  let isAddress = (s: string) =>
+    Js.Re.test_(%re("/^0x[a-fA-F0-9]{40}$/"), s)
codegenerator/cli/src/config_parsing/human_config.rs (1)

212-216: Consider future-proofing the config shape.

If you anticipate more address formatting modes later, consider an enum like address_format: "checksummed" | "lowercase" or grouping under a subgraph_compatibility section (as discussed in the PR). Current boolean is fine if this is the only mode you’ll support.

codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res (2)

175-192: Deduplicate client construction.

Compute enableChecksumAddresses = !lowercaseAddresses once and call HyperSyncClient.make once.

-  let client =
-    if lowercaseAddresses {
-      HyperSyncClient.make(
-        ~url=endpointUrl,
-        ~apiToken,
-        ~maxNumRetries=Env.hyperSyncClientMaxRetries,
-        ~httpReqTimeoutMillis=Env.hyperSyncClientTimeoutMillis,
-        ~enableChecksumAddresses=false,
-      )
-    } else {
-      HyperSyncClient.make(
-        ~url=endpointUrl,
-        ~apiToken,
-        ~maxNumRetries=Env.hyperSyncClientMaxRetries,
-        ~httpReqTimeoutMillis=Env.hyperSyncClientTimeoutMillis,
-        ~enableChecksumAddresses=true,
-      )
-    }
+  let enableChecksumAddresses = !lowercaseAddresses
+  let client = HyperSyncClient.make(
+    ~url=endpointUrl,
+    ~apiToken,
+    ~maxNumRetries=Env.hyperSyncClientMaxRetries,
+    ~httpReqTimeoutMillis=Env.hyperSyncClientTimeoutMillis,
+    ~enableChecksumAddresses,
+  )

205-209: Mirror decoder toggle via same boolean.

Use the computed enableChecksumAddresses to drive decoder setup for clarity.

-        if lowercaseAddresses {
-          decoder.disableChecksummedAddresses()
-        } else {
-          decoder.enableChecksummedAddresses()
-        }
+        if enableChecksumAddresses {
+          decoder.enableChecksummedAddresses()
+        } else {
+          decoder.disableChecksummedAddresses()
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ac325a and e3de440.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (5 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (3 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res (4 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/npm/envio/src/Address.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/npm/envio/src/Address.res
codegenerator/cli/templates/{static,dynamic}/codegen/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Edit template versions under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src instead of editing generated/src

Files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
{codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • codegenerator/cli/src/config_parsing/human_config.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-09-01T14:12:02.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-09-01T14:12:02.500Z
Learning: Applies to {codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs} : When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/src/config_parsing/system_config.rs
🔇 Additional comments (18)
codegenerator/cli/npm/envio/src/Address.res (2)

20-30: Lowercasing constructor with validation — LGTM

Validates first, returns canonical lowercase. Clear error message.


32-34: Helper passthrough — LGTM

Keeps the API ergonomic alongside the non-lowercasing variant.

codegenerator/cli/templates/static/codegen/src/UserContext.res (1)

292-297: Respect lowercaseAddresses when validating user-provided contract addresses — good; ensure consistency across pipeline

This matches the config and prevents mixed-case drift at registration. Please verify Hypersync/decoder paths also use lowercase when this flag is on (they appear to).

codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1)

288-289: Initialize new field with None — LGTM

Neutral default keeps migrations non-opinionated; system layer can unwrap_or(false).

codegenerator/cli/src/cli_args/init_config.rs (1)

174-175: Expose lowercase_addresses on HumanConfig (EVM) — LGTM

Keeps init flow backward-compatible while enabling the new option.

codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (1)

16-17: Thread lowercaseAddresses into HyperSyncSource — LGTM; validate call sites

Signature change is localized to templates and forwarded correctly. Ensure all template emitters pass this arg.

Also applies to: 34-35

codegenerator/cli/templates/static/codegen/src/Config.res (1)

131-132: Add top-level lowercaseAddresses with default false — LGTM

Public surface and constructor default look right; field is included in returned record.

Also applies to: 142-143, 177-178

codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (1)

30-31: Expose lowercaseAddresses in generated YAML — LGTM; confirm scope

Template maps lowercase_addresses -> lowercaseAddresses per chain entry. Confirm the intent is global (same for all chains) vs per-chain overrides.

Also applies to: 65-66

codegenerator/cli/src/config_parsing/human_config.rs (1)

212-216: Add optional lowercase_addresses to EVM HumanConfig — LGTM; regenerate npm schema

  • Wiring confirmed: codegenerator/cli/src/config_parsing/system_config.rs defines pub lowercase_addresses: bool and maps from human config with evm_config.lowercase_addresses.unwrap_or(false) (default=false).
  • Generated schema not verifiable: repo search failed because the npm directory / npm/envio/evm.schema.json was not present. Regenerate and commit the updated evm.schema.json and run the schema-equality tests.
codegenerator/cli/src/hbs_templating/codegen_templates.rs (2)

1282-1283: Expose lowercase_addresses on ProjectTemplate — LGTM.

Field added to the serialization surface so templates can consume it. No concerns.


1389-1390: Propagate from SystemConfig — LGTM.

Correctly sources cfg.lowercase_addresses for templates.

codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res (1)

147-156: Plumbing lowercaseAddresses through options/make — LGTM.

Type and arg added consistently; aligns with generator changes.

Also applies to: 157-167

codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (1)

78-79: Config.make already supports ~lowercaseAddresses (default=false) — no action required

Confirmed: codegenerator/cli/templates/static/codegen/src/Config.res defines lowercaseAddresses: bool and ~lowercaseAddresses=false; the dynamic template passes ~lowercaseAddresses={{lowercase_addresses}} (codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs:78).

codegenerator/cli/src/config_parsing/system_config.rs (5)

417-418: SystemConfig gains lowercase_addresses

Field addition is straightforward and scoped; no trait bounds impacted. LGTM.


725-726: EVM default wiring

lowercase_addresses: evm_config.lowercase_addresses.unwrap_or(false) correctly preserves backward compatibility. LGTM.


863-864: Fuel path explicitly disables lowercasing

Explicit false keeps behavior unchanged for Fuel. LGTM.


2091-2092: Tests: include new optional field

Adding lowercase_addresses: None in test configs is correct to exercise defaults. LGTM.


2138-2139: Tests: include new optional field (second case)

Same here; maintains parity across fixtures. LGTM.

Copy link
Member

@DZakh DZakh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🔥


// NOTE: We could use a regex for this instead, not sure if it is faster/slower than viem's 'isAddress' function
// `/^0x[a-fA-F0-9]{40}$/`
@module("viem") @private
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@module("viem") @private
@module("viem")

@Private doesn't exist in ReScript

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, funny. I actually added that. It wasn't from AI. I had a vague memory of something like this but you're right it might be from ReasonML 🤔

We need to find a way to make sure this doesn't make Viem a required dependency for the users. I don't fully understand the solution that is used for the other function (fromStringOrThrow) but I assume I need to do the same here 🤔 - I thought making it private would maybe help.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do let fromStringOrThrow = fromStringOrThrow below the line. This way it will be exported for ReScript users, but won't require to install viem

#[schemars(
description = "If true, Ethereum addresses are kept lowercase (no checksum) across the indexer (default: false)"
)]
pub lowercase_addresses: Option<bool>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote for address_format: checksum | lowercase field

Comment on lines 176 to 192
if lowercaseAddresses {
HyperSyncClient.make(
~url=endpointUrl,
~apiToken,
~maxNumRetries=Env.hyperSyncClientMaxRetries,
~httpReqTimeoutMillis=Env.hyperSyncClientTimeoutMillis,
~enableChecksumAddresses=false,
)
} else {
HyperSyncClient.make(
~url=endpointUrl,
~apiToken,
~maxNumRetries=Env.hyperSyncClientMaxRetries,
~httpReqTimeoutMillis=Env.hyperSyncClientTimeoutMillis,
~enableChecksumAddresses=true,
)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified to ~enableChecksumAddresses=!lowercaseAddresses

| decoder =>
decoder.enableChecksummedAddresses()
if lowercaseAddresses {
decoder.disableChecksummedAddresses()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, I didn't know that we have the option

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think it is the default, but doesn't hurt to explicitly set it :)

@DZakh DZakh linked an issue Sep 11, 2025 that may be closed by this pull request
@DZakh
Copy link
Member

DZakh commented Sep 11, 2025

Let's also update init templates to use lowercase by default

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/src/Address.res (1)

37-38: Avoid re-validating an already-typed Address.t.

fromAddressLowercaseOrThrow converts t -> string -> t but re-runs validation. Since address: t is already valid, you can lowercase and wrap directly.

-  let fromAddressLowercaseOrThrow = address =>
-    address->toString->fromStringLowercaseOrThrow
+  // No need to re-validate a value already typed as Address.t.
+  let fromAddressLowercaseOrThrow = address =>
+    address->toString->Js.String2.toLowerCase->unsafeFromString
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3de440 and e552611.

📒 Files selected for processing (2)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/hypersync/HyperSyncSource.res
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/Address.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • codegenerator/cli/npm/envio/src/Address.res
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res

@JasoonS
Copy link
Contributor Author

JasoonS commented Sep 12, 2025

Let's also update init templates to use lowercase by default

Could you explain this more, is this just for being more similar to subgraphs?

@DZakh
Copy link
Member

DZakh commented Sep 12, 2025

Yes, I think it's good to be more similar to SubGraph, as well as Ponder. It should also be a little bit more performant

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
scenarios/test_codegen/test/AddressLowercase_test.res (2)

10-12: Optional: strengthen the failure assertion.

Also assert the error type or message (regex) to avoid false positives from unrelated exceptions.

Example:

Assert.throws(
  () => Address.Evm.fromStringLowercaseOrThrow("invalid-address")->ignore,
  /* match by message or custom predicate */
)

3-19: Consider a dict-key normalization test.

Add a test proving that using lowercase addresses as map keys enables case-insensitive retrieval, aligning with our “lowercase keys + compare with toLowerCase” guidance.

Example:

it("dict lookups work with lowercased keys", () => {
  let d = Js.Dict.empty()
  Js.Dict.set(d, "0xabc0000000000000000000000000000000000000", "ok")
  let k = "0xAbC0000000000000000000000000000000000000"
    ->Address.Evm.fromStringLowercaseOrThrow
  Assert.strictEqual(Js.Dict.get(d, k)->Belt.Option.getExn, "ok")
})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e552611 and 6ad22d9.

📒 Files selected for processing (3)
  • scenarios/test_codegen/rescript.json (1 hunks)
  • scenarios/test_codegen/test/AddressLowercase_test.res (1 hunks)
  • scenarios/test_codegen/test/Config_test.res (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • scenarios/test_codegen/rescript.json
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • scenarios/test_codegen/test/Config_test.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • scenarios/test_codegen/test/Config_test.res
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • scenarios/test_codegen/test/Config_test.res
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • scenarios/test_codegen/test/Config_test.res
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • scenarios/test_codegen/test/Config_test.res
🔇 Additional comments (4)
scenarios/test_codegen/test/Config_test.res (2)

12-12: Good addition: default lowercaseAddresses flag captured in expected config.

Matches the new config surface and keeps backward-compat defaults explicit.


24-24: Add a companion test for the true path (lowercaseAddresses: true).

Existing test sets lowercaseAddresses: false in scenarios/test_codegen/test/Config_test.res — add a mirror test that sets lowercaseAddresses: true and asserts the generated config normalizes addresses to lowercase.

scenarios/test_codegen/test/AddressLowercase_test.res (2)

4-8: LGTM: Valid address lowercasing is correctly asserted.

Covers EIP-55 mixed case -> canonical lowercase round-trip via toString.


14-18: LGTM: Idempotence of lowercase normalization.

Confirms fromAddressLowercaseOrThrow preserves lowercase.

@enviodev enviodev deleted a comment from coderabbitai bot Sep 12, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
codegenerator/cli/src/config_parsing/human_config.rs (2)

212-217: New field looks good; decide on explicit default vs. implied default.

Docs say “default: checksum” but the type is Option<AddressFormat>. If you want an actual default at deserialization/schema level (and to omit it from YAML when defaulted), consider making the field non-optional with serde+schemars defaults; otherwise tweak the description to “unset = checksum”.

Possible refactor (optional, ripple across callers expected):

-        #[serde(skip_serializing_if = "Option::is_none")]
-        #[schemars(
-            description = "Address format for Ethereum addresses: 'checksum' or 'lowercase' (default: checksum)"
-        )]
-        pub address_format: Option<AddressFormat>,
+        #[serde(
+            default = "default_address_format",
+            skip_serializing_if = "is_default_address_format"
+        )]
+        #[schemars(
+            description = "Address format for Ethereum addresses: 'checksum' or 'lowercase' (default: checksum)"
+        )]
+        pub address_format: AddressFormat,

Add within the same module:

fn default_address_format() -> AddressFormat { AddressFormat::Checksum }
fn is_default_address_format(fmt: &AddressFormat) -> bool {
    matches!(fmt, AddressFormat::Checksum)
}

219-224: Make AddressFormat trivially copyable (and Eq).

Tiny ergonomics win and avoids unnecessary clones in downstream code.

-    #[derive(Debug, Serialize, Deserialize, PartialEq, Clone, JsonSchema)]
+    #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Copy, Clone, JsonSchema)]
     #[serde(rename_all = "lowercase")]
     pub enum AddressFormat {
         Checksum,
         Lowercase,
     }
codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1)

288-289: Consider defaulting migrated configs to lowercase format to align with ecosystem and internal guidance.

Subgraphs and similar tools often use lowercase addresses; we’ve also standardized on lowercase comparisons in configs previously. Setting this to lowercase by default improves consistency and avoids mixed-casing pitfalls.

-        preload_handlers: Some(true),
-        address_format: None,
+        preload_handlers: Some(true),
+        address_format: Some(AddressFormat::Lowercase),

Add import near existing human_config imports:

use crate::config_parsing::human_config::evm::AddressFormat;

Please verify end-to-end that a migrated subgraph with checksummed addresses still matches correctly when address_format: lowercase is set (the pipeline should normalize accordingly). If you prefer to preserve source casing, keep None here but ensure templates/init paths default to lowercase elsewhere per PR discussion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ad22d9 and 79f3ae3.

📒 Files selected for processing (4)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • codegenerator/cli/src/cli_args/init_config.rs
  • codegenerator/cli/src/config_parsing/system_config.rs
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

@JasoonS
Copy link
Contributor Author

JasoonS commented Sep 12, 2025

It should also be a little bit more performant

I just saw that the isAddress function checks if addresses are checksumed and validates the checksum (So it must be more expensive than just a regex) - and therefore I don't think it will be more performant how it is implemented now with lower case 🤔

What would be more performant is to just do a regex to check that it is lowercase and fail if it is not lowercase 🤔 But maybe a bit abrasive to our users to get a runtime error like that.

@JasoonS
Copy link
Contributor Author

JasoonS commented Sep 12, 2025

Tested a few versions, it is definitely better not to use regex, and only very very marginally faster on the function that only allows lower-case (but of course has the big downsides).

  Address lowercase performance
fromStringLowercaseOrThrowOriginal (lowercase) ms: 800
fromStringLowercaseOrThrowLowercaseOnly (lowercase) ms: 798
fromStringLowercaseOrThrowPermissiveRegex (lowercase) ms: 879
    ✔ lowercase inputs across all three (2498ms)
fromStringLowercaseOrThrowOriginal (checksummed) ms: 918
fromStringLowercaseOrThrowPermissiveRegex (checksummed) ms: 940
    ✔ checksummed inputs across permissive functions (4044ms)
fromStringLowercaseOrThrowOriginal (lowercase input) ms: 885
fromStringLowercaseOrThrowOriginal (checksummed input) ms: 930
fromStringOrThrow (lowercase input) ms: 2096
fromStringOrThrow (checksummed input) ms: 2193
    ✔ Original checksummed vs new permisive functions (8275ms)

@JasoonS JasoonS force-pushed the lower-case-address branch 2 times, most recently from 6ed09d8 to 1dfea0b Compare September 12, 2025 14:38
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (8)
codegenerator/cli/templates/static/greeter_template/rescript/config.yaml (1)

33-35: Wording + EOF newline

  • Recommend softening the perf claim to reflect the marginal/conditional nature.
  • Add trailing newline to satisfy YAMLlint.

Apply:

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: consider lowercasing the example addresses above to match this setting and prior casing consistency learnings.

codegenerator/cli/templates/static/greeter_template/javascript/config.yaml (1)

33-35: Wording + EOF newline

Same as the Rescript greeter: soften perf claim and add trailing newline.

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: lowercase the two example contract addresses to align with address_format.

codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1)

33-35: Wording + EOF newline

Adjust the comment and fix the missing newline at EOF.

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: lowercase the example addresses for consistency with the configured format.

codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1)

22-24: Wording + EOF newline

Tweak the perf phrasing and add a trailing newline.

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: lowercase the UNI token address above to match the configured format.

codegenerator/cli/templates/static/erc20_template/javascript/config.yaml (1)

22-24: Wording + EOF newline

Same adjustments as other EVM templates.

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: lowercase the UNI token address above to align with the configured format.

codegenerator/cli/templates/static/erc20_template/rescript/config.yaml (1)

22-24: Wording + EOF newline

Adjust perf phrasing and add a trailing newline.

-# using lowercase addresses is slightly faster
+# lowercase may be marginally faster in some setups; also improves Subgraph/Ponder compatibility
 address_format: lowercase
+

Optional: lowercase the UNI token address above for consistency with the configured format.

codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml (1)

21-21: Add newline at EOF.

YAMLlint flags missing terminal newline.

-address_format: lowercase
+address_format: lowercase
+
scenarios/test_codegen/test/AddressLowercase_test.res (1)

3-19: Tests cover the critical paths for lowercase helpers. LGTM.

Covers valid mixed-case input, invalid input, and Address->lowercase roundtrip.

Consider adding one more case for a checksummed input that differs only by checksum (e.g., mixed casing) to ensure normalization is always lowercase.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79f3ae3 and 1dfea0b.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (5 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (3 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (2 hunks)
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml (1 hunks)
  • scenarios/test_codegen/rescript.json (1 hunks)
  • scenarios/test_codegen/test/AddressLowercase_test.res (1 hunks)
  • scenarios/test_codegen/test/Config_test.res (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • scenarios/test_codegen/rescript.json
🚧 Files skipped from review as they are similar to previous changes (11)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs
  • codegenerator/cli/src/cli_args/init_config.rs
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to config.yaml : Enable preload_handlers: true when using Effect API for external calls

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/config.yaml : Enable preload optimizations by adding preload_handlers: true in config.yaml

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : Enable preload optimizations by adding `preload_handlers: true` in config.yaml

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/config.yaml : Add `preload_handlers: true` to config.yaml to enable preload optimisations

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
🪛 YAMLlint (1.37.1)
codegenerator/cli/templates/static/greeter_template/rescript/config.yaml

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/erc20_template/rescript/config.yaml

[error] 24-24: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/greeter_template/typescript/config.yaml

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/erc20_template/typescript/config.yaml

[error] 24-24: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/greeter_template/javascript/config.yaml

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/erc20_template/javascript/config.yaml

[error] 24-24: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (6)
codegenerator/cli/src/config_parsing/human_config.rs (2)

219-224: AddressFormat enum is appropriately modeled.

Serde lowercasing aligns with YAML values 'checksum' | 'lowercase'.


212-217: Approve — address_format field OK; schema test couldn't be run locally

Public address_format: optional with sensible default (checksum); serde + schemars attrs and docs look correct.

Attempted to run: cargo test -p codegenerator -- test_evm_config_schema -- --nocapture — failed with: "rustup could not choose a version of cargo to run, because one wasn't specified explicitly, and no default is configured." Run rustup default stable if needed and re-run the test locally to confirm evm.schema.json matches the Rust schema.

codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (1)

157-158: Approve: lowercaseAddresses threaded correctly

Threading lowercaseAddresses and negating into ~enableChecksumAddresses is correct; decoder toggle matches intent. Verified HyperSyncSource.make callsite passes ~lowercaseAddresses (codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res:25) and HyperSyncClient.make accepts enableChecksumAddresses (codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res:9,456-460).

codegenerator/cli/src/config_parsing/system_config.rs (3)

417-418: SystemConfig.new field lowercase_addresses added—OK.

Placement is fine; no serialization concerns here.


725-729: Correctly derive lowercase_addresses from EVM address_format.

Defaulting to checksum when None is consistent with docs.


866-867: Fuel default lowercase_addresses = false is sensible.

Fuel path remains unaffected by EVM-only option.

Comment on lines +19 to +21
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Remove EVM-only address_format from Fuel template (breaks schema).

Fuel HumanConfig denies unknown fields and doesn’t define address_format. Keeping this here will make generated Fuel projects fail to parse config.yaml. Also, the comment mentions Ethereum in a Fuel template.

Apply:

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
-address_format: lowercase
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In
codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
around lines 19 to 21, remove the EVM-specific "address_format: lowercase" line
and its Ethereum-specific comment because Fuel HumanConfig rejects unknown
fields; also replace or remove the comment referencing Ethereum so the template
contains only Fuel-relevant config entries and valid comments.

Comment on lines +19 to +21
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fuel template: incorrect “Ethereum addresses” wording and potential schema issue

Same concern as the Fuel TypeScript template: misleading wording and possible schema rejection.

Choose one:

A) Remove:

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
-address_format: lowercase

B) Keep with clear EVM-only note and add newline:

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
+# EVM-only: address format ('checksum' or 'lowercase'). Ignored for Fuel.
 address_format: lowercase
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
# EVM-only: address format ('checksum' or 'lowercase'). Ignored for Fuel.
address_format: lowercase
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In
codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
around lines 19–21, the comment incorrectly says "Ethereum addresses" and may
cause schema confusion; update the comment to refer to "EVM addresses" (or
remove the line if you prefer option A), and if keeping it, add a clear EVM-only
note and a trailing newline after the comment, and ensure the documented values
('checksum' or 'lowercase') match the config schema enum so the YAML won't be
rejected.

Comment on lines +19 to +21
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fuel template mentions “Ethereum addresses” and may introduce a schema mismatch

  • The comment explicitly references Ethereum addresses in a Fuel template; this is misleading.
  • Verify whether fuel.schema.json accepts address_format. If not, this will fail validation.

Two options:

A) Remove the setting from Fuel templates (safest):

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
-address_format: lowercase

B) If the schema supports it and it’s intentionally a no-op, clarify and keep, plus newline:

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
+# EVM-only: address format ('checksum' or 'lowercase'). Ignored for Fuel.
 address_format: lowercase
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Suggested change
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
# EVM-only: address format ('checksum' or 'lowercase'). Ignored for Fuel.
address_format: lowercase
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In
codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
around lines 19 to 21, the inline comment references "Ethereum addresses" and
the file defines address_format: lowercase which may not be valid for Fuel
templates; confirm whether fuel.schema.json actually accepts address_format and
if not remove the entire address_format line (and its Ethereum-specific comment)
from the Fuel template; if the schema does accept it and the field is
intentionally a no-op, change the comment to mention Fuel-specific address
behavior (not Ethereum), keep the setting, and add a trailing newline to the
file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
codegenerator/cli/npm/envio/evm.schema.json (3)

2-3: Add $id for resolvable schema identity (better editor UX).

Including a stable $id helps YAML LS and tooling cache/resolve this schema reliably.

Apply this diff (adjust URL to your final CDN/npm URL on release):

 {
-  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$id": "https://schemas.envio.dev/evm.schema.json",

668-674: Clarify enum semantics for AddressFormat.

Make intent explicit (EIP‑55 vs plain lowercase) to avoid ambiguity in consumers.

Apply this diff:

     "AddressFormat": {
       "type": "string",
+      "description": "Address formatting mode: 'checksum' (EIP-55 validation/normalization) or 'lowercase' (all-hex lowercase without checksum validation).",
       "enum": [
         "checksum",
         "lowercase"
       ]
     }

117-126: Add schema default and examples for address_format (non-behavioral)

Add an advisory default and examples to improve editor/docs UX; this does not change runtime behavior (templates already set explicit values).

Apply this diff:

     "address_format": {
       "description": "Address format for Ethereum addresses: 'checksum' or 'lowercase' (default: checksum)",
+      "default": "checksum",
+      "examples": ["checksum", "lowercase"],
       "anyOf": [
         {
           "$ref": "#/$defs/AddressFormat"
         },
         {
           "type": "null"
         }
       ]
     }

Optional: to restrict use to EVM-only configs, consider a root-level conditional (Draft 2020-12) requiring ecosystem === "evm" when address_format is present.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1dfea0b and 690ca41.

📒 Files selected for processing (3)
  • codegenerator/cli/npm/envio/evm.schema.json (2 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (5 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/src/config_parsing/system_config.rs
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/config.yaml : Add YAML schema validation header to config.yaml: `# yaml-language-server: $schema=./node_modules/envio/evm.schema.json`

Applied to files:

  • codegenerator/cli/npm/envio/evm.schema.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test

@JasoonS JasoonS requested a review from DZakh September 14, 2025 19:13
Copy link
Member

@DZakh DZakh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🎉

But I just thought of viem decoder and RPC data source. I'm not 100% but do you know whether we need to do something with them. Feel free to merge if you think it's fine.

@JasoonS
Copy link
Contributor Author

JasoonS commented Sep 19, 2025

I just thought of viem decoder and RPC data source

Worth testing, I assumed it would lower case them, before being saved still, but worth testing it. Will try that on Monday

@JasoonS JasoonS marked this pull request as draft September 22, 2025 09:21
@JasoonS JasoonS requested a review from DZakh September 25, 2025 07:47
@JasoonS JasoonS marked this pull request as ready for review September 25, 2025 07:47
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
codegenerator/cli/src/commands.rs (4)

339-339: Set HTTP client timeouts to avoid hanging polls.

Requests can hang indefinitely under network issues.

Apply:

-        let client = reqwest::Client::new();
+        let client = reqwest::Client::builder()
+            .timeout(Duration::from_secs(15))
+            .build()
+            .context("Failed to build HTTP client")?;

338-343: Normalize base URL to avoid double slashes.

ENVIO_API_URL ending with “/” yields //api/... paths.

Apply:

-        let base = get_api_base_url();
+        let base = get_api_base_url().trim_end_matches('/').to_string();

365-372: Avoid 4s initial delay before first poll.

You sleep 2s pre-loop and again at loop start. Remove one.

Apply:

-        // Give the UI a brief warm-up before first poll
-        sleep(Duration::from_secs(2)).await;
-
         let mut consecutive_not_found = 0u32;

-        for _ in 0..max_attempts {
-            sleep(poll_interval).await;
+        for _ in 0..max_attempts {
+            sleep(poll_interval).await;

Alternative: keep the pre-loop 2s sleep and move the in-loop sleep to the end of the loop body.


393-411: Fail fast on completed-without-token and on unauthorized.

Prevent silent loops when completed=true but token is missing; also handle 401/403 explicitly.

Apply:

             if resp.status().is_success() {
                 let status: CliAuthStatus = match resp.json().await {
                     Ok(s) => s,
                     Err(_) => continue,
                 };

                 if let Some(err) = status.error {
                     if !err.is_empty() {
                         return Err(anyhow!("authentication error: {}", err));
                     }
                 }

                 if status.completed {
                     if let Some(token) = status.token {
                         println!("{}", token);
                         return Ok(());
+                    } else {
+                        return Err(anyhow!("authentication completed but token missing"));
                     }
                 }
+            } else if resp.status() == StatusCode::UNAUTHORIZED || resp.status() == StatusCode::FORBIDDEN {
+                return Err(anyhow!("authentication unauthorized; please retry login"));
             }
codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1)

456-460: Naming inconsistency: “Checksum” vs “Checksummed”.

Decoder uses enableChecksummedAddresses/disableChecksummedAddresses; your config uses enableChecksumAddresses.

Align naming to reduce confusion (even if not forwarded to the client), e.g., rename to enableChecksummedAddresses across your wrappers/config.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b200cd and de879da.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (30)
  • codegenerator/cli/CommandLineHelp.md (1 hunks)
  • codegenerator/cli/npm/envio/evm.schema.json (2 hunks)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4 hunks)
  • codegenerator/cli/src/cli_args/clap_definitions.rs (1 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/commands.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (5 hunks)
  • codegenerator/cli/src/executor/mod.rs (1 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (8 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (2 hunks)
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml (1 hunks)
  • scenarios/test_codegen/rescript.json (1 hunks)
  • scenarios/test_codegen/test/AddressLowercase_test.res (1 hunks)
  • scenarios/test_codegen/test/Config_test.res (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • scenarios/test_codegen/rescript.json
  • codegenerator/cli/CommandLineHelp.md
🚧 Files skipped from review as they are similar to previous changes (13)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/src/config_parsing/human_config.rs
  • codegenerator/cli/src/cli_args/init_config.rs
  • scenarios/test_codegen/test/AddressLowercase_test.res
🧰 Additional context used
📓 Path-based instructions (4)
codegenerator/cli/templates/{static,dynamic}/codegen/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Edit template versions under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src instead of editing generated/src

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
{codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/config.yaml : Add YAML schema validation header to config.yaml: `# yaml-language-server: $schema=./node_modules/envio/evm.schema.json`

Applied to files:

  • codegenerator/cli/npm/envio/evm.schema.json
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to config.yaml : Enable preload_handlers: true when using Effect API for external calls

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/config.yaml : Enable preload optimizations by adding preload_handlers: true in config.yaml

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : Enable preload optimizations by adding `preload_handlers: true` in config.yaml

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/config.yaml : Add `preload_handlers: true` to config.yaml to enable preload optimisations

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
🧬 Code graph analysis (2)
codegenerator/cli/src/executor/mod.rs (1)
codegenerator/cli/src/commands.rs (1)
  • run_auth (337-415)
codegenerator/cli/src/commands.rs (1)
codegenerator/cli/src/config_parsing/system_config.rs (4)
  • var (67-102)
  • new (60-65)
  • new (1186-1199)
  • new (1481-1486)
🪛 GitHub Actions: Build & Test Scenario
codegenerator/cli/src/cli_args/clap_definitions.rs

[error] 403-403: Test 'check_cli_help_md_is_up_to_date' failed. Please run 'make update-generated-docs' to update the generated CLI documentation.

🔇 Additional comments (12)
codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1)

19-21: Remove the EVM-only address_format block from the Fuel template.

Fuel configs are validated against fuel.schema.json, which does not accept the EVM-only address_format field. Leaving this in place breaks schema validation for anyone bootstrapping the Fuel greeter template, and the accompanying comment is misleading. Please drop the block (or gate it behind the EVM templates only).

-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
-address_format: lowercase
scenarios/test_codegen/test/Config_test.res (1)

12-12: Lowercase flag expectation captured correctly

The generated config now surfaces the flag, and defaulting to false here aligns with the existing mixed-case address fixture. Looks good.

codegenerator/cli/templates/static/codegen/src/UserContext.res (1)

290-296: Correctly respects lowercaseAddresses when validating user-supplied addresses.

Switching between checksum and lowercase validators based on config is correct.

codegenerator/cli/src/executor/mod.rs (1)

119-123: Auth command wiring looks correct.

Executes async flow and adds helpful error context.

codegenerator/cli/npm/envio/evm.schema.json (1)

116-127: Schema surface for address_format added cleanly.

Top-level address_format with AddressFormat enum ("checksum" | "lowercase") integrates without breaking required sets.

Also applies to: 668-674

codegenerator/cli/src/hbs_templating/codegen_templates.rs (3)

1123-1128: Propagates ~lowercaseAddresses into generated NetworkSources.evm.

Correctly emits boolean based on cfg.lowercase_addresses.


1283-1284: Template data includes lowercase_addresses and maps from SystemConfig.

Keeps flag available to all templates and tests.

Also applies to: 1404-1405


1526-1527: Updated test expectations for sources_code to include ~lowercaseAddresses=false.

Ensures stability after adding the new labeled arg.

Also applies to: 1581-1582, 1588-1589, 1621-1622, 1651-1653, 1662-1663

codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (1)

38-43: Correct Handlebars scoping and config propagation for lowercase addresses.

  • Uses ../../../lowercase_addresses under is_evm_ecosystem scope (correct).
  • Threads ~lowercaseAddresses into Config.make.

Also applies to: 79-80

codegenerator/cli/src/cli_args/clap_definitions.rs (1)

69-71: Remove doc update suggestion; docs are current
CommandLineHelp.md already includes “* auth — Authenticate with envio hosted services and print a JWT”, so no update is needed.

Likely an incorrect or invalid review comment.

codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (1)

16-17: Threading lowercaseAddresses through EVM sources looks good — all NetworkSources.evm call sites include ~lowercaseAddresses
Verified repository-wide; no remaining calls missing the new arg.

codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1)

451-461: Constructor option likely ignored by @envio-dev/hypersync-client.

Passing enableChecksumAddresses is probably a no-op; this option isn’t documented/supported.

If the client doesn’t honor this field, drop it from the object you pass and handle casing via the Decoder or upstream normalization.

Minimal change:

 let make = (
   ~url,
   ~apiToken,
   ~httpReqTimeoutMillis,
   ~maxNumRetries,
   ~enableChecksumAddresses=true,
 ) =>
   make({
     url,
-    enableChecksumAddresses,
     bearerToken: apiToken,
     httpReqTimeoutMillis,
     maxNumRetries,
   })

Optionally keep the parameter for API symmetry, but don’t forward it until the client supports it.

Would you like me to also update cfg to remove the field and thread the behavior via Decoder.enableChecksummedAddresses/disableChecksummedAddresses where Decoder is constructed?

Comment on lines 16 to 31
external fromStringLowercaseOrThrow: string => bool = "isAddress"

// Reassign since the function might be used in the handler code
// and we don't want to have a "viem" import there. It's needed to keep "viem" a dependency
// of generated code instead of adding it to the indexer project dependencies.
// Also, we want a custom error message, which is searchable in our codebase.
// Validate that the string is a proper address but return a lowercased value
let fromStringLowercaseOrThrow = string => {
if (fromStringLowercaseOrThrow(string)) {
unsafeFromString(string->Js.String2.toLowerCase)
} else {
Js.Exn.raiseError(
`Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix infinite recursion by aliasing externals before wrapper definitions.

Both wrappers call identically named bindings and will recurse forever at runtime. Alias viem externals (getAddress/isAddress) under different names and call those inside wrappers.

Apply:

 module Evm = {
-  @module("viem")
-  external fromStringOrThrow: string => t = "getAddress"
+  @module("viem")
+  external viemGetAddress: string => t = "getAddress"
@@
-  // NOTE: the function is named to be overshadowed by the one below, so that we don't have to import viem in the handler code
-  @module("viem")
-  external fromStringLowercaseOrThrow: string => bool = "isAddress" 
+  // viem helpers (keep dependency in this package, not user handlers)
+  @module("viem")
+  external viemIsAddress: string => bool = "isAddress"
@@
-  let fromStringLowercaseOrThrow = string => {
-    if (fromStringLowercaseOrThrow(string)) {
+  let fromStringLowercaseOrThrow = string => {
+    if (viemIsAddress(string)) {
       unsafeFromString(string->Js.String2.toLowerCase)
     } else {
       Js.Exn.raiseError(
         `Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
       )
     }
   }
@@
   let fromStringOrThrow = string => {
     try {
-      fromStringOrThrow(string)
+      viemGetAddress(string)
     } catch {
     | _ =>
       Js.Exn.raiseError(
         `Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
       )
     }
   }

Also applies to: 40-49

🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/Address.res around lines 16 to 31 (and
similarly lines 40 to 49), the wrapper functions are shadowing the externals and
causing infinite recursion; alias the imported viem externals before defining
wrappers (e.g., define isAddressExternal/getAddressExternal or similar names
that reference the original externals) and then implement the wrapper functions
to call those aliased externals, preserving the custom error messages and
lowercasing behavior.

Comment on lines 362 to 364
let extra_grace_attempts = 15; // ~30s grace
let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix integer type mismatch in max_attempts calculation (compile error).

Adding i32 (extra_grace_attempts) to u64 causes a type error.

Apply one of the following diffs:

-        let extra_grace_attempts = 15; // ~30s grace
-        let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
+        let extra_grace_attempts: u64 = 15; // ~30s grace
+        let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;

or

-        let extra_grace_attempts = 15; // ~30s grace
-        let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
+        let extra_grace_attempts = 15; // ~30s grace
+        let max_attempts = (session.expires_in.max(0) as u64) / 2 + (extra_grace_attempts as u64);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let extra_grace_attempts = 15; // ~30s grace
let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
let extra_grace_attempts: u64 = 15; // ~30s grace
let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
Suggested change
let extra_grace_attempts = 15; // ~30s grace
let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
let extra_grace_attempts = 15; // ~30s grace
let max_attempts = (session.expires_in.max(0) as u64) / 2
(extra_grace_attempts as u64);
🤖 Prompt for AI Agents
In codegenerator/cli/src/commands.rs around lines 362 to 364, the expression
adds extra_grace_attempts (i32) to a u64 result causing a type mismatch; fix by
making both operands the same unsigned type — either declare
extra_grace_attempts as u64 (e.g. let extra_grace_attempts: u64 = 15;) or cast
it when used (e.g. ... / 2 + extra_grace_attempts as u64); ensure the cast or
changed declaration yields the intended value and that parentheses are used
correctly around the division before the addition.

Comment on lines +22 to +24
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Address format flag conflicts with template address casing

Same issue here: address_format: lowercase mandates lowercase addresses, but the sample contract entry remains checksummed (Line 9). This leaves the generated config in an invalid state. Please align the sample address casing with the flag or keep the flag at checksum.

-# using lowercase addresses is slightly faster
-address_format: lowercase
+# using lowercase addresses is slightly faster
+address_format: checksum
🤖 Prompt for AI Agents
In codegenerator/cli/templates/static/erc20_template/rescript/config.yaml around
lines 22-24 (and note the sample contract address at line 9), the config sets
address_format: lowercase while the example address remains checksummed; make
them consistent by either changing address_format to checksum or converting the
sample contract address on line 9 to a lowercase address (and update any other
example addresses in the file to match), ensuring the address_format value and
example addresses use the same casing.

Comment on lines +22 to +24
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Address format flag conflicts with template address casing

address_format: lowercase requires every configured address to already be lowercase. The template still ships the ERC20 address in its original mixed-case checksum form (Line 9), so a freshly generated project will fail validation/parsing under the new flag. Either keep the sample in checksum mode or lowercase the address to match the flag.

-# using lowercase addresses is slightly faster
-address_format: lowercase
+# using lowercase addresses is slightly faster
+address_format: checksum
🤖 Prompt for AI Agents
In codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
around lines 22-24, the address_format is set to "lowercase" but the template's
sample ERC20 address (line 9) is still in checksum mixed-case form; make these
consistent by either changing address_format to "checksum" or converting the
sample ERC20 address on line 9 to lowercase so the sample complies with the
lowercase requirement; update only one of those places to keep format consistent
across the template.

Comment on lines +33 to +35
# Address format for Ethereum addresses: 'checksum' or 'lowercase'
# using lowercase addresses is slightly faster
address_format: lowercase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Lowercase format flag requires the example addresses to be lowercase as well

Setting address_format: lowercase means the config loader will now expect the contract addresses in this file to already be lowercase. The two sample addresses above remain in checksum case, so a freshly generated project will hit validation errors. Please lowercase the example addresses to keep the template runnable.

-        address: 0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c
+        address: 0x9d02a17de4e68545d3a58d3a20bbbe0399e05c9c
...
-        address: 0xdEe21B97AB77a16B4b236F952e586cf8408CF32A
+        address: 0xdee21b97ab77a16b4b236f952e586cf8408cf32a
🤖 Prompt for AI Agents
In codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
around lines 33 to 35, the config sets address_format: lowercase but the example
contract addresses earlier in the file are still in checksum case; update those
sample addresses to be fully lowercase (replace the two example Ethereum
addresses above this setting with their lowercase equivalents) so the config
loader validation won't fail for freshly generated projects.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
codegenerator/cli/src/config_parsing/entity_parsing.rs (1)

277-286: Duplicate enum detection is broken (always passes).

You pre-fill the set, so inserts never detect dups. This lets duplicate enum values slip through.

Apply:

-        let mut value_set: HashSet<String> = self.values.clone().into_iter().collect();
-
-        let duplicate_values = self
-            .values
-            .clone()
-            .into_iter()
-            .filter(|value| value_set.insert(value.clone()))
-            .collect::<Vec<_>>();
+        let mut value_set: HashSet<String> = HashSet::new();
+        let duplicate_values = self
+            .values
+            .clone()
+            .into_iter()
+            .filter(|value| !value_set.insert(value.clone()))
+            .collect::<Vec<_>>();

Consider adding a test that asserts an error when enum values repeat.

codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (1)

188-207: Decoder instantiated on every call; cache it in the ref

getHscDecoder() never stores the decoder into hscDecoder, so each call re-creates it. Cache once and reuse; also keeps your enable/disableChecksummedAddresses choice stable.

Apply this diff:

 let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
 let getHscDecoder = () => {
   switch hscDecoder.contents {
   | Some(decoder) => decoder
   | None =>
     switch HyperSyncClient.Decoder.fromSignatures(allEventSignatures) {
     | exception exn =>
       exn->ErrorHandling.mkLogAndRaise(
         ~msg="Failed to instantiate a decoder from hypersync client, please double check your ABI or try using 'event_decoder: viem' config option",
       )
     | decoder =>
       if lowercaseAddresses {
         decoder.disableChecksummedAddresses()
       } else {
         decoder.enableChecksummedAddresses()
       }
-      decoder
+      hscDecoder := Some(decoder);
+      decoder
     }
   }
 }
codegenerator/cli/npm/envio/src/sources/RpcSource.res (1)

755-836: Viem path ignores lowercaseAddresses for routing and srcAddress

When lowercaseAddresses=true, eventRouter lookups and emitted srcAddress should use the lowercased form, same as the HyperSync path, otherwise matching can fail.

Apply this diff:

-      await logs
-      ->Belt.Array.keepMap(log => {
+      logs
+      ->Belt.Array.keepMap(log => {
         let topic0 = log.topics->Js.Array2.unsafe_get(0)
+        let routedAddress =
+          if lowercaseAddresses {
+            log.address->Address.Evm.fromAddressLowercaseOrThrow
+          } else {
+            log.address
+          }
 
         switch eventRouter->EventRouter.get(
           ~tag=EventRouter.getEvmEventId(
             ~sighash=topic0->EvmTypes.Hex.toString,
             ~topicCount=log.topics->Array.length,
           ),
           ~indexingContracts,
-          ~contractAddress=log.address,
+          ~contractAddress=routedAddress,
           ~blockNumber=log.blockNumber,
         ) {
 ...
                 Internal.Event({
                   eventConfig: (eventConfig :> Internal.eventConfig),
                   timestamp: block.timestamp,
                   blockNumber: block.number,
                   chain,
                   logIndex: log.logIndex,
                   event: {
                     chainId: chain->ChainMap.Chain.toChainId,
                     params: decodedEvent.args,
                     transaction,
                     // Unreliably expect that the Ethers block fields match the types in HyperIndex
                     // I assume this is wrong in some cases, so we need to fix it in the future
                     block: block->(
                       Utils.magic: Ethers.JsonRpcProvider.block => Internal.eventBlock
                     ),
-                    srcAddress: log.address,
+                    srcAddress: routedAddress,
                     logIndex: log.logIndex,
                   }->Internal.fromGenericEvent,
                 })
🧹 Nitpick comments (17)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (6)

1125-1134: Don’t hardcode shouldUseHypersyncClientDecoder; wire it from cfg and simplify bool formatting

Use the config flag instead of true and pass booleans directly rather than constructing "true"/"false" strings.

-                        "NetworkSources.evm(~chain, ~contracts=[{contracts_code}], \
-                         ~hyperSync={hyper_sync_code}, \
-                         ~allEventSignatures=[{all_event_signatures}]->Belt.Array.concatMany, \
-                         ~shouldUseHypersyncClientDecoder=true, ~rpcs=[{rpcs}], \
-                         ~lowercaseAddresses={})",
-                        if config.lowercase_addresses {
-                            "true"
-                        } else {
-                            "false"
-                        }
+                        "NetworkSources.evm(~chain, ~contracts=[{contracts_code}], \
+                         ~hyperSync={hyper_sync_code}, \
+                         ~allEventSignatures=[{all_event_signatures}]->Belt.Array.concatMany, \
+                         ~shouldUseHypersyncClientDecoder={}, ~rpcs=[{rpcs}], \
+                         ~lowercaseAddresses={})",
+                        config.should_use_hypersync_client_decoder,
+                        config.lowercase_addresses

1107-1121: JSON‑escape RPC URLs to avoid broken generated code on unusual characters

Interpolating rpc.url inside quotes risks breaking the generated Rescript if the URL ever contains quotes or backslashes. Emit a JSON string literal instead.

-                let rpcs = rpcs
-                    .iter()
-                    .map(|rpc| {
-                        format!(
-                            "{{url: \"{}\", sourceFor: {}, syncConfig: {}}}",
-                            rpc.url,
-                            match rpc.source_for {
-                                For::Sync => "Sync",
-                                For::Fallback => "Fallback",
-                            },
-                            rpc_to_sync_config_options(rpc)
-                        )
-                    })
+                let rpcs = rpcs
+                    .iter()
+                    .map(|rpc| {
+                        let url_json = serde_json::to_string(&rpc.url)
+                            .expect("url should serialize to JSON");
+                        let source_for = match rpc.source_for {
+                            For::Sync => "Sync",
+                            For::Fallback => "Fallback",
+                        };
+                        format!(
+                            "{{url: {url_json}, sourceFor: {source_for}, syncConfig: {}}}",
+                            rpc_to_sync_config_options(rpc)
+                        )
+                    })

1535-1536: Add a positive test for lowercaseAddresses=true

Tests cover the default false. Add one config fixture with address_format: lowercase (or equivalent) and assert the generated sources string contains ~lowercaseAddresses=true. This guards the new path and prevents regressions.

Based on learnings

Would you like me to draft the test and a minimal YAML fixture?

Also applies to: 1590-1592, 1597-1599, 1630-1632, 1660-1661, 1671-1672


1023-1025: Unused is_client_decoder argument — align with the new flag or remove

is_client_decoder: _ suggests the param is ignored. Either:

  • thread it to control shouldUseHypersyncClientDecoder, or
  • remove/deprecate it across config to avoid drift.

Confirm intended source of truth for client decoder (old param vs new cfg.should_use_hypersync_client_decoder) to avoid confusion.


965-965: Remove commented field or add a TODO with rationale

// event_decoder: Option<String>, is leftover noise in a serialized struct. Either delete or add a short TODO explaining why it’s intentionally kept commented.


870-872: Fuel ABI transpile string — consider path escaping

Looks fine. If there’s any chance of backticks in paths, consider escaping or switching to JSON string emission for safety (low priority).

codegenerator/cli/src/config_parsing/entity_parsing.rs (1)

269-276: Typo in method name: valididate → validate.

Minor polish; keeps API clear.

Apply:

-    pub fn new(name: String, values: Vec<String>) -> anyhow::Result<Self> {
-        Self { name, values }.valididate()
-    }
+    pub fn new(name: String, values: Vec<String>) -> anyhow::Result<Self> {
+        Self { name, values }.validate()
+    }
@@
-    fn valididate(self) -> anyhow::Result<Self> {
+    fn validate(self) -> anyhow::Result<Self> {
         self.check_duplicate_values()?.check_valid_postgres_name()
     }
codegenerator/cli/src/commands.rs (1)

337-418: Set an HTTP client timeout to avoid indefinite hangs.

Add a sane timeout on the reqwest Client; network hiccups can stall polls.

Example:

-        let client = reqwest::Client::new();
+        let client = reqwest::Client::builder()
+            .timeout(std::time::Duration::from_secs(15))
+            .build()
+            .context("failed to build HTTP client")?;
codegenerator/cli/templates/static/codegen/src/Config.res (2)

117-118: Document the new public config surface.

Add a brief doc comment explaining what is lowered (addresses in DB? event router filters? outputs?) and the incompatibility with viem.


130-144: Micro-nit: unnecessary loop.

The forEach over chains doesn’t use chain; a single if around the block is enough.

-  chains->Array.forEach(chain => {
-    if (
-      lowercaseAddresses &&
-      !shouldUseHypersyncClientDecoder
-    ) {
-      Js.Exn.raiseError(
-        "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
-      )
-    }
-  })
+  if (lowercaseAddresses && !shouldUseHypersyncClientDecoder) {
+    Js.Exn.raiseError(
+      "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
+    )
+  }
scenarios/test_codegen/test/Integration_ts_helpers.res (1)

53-56: Thread from config to avoid drift.

Instead of hardcoding, consider passing lowercaseAddresses/decoder from the top‑level Config to mirror real setups and reduce test maintenance.

scenarios/test_codegen/test/E2EEthNode_test.res (1)

64-67: Add a variant with lowercaseAddresses=true.

Include one E2E that sets lowercaseAddresses=true and asserts stored/emitted addresses are lowercase to exercise the new path.

scenarios/test_codegen/test/RpcSource_test.res (1)

172-177: Cover lowercase address formatting.

Add a companion test with ~lowercaseAddresses=true and assert from/to are lowercased. This ensures the builder and downstream schema honor the flag.

scenarios/test_codegen/test/__mocks__/MockConfig.res (1)

64-67: Confirm mock addresses align with lowercaseAddresses setting

Tests currently set lowercaseAddresses: false and use checksummed addresses in mocks—no change needed now. If you enable lowercaseAddresses: true later, update any static mock addresses to lowercase (e.g. via Address.Evm.fromAddressLowercaseOrThrow) to ensure deterministic matching.

codegenerator/cli/npm/envio/src/sources/RpcSource.res (3)

45-54: In-place miner lowercasing OK; consider parity for any alias fields

Mutation is fine for perf. If any providers alias miner as author, consider normalizing that too in the same branch (low priority).


664-676: Drop superfluous await on plain arrays

await logs is a no-op here; remove for clarity.

Also applies to: 755-756


538-539: Typo: “endipoint” → “endpoint”

Minor logging string fix.

-            "suggestedFix": "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint.",
+            "suggestedFix": "This likely means the RPC url you are using is not responding correctly. Please try another RPC endpoint.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34ba0e7 and 2a2afc8.

📒 Files selected for processing (17)
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4 hunks)
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res (8 hunks)
  • codegenerator/cli/src/commands.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/entity_parsing.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (7 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (15 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/Env.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (3 hunks)
  • scenarios/test_codegen/config.yaml (1 hunks)
  • scenarios/test_codegen/test/E2EEthNode_test.res (2 hunks)
  • scenarios/test_codegen/test/Integration_ts_helpers.res (1 hunks)
  • scenarios/test_codegen/test/RpcSource_test.res (3 hunks)
  • scenarios/test_codegen/test/__mocks__/MockConfig.res (1 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/static/codegen/src/Env.res
🚧 Files skipped from review as they are similar to previous changes (2)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/src/config_parsing/human_config.rs
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/Integration_ts_helpers.res
  • scenarios/test_codegen/test/RpcSource_test.res
  • scenarios/test_codegen/test/__mocks__/MockConfig.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • scenarios/test_codegen/test/E2EEthNode_test.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • scenarios/test_codegen/test/Integration_ts_helpers.res
  • scenarios/test_codegen/test/RpcSource_test.res
  • scenarios/test_codegen/test/__mocks__/MockConfig.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • scenarios/test_codegen/test/E2EEthNode_test.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
scenarios/test_codegen/**/config.yaml

📄 CodeRabbit inference engine (scenarios/test_codegen/.cursor/rules/hyperindex.mdc)

scenarios/test_codegen/**/config.yaml: After changing config.yaml, run: pnpm codegen
Enable preload optimizations by adding preload_handlers: true in config.yaml
If using transaction-level data (e.g., event.transaction.hash), declare it under field_selection.transaction_fields in config.yaml
Annotate config.yaml with the YAML schema directive: # yaml-language-server: $schema=./node_modules/envio/evm.schema.json

Files:

  • scenarios/test_codegen/config.yaml
codegenerator/cli/templates/{static,dynamic}/codegen/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Edit template versions under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src instead of editing generated/src

Files:

  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
{codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/config.yaml : If using transaction-level data (e.g., event.transaction.hash), declare it under field_selection.transaction_fields in config.yaml

Applied to files:

  • scenarios/test_codegen/config.yaml
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to src/**/*.ts : For multichain support, prefix all entity IDs with event.chainId (e.g., `${event.chainId}-${originalId}`), never hardcode chainId=1, pass chainId into helpers, and use chain-specific Bundle IDs like `${chainId}-1`

Applied to files:

  • scenarios/test_codegen/test/__mocks__/MockConfig.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/src/config_parsing/system_config.rs
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/src/config_parsing/system_config.rs
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • codegenerator/cli/src/config_parsing/system_config.rs
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Use `entity_id` fields for relationships instead of entity arrays in the schema

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/schema.graphql : Do not add the entity decorator to GraphQL schema types

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : In GraphQL schema, use `entity_id` fields (e.g., `token_id: String!`) for relationships instead of direct object references

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to schema.graphql : Migrate schema from TheGraph to Envio: remove entity decorators, change Bytes! to String!, keep ID! as ID!, and preserve all business entities

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
🧬 Code graph analysis (1)
codegenerator/cli/src/config_parsing/system_config.rs (1)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
  • network (973-979)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (18)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (4)

365-372: Event filters Rescript types — LGTM

The new eventFiltersArgs/eventFiltersDefinition scaffolding reads clean and keeps types precise.


588-600: Event filter parsing glue — LGTM

The generated call to LogSelection.parseEventFiltersOrThrow with normalized topic filters looks correct.


621-635: HyperSync decoder mapping — LGTM

Index/body mapping into event params is consistent with indexed/non‑indexed ordering.

Please ensure tests cover at least one event with mixed indexed/non‑indexed params.


1290-1292: Verify template wiring and explicit lowercase conversions

  • lowercase_addresses is passed through RegisterHandlers.res.hbs and ConfigYAML.res.hbs and consumed in Config.res, UserContext.res, and NetworkSources.res—but no address.toLowerCase() calls were found; ensure your generated code applies .toLowerCase() when the flag is true.
  • should_use_hypersync_client_decoder is correctly threaded through RegisterHandlers.res.hbs, Config.res, and NetworkSources.res.
codegenerator/cli/src/config_parsing/entity_parsing.rs (2)

193-203: Lifetimes in TypeDef are fine.

Return type now borrows from self; this avoids clones and is sound here.


1472-1475: Test helper lifetime tweaks look good.

Also applies to: 1491-1495

codegenerator/cli/src/config_parsing/system_config.rs (2)

1032-1049: Good, clear error on conflicting HyperSync vs RPC for sync.


726-735: Verify template threading for new flags
Config flags flow correctly through codegen_templates.rs into both static and dynamic codegen templates (e.g. Config.res, UserContext.res, NetworkSources.res, ConfigYAML.res.hbs, RegisterHandlers.res.hbs), but I didn’t find lowercaseAddresses or shouldUseHypersyncClientDecoder in Env.res, nor could I locate a RpcSource.res or any HyperSync* template. Please manually confirm that both flags are exposed in all required templates and source files.

codegenerator/cli/npm/envio/src/bindings/Ethers.res (2)

150-186: Lowercasing from/to/contractAddress is correct and minimal.


150-186: Normalize log.address across all log‐decoding paths when lowercaseAddresses = true.
Currently, only the Hypersync client decoder branch in RpcSource.res lowercases log.address for routing (the routedAddress variable). Everywhere else—convertEthersLogToHyperSyncEvent (using address: log.address), makeEventBatchQueueItem (srcAddress: log.address), and non‐client flows (~contractAddress=log.address)—the raw log.address is used, leading to inconsistent casing and potential mismatches. Update these spots to apply lowercase normalization (e.g. via Address.Evm.fromAddressLowercaseOrThrow or Js.String2.toLowerCase) whenever lowercaseAddresses is enabled.

⛔ Skipped due to learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency
codegenerator/cli/src/commands.rs (1)

365-367: Fix integer type mismatch in max_attempts (compile error).

Use a u64 literal or cast:

-        let extra_grace_attempts = 15; // ~30s grace
+        let extra_grace_attempts: u64 = 15; // ~30s grace
         let max_attempts = (session.expires_in.max(0) as u64) / 2 + extra_grace_attempts;
codegenerator/cli/templates/static/codegen/src/Config.res (1)

186-187: Ensure consumers actually honor the flag.

Double‑check that Address.Evm parsing/formatting, DB layer, and selection config consistently lower-case when this flag is true (match keys and comparisons with toLowerCase()). I can help add an E2E asserting DB/handler outputs are lowercase.

Based on learnings

scenarios/test_codegen/test/RpcSource_test.res (2)

33-36: LGTM on surface expansion.

Good to surface the new options explicitly in RpcSource.make tests.


50-53: Running scripts to locate and inspect Config.make and RpcSource.make definitions.

codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (2)

157-158: Threading lowercaseAddresses into options and make() looks correct

Plumbing the new flag through options and into make() is consistent and straightforward.

Sanity-check that all callers of HyperSyncSource.make pass the new lowercaseAddresses arg (templates and NetworkSources).

Also applies to: 171-172


180-186: Correct polarity: enableChecksumAddresses = !lowercaseAddresses

Good inversion; aligns client response format to the chosen address casing.

codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2)

37-43: Scope for lowercase_addresses is now correct

Using ../../../lowercase_addresses under the current each nesting fixes the prior overshoot and ensures EVM addresses are parsed with the intended helper.


72-81: New Config.make args are properly exposed

lowercaseAddresses and shouldUseHypersyncClientDecoder are passed through; matches downstream expectations.

Regenerate a sample project to confirm these flags appear in the generated Config.make signature and compile cleanly.

Comment on lines 147 to +154
@send
external getTransaction: (t, ~transactionHash: string) => promise<transaction> = "getTransaction"

let makeGetTransactionFields = (~getTransactionByHash) =>
async (log: log): promise<unknown> => {
let transaction = await getTransactionByHash(log.transactionHash)
// Mutating should be fine, since the transaction isn't used anywhere else outside the function
let fields: {..} = transaction->Obj.magic

// Make it compatible with HyperSync transaction fields
fields["transactionIndex"] = log.transactionIndex
fields["input"] = fields["data"]

fields->Obj.magic
let makeGetTransactionFields = (~getTransactionByHash, ~lowercaseAddresses: bool) => async (
log: log,
): promise<unknown> => {
let transaction = await getTransactionByHash(log.transactionHash)
// Mutating should be fine, since the transaction isn't used anywhere else outside the function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle nullable getTransaction results (ethers may return null).

Provider.getTransaction can return null; current type/signature assumes non-null and may crash.

Apply:

-  @send
-  external getTransaction: (t, ~transactionHash: string) => promise<transaction> = "getTransaction"
+  @send
+  external getTransaction: (t, ~transactionHash: string) => promise<Js.nullable<transaction>> = "getTransaction"
@@
-  let makeGetTransactionFields = (~getTransactionByHash, ~lowercaseAddresses: bool) => async (
+  let makeGetTransactionFields = (~getTransactionByHash, ~lowercaseAddresses: bool) => async (
     log: log,
   ): promise<unknown> => {
-    let transaction = await getTransactionByHash(log.transactionHash)
+    let transaction = await getTransactionByHash(log.transactionHash)
+    let transaction =
+      switch transaction {
+      | Js.Nullable.Value(tx) => tx
+      | Js.Nullable.Null
+      | Js.Nullable.Undefined =>
+        Js.Exn.raiseError("getTransaction returned null for " ++ log.transactionHash)
+      }

Also applies to: 150-156

Comment on lines +575 to +584
let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
let getHscDecoder = () => {
switch hscDecoder.contents {
| Some(decoder) => decoder
| None => {
let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
decoder
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Cache the HyperSync decoder and set address mode like HyperSyncSource

getHscDecoder() creates a new decoder every time and doesn’t set address casing behavior. Mirror HyperSyncSource: cache once and toggle checksummed vs lowercase to keep decoded address fields consistent.

Apply this diff:

 let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
 let getHscDecoder = () => {
   switch hscDecoder.contents {
   | Some(decoder) => decoder
-  | None => {
-      let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
-      decoder
-    }
+  | None => {
+      let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
+      // Align decoded address handling with lowercaseAddresses
+      if lowercaseAddresses {
+        decoder.disableChecksummedAddresses()
+      } else {
+        decoder.enableChecksummedAddresses()
+      };
+      hscDecoder := Some(decoder);
+      decoder
+    }
   }
 }
🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/sources/RpcSource.res around lines 575-584,
getHscDecoder currently constructs a new decoder on every call and never updates
hscDecoder.contents or the decoder's address-casing behavior; change it to
create the decoder only once (store it into hscDecoder.contents when None) and
set its address mode to mirror HyperSyncSource (toggle between Checksummed and
Lowercase as used elsewhere — e.g., set decoder.addressMode =
HyperSyncClient.Decoder.AddressMode.Checksummed when checksummed addresses are
expected, otherwise .Lowercase) so decoded address fields remain consistent.

Comment on lines +678 to +699
await logs
->Array.zip(parsedEvents)
->Array.keepMap(((
log: Ethers.log,
maybeDecodedEvent: Js.Nullable.t<HyperSyncClient.Decoder.decodedEvent>,
)) => {
let topic0 = log.topics[0]->Option.getWithDefault("0x0"->EvmTypes.Hex.fromStringUnsafe)
let routedAddress = if lowercaseAddresses {
log.address->Address.Evm.fromAddressLowercaseOrThrow
} else {
log.address
}

switch eventRouter->EventRouter.get(
~tag=EventRouter.getEvmEventId(
~sighash=topic0->EvmTypes.Hex.toString,
~topicCount=log.topics->Array.length,
),
~indexingContracts,
~contractAddress=routedAddress,
~blockNumber=log.blockNumber,
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: topic0 extraction uses Option on non-option; also normalize routedAddress here

log.topics is an array; indexing doesn’t return option. Use Js.Array2.unsafe_get(0) like the Viem branch, and keep routedAddress normalization.

Apply this diff:

-      await logs
-      ->Array.zip(parsedEvents)
+      logs
+      ->Array.zip(parsedEvents)
       ->Array.keepMap(((
         log: Ethers.log,
         maybeDecodedEvent: Js.Nullable.t<HyperSyncClient.Decoder.decodedEvent>,
       )) => {
-        let topic0 = log.topics[0]->Option.getWithDefault("0x0"->EvmTypes.Hex.fromStringUnsafe)
+        let topic0 = log.topics->Js.Array2.unsafe_get(0)
         let routedAddress = if lowercaseAddresses {
           log.address->Address.Evm.fromAddressLowercaseOrThrow
         } else {
           log.address
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/sources/RpcSource.res around lines 678 to
699, the code incorrectly treats log.topics[0] as an Option and uses
Option.getWithDefault; replace that with Js.Array2.unsafe_get(0) (as in the Viem
branch) to directly extract the first topic, and keep/ensure the routedAddress
normalization logic (using Address.Evm.fromAddressLowercaseOrThrow when
lowercaseAddresses is true) so the EventRouter.get call uses the normalized
address and the correct topic0 string and topicCount.

- event: EmptyFiltersArray(address indexed from)
- event: "WildcardHandlerWithLoader()"
- event: "FilterTestEvent(address indexed addr)"
event_decoder: "hypersync-client" # default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Add preload_handlers and regenerate code.

Good with event_decoder default. Also enable preload optimizations and rerun codegen.

Apply:

 name: test_codegen
 description: Gravatar for Ethereum
 rollback_on_reorg: true
 save_full_history: false
+preload_handlers: true

Then run:

As per coding guidelines.


🏁 Script executed:

pnpm codegen

Length of output: 124


🏁 Script executed:

#!/bin/bash
find . -maxdepth 4 -type f -name package.json

Length of output: 203


🏁 Script executed:

#!/bin/bash
sed -n '1,200p' scenarios/test_codegen/package.json

Length of output: 2120


Enable preload optimizations in test_codegen

Add preload_handlers: true to scenarios/test_codegen/config.yaml and regenerate the generated code:

 name: test_codegen
 description: Gravatar for Ethereum
 rollback_on_reorg: true
 save_full_history: false
+preload_handlers: true

Then run from the package directory:

cd scenarios/test_codegen
pnpm codegen
🤖 Prompt for AI Agents
In scenarios/test_codegen/config.yaml at line 24, the config is missing the
preload_handlers optimization; add the line preload_handlers: true to that file,
save, then regenerate the generated code by running pnpm codegen from the
scenarios/test_codegen package directory (cd scenarios/test_codegen && pnpm
codegen) so the codegen output includes the preload handler optimizations.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
codegenerator/cli/npm/envio/src/sources/RpcSource.res (1)

753-837: Add address normalization to the Viem decoding branch.

The Viem decoding path (lines 755-836) doesn't normalize log.address based on lowercaseAddresses, unlike the HyperSync path. This creates inconsistent address casing across decoding strategies.

Apply this diff to normalize addresses in the Viem branch:

       await logs
       ->Belt.Array.keepMap(log => {
         let topic0 = log.topics->Js.Array2.unsafe_get(0)
+        let routedAddress = if lowercaseAddresses {
+          log.address->Address.Evm.fromAddressLowercaseOrThrow
+        } else {
+          log.address
+        }

         switch eventRouter->EventRouter.get(
           ~tag=EventRouter.getEvmEventId(
             ~sighash=topic0->EvmTypes.Hex.toString,
             ~topicCount=log.topics->Array.length,
           ),
           ~indexingContracts,
-          ~contractAddress=log.address,
+          ~contractAddress=routedAddress,
           ~blockNumber=log.blockNumber,
         ) {

And update the event construction at line 827:

-                    srcAddress: log.address,
+                    srcAddress: routedAddress,
♻️ Duplicate comments (7)
codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1)

19-21: Misleading "Ethereum addresses" comment in Fuel template.

This is a duplicate concern: the past review already flagged that the comment references "Ethereum addresses" in a Fuel template where the ecosystem is fuel (line 3), not EVM. Fuel uses 32-byte ContractIds, not 20-byte Ethereum addresses, making the comment confusing.

As suggested in the previous review, either:

  • Option A: Remove these lines if address_format doesn't apply to Fuel templates
  • Option B: Clarify the comment as "EVM-only" and add a trailing newline

Based on learnings

codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1)

22-24: Address format flag conflicts with template address casing.

The address_format: lowercase setting requires addresses to be lowercase, but the sample ERC20 address on line 9 (0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984) is in mixed-case checksum format. Either change address_format to checksum or lowercase the sample address to maintain consistency.

scenarios/test_codegen/test/E2EEthNode_test.res (1)

13-13: Revert it_only to it before merging.

Using it_only disables all other tests in the suite, which will break CI coverage.

Apply this diff:

-  Async.it_only("Complete E2E", async () => {
+  Async.it("Complete E2E", async () => {
codegenerator/cli/templates/static/codegen/src/Config.res (1)

133-143: Validation doesn't check per-source decoder overrides.

This validation iterates over chains but only checks the global shouldUseHypersyncClientDecoder parameter. Individual sources (e.g., RpcSource) can override the decoder setting, so a configuration can pass this check yet still violate the constraint at the source level.

Consider adding the same validation inside RpcSource.make and other source constructors to catch misconfigurations when per-source overrides are used.

Run this script to locate source constructors that accept decoder options:

#!/bin/bash
# Description: Find source constructors that may need validation

# Search for RpcSource.make and similar patterns
ast-grep --pattern $'let make = ($$$) => {
  $$$
}'

# Search for shouldUseHypersyncClientDecoder usage in source files
rg -n "shouldUseHypersyncClientDecoder" --type=rescript -C3
codegenerator/cli/npm/envio/src/bindings/Ethers.res (1)

147-148: Address the nullable getTransaction return type.

This concern was raised in a previous review and remains unresolved. Ethers.js getTransaction can return null for non-existent transactions, but the current binding assumes a non-null result and will crash at runtime.

Apply this fix:

-  @send
-  external getTransaction: (t, ~transactionHash: string) => promise<transaction> = "getTransaction"
+  @send
+  external getTransaction: (t, ~transactionHash: string) => promise<Js.nullable<transaction>> = "getTransaction"

Then update makeGetTransactionFields at line 153:

   let makeGetTransactionFields = (~getTransactionByHash, ~lowercaseAddresses: bool) => async (
     log: log,
   ): promise<unknown> => {
-    let transaction = await getTransactionByHash(log.transactionHash)
+    let txResult = await getTransactionByHash(log.transactionHash)
+    let transaction = switch txResult {
+    | Js.Nullable.Value(tx) => tx
+    | Js.Nullable.Null | Js.Nullable.Undefined =>
+      Js.Exn.raiseError("Transaction not found: " ++ log.transactionHash)
+    }
codegenerator/cli/npm/envio/src/sources/RpcSource.res (2)

678-699: Fix topic0 extraction; routedAddress normalization is correct.

Line 684 incorrectly treats log.topics[0] as an option. Since log.topics is an array, indexing returns the element directly.

Apply this diff to fix the extraction:

-        let topic0 = log.topics[0]->Option.getWithDefault("0x0"->EvmTypes.Hex.fromStringUnsafe)
+        let topic0 = log.topics->Js.Array2.unsafe_get(0)

The routedAddress normalization at lines 685-689 is correctly implemented.


575-584: Cache decoder and set address casing mode.

getHscDecoder doesn't cache the decoder or set its address mode. This creates a new decoder on every call and fails to align with lowercaseAddresses.

Apply this diff to cache and configure the decoder:

 let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
 let getHscDecoder = () => {
   switch hscDecoder.contents {
   | Some(decoder) => decoder
   | None => {
       let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
-      decoder
+      if lowercaseAddresses {
+        decoder.disableChecksummedAddresses()
+      } else {
+        decoder.enableChecksummedAddresses()
+      }
+      hscDecoder := Some(decoder)
+      decoder
     }
   }
 }
🧹 Nitpick comments (1)
scenarios/test_codegen/test/AddressLowercase_test.res (1)

1-19: Good baseline test coverage for address lowercase helpers.

The tests correctly validate:

  • Lowercasing of checksummed addresses
  • Error handling for invalid addresses
  • Normalization via fromAddressLowercaseOrThrow

Consider adding tests for additional edge cases:

  • All-uppercase addresses: "0xABCDEF123456..."
  • Already-lowercase addresses (idempotency)
  • Invalid checksum but valid format: "0x2c169DFe5fBbA12957Bdd0Ba47d9CEDbFE260CA7" (mixed case with wrong checksum)
  • Missing 0x prefix handling

These would provide more comprehensive coverage of the address validation and normalization logic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a2afc8 and 8ed9ee5.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • codegenerator/cli/npm/envio/evm.schema.json (2 hunks)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4 hunks)
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res (8 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/entity_parsing.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (7 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (15 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/Env.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (3 hunks)
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml (1 hunks)
  • scenarios/test_codegen/config.yaml (1 hunks)
  • scenarios/test_codegen/rescript.json (1 hunks)
  • scenarios/test_codegen/test/AddressLowercase_test.res (1 hunks)
  • scenarios/test_codegen/test/Config_test.res (1 hunks)
  • scenarios/test_codegen/test/E2EEthNode_test.res (2 hunks)
  • scenarios/test_codegen/test/Integration_ts_helpers.res (1 hunks)
  • scenarios/test_codegen/test/RpcSource_test.res (3 hunks)
  • scenarios/test_codegen/test/__mocks__/MockConfig.res (1 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/static/codegen/src/Env.res
🚧 Files skipped from review as they are similar to previous changes (17)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • scenarios/test_codegen/test/mocks/MockConfig.res
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • scenarios/test_codegen/rescript.json
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • scenarios/test_codegen/test/RpcSource_test.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • scenarios/test_codegen/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/E2EEthNode_test.res
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • scenarios/test_codegen/test/Integration_ts_helpers.res
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • scenarios/test_codegen/test/E2EEthNode_test.res
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • scenarios/test_codegen/test/Integration_ts_helpers.res
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/Address.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
codegenerator/cli/templates/{static,dynamic}/codegen/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Edit template versions under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src instead of editing generated/src

Files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
{codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to config.yaml : Enable preload_handlers: true when using Effect API for external calls

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • scenarios/test_codegen/test/AddressLowercase_test.res
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
🔇 Additional comments (24)
codegenerator/cli/src/config_parsing/entity_parsing.rs (1)

36-39: LGTM: Lifetime annotation refinements improve type safety.

The lifetime annotations have been updated consistently across TypeDef, try_get_type_def, and test helpers. Using the anonymous lifetime '_ is idiomatic and allows the compiler to infer lifetimes from context without changing behavior.

Also applies to: 193-203, 472-475, 1491-1495

codegenerator/cli/templates/static/codegen/src/UserContext.res (1)

288-299: LGTM: Address validation correctly respects the lowercase configuration.

The conditional logic properly validates addresses according to the lowercaseAddresses config flag, using fromAddressLowercaseOrThrow when enabled and fromAddressOrThrow otherwise. The EVM-specific scoping is appropriate, and the comment accurately describes the behavior.

Based on learnings

scenarios/test_codegen/test/Config_test.res (1)

12-12: LGTM: Test correctly includes the new configuration field.

The addition of lowercaseAddresses: false to the expected config aligns with the new address formatting feature and its default value.

scenarios/test_codegen/test/Integration_ts_helpers.res (1)

53-55: LGTM: RpcSource configuration correctly includes new fields.

The three new fields (allEventSignatures, shouldUseHypersyncClientDecoder, lowercaseAddresses) are properly initialized with sensible defaults for the test scenario. The inline comments clearly document their purpose.

codegenerator/cli/src/cli_args/init_config.rs (1)

174-174: LGTM! Appropriate initialization for new field.

Setting address_format: None during contract import initialization is correct and consistent with other optional fields in the HumanConfig struct.

scenarios/test_codegen/test/E2EEthNode_test.res (1)

64-66: LGTM! Appropriate test configuration for new fields.

The new fields are correctly initialized:

  • allEventSignatures: [] provides required initialization
  • shouldUseHypersyncClientDecoder: false explicitly selects VIEM decoder (as noted in comment)
  • lowercaseAddresses: false is a safe default for this E2E test
codegenerator/cli/templates/static/codegen/src/Config.res (3)

117-117: LGTM! New field added to config type.

The lowercaseAddresses boolean field is appropriately added to the config type.


130-131: LGTM! Reasonable parameter defaults.

The default values are appropriate:

  • lowercaseAddresses=false maintains backward compatibility
  • shouldUseHypersyncClientDecoder=true aligns with existing behavior

186-186: LGTM! Field correctly propagated to config.

The lowercaseAddresses field is properly included in the returned configuration object.

codegenerator/cli/npm/envio/evm.schema.json (2)

117-127: LGTM! Address format configuration looks good.

The schema correctly introduces the new address_format field as an optional configuration with proper enum constraints. The description clearly communicates the default behavior (checksum) to users.


668-674: AddressFormat enum definition is correct.

The enum properly defines the two supported variants with lowercase serialization. This aligns with the configuration surface introduced in the Rust config parsing.

codegenerator/cli/npm/envio/src/bindings/Ethers.res (1)

150-185: Lowercasing logic is correct, but verify the performance concern.

The implementation correctly handles nullable fields when lowercasing addresses. However, the inline comment (lines 161-163) notes this may be wasteful when these fields aren't selected in user config.

According to the PR comments, microbenchmarks showed minimal performance difference between implementations. However, to confirm this isn't a concern in practice, consider:

  1. Are the selected transaction fields available at this call site to enable conditional lowercasing?
  2. Would the added complexity of conditional field processing be worth any performance gain?

Based on the PR discussion showing only ~85ms difference between lowercase and checksummed inputs (885ms vs 930ms), the current approach seems acceptable unless profiling reveals this as a bottleneck.

codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (1)

9-57: LGTM! Proper propagation of address format configuration.

The lowercaseAddresses parameter is correctly threaded through to both HyperSync and RPC sources. The cleanup of shouldUseHypersyncClientDecoder handling (passing directly rather than unwrapping inline) improves readability.

codegenerator/cli/src/config_parsing/human_config.rs (2)

215-226: LGTM! AddressFormat configuration is well-defined.

The Rust configuration correctly introduces:

  • AddressFormat enum with appropriate variants
  • Optional address_format field on HumanConfig
  • Proper serde attributes for lowercase serialization
  • Schema generation support via JsonSchema derive

This aligns with the schema changes and follows the naming suggested in prior review feedback.


87-90: Minor improvement to description clarity.

The updated description for start_block is clearer and more accurate.

codegenerator/cli/npm/envio/src/Address.res (2)

14-31: LGTM! Consistent overshadowing pattern for lowercase address validation.

The external binding and wrapper follow the established pattern: the external isAddress is called within the wrapper (line 24) before being shadowed by the let definition, avoiding a viem dependency in handler code while providing validation and lowercasing.


33-34: LGTM! Convenience wrapper consistent with existing pattern.

The wrapper correctly composes toString with fromStringLowercaseOrThrow, matching the pattern used by fromAddressOrThrow at line 51.

codegenerator/cli/npm/envio/src/sources/RpcSource.res (3)

19-54: Address lowercasing in getKnownBlockWithBackoff is acceptable for RPC sync.

The in-place mutation of result.miner using Obj.magic is pragmatic for the RPC sync path. The comment at lines 47-50 acknowledges the potential waste when the miner field isn't selected in the user's config.


459-483: LGTM! Configuration fields properly threaded through RpcSource.

The new allEventSignatures, shouldUseHypersyncClientDecoder, and lowercaseAddresses fields are correctly added to the options type and destructured in the make function signature.


518-543: LGTM! blockLoader correctly threads lowercaseAddresses.

The blockLoader initialization properly passes ~lowercaseAddresses to getKnownBlockWithBackoff at line 526, ensuring consistent address casing behavior.

codegenerator/cli/src/hbs_templating/codegen_templates.rs (4)

1290-1291: LGTM! New configuration flags properly added to ProjectTemplate.

The lowercase_addresses and should_use_hypersync_client_decoder fields are correctly typed and initialized from config at lines 1412-1413.


1123-1135: LGTM! NetworkSources.evm correctly emits lowercaseAddresses flag.

The conditional at lines 1130-1134 correctly interpolates "true" or "false" into the ~lowercaseAddresses={} placeholder based on config.lowercase_addresses.


1535-1671: LGTM! Test expectations correctly updated for new flag.

All test cases (lines 1535, 1590, 1597, 1630, 1660, 1671) now expect ~lowercaseAddresses=false in the generated NetworkSources.evm strings, consistent with the default configuration.


1022-1026: LGTM! Ignoring is_client_decoder in pattern match is acceptable.

The pattern at line 1024 correctly ignores is_client_decoder using _, as this field isn't needed for this specific emission logic. The field is properly utilized elsewhere in the template generation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (8)
codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1)

19-21: Remove EVM-specific address_format from Fuel template.

This configuration is misleading and potentially broken. The address_format option is designed for EVM chains (as discussed in the PR objectives), but this is a Fuel template. Fuel uses a different address format (typically bech32m), not EVM checksummed or lowercase hex addresses.

Apply this diff to remove the configuration:

 preload_handlers: true
-# Address format for Ethereum addresses: 'checksum' or 'lowercase'
-# using lowercase addresses is slightly faster
-address_format: lowercase

If the schema permits this field for Fuel configs (which would be a schema design issue), you should still remove it to avoid user confusion.

codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1)

33-35: Example addresses must be lowercased to match the configured format.

The address_format: lowercase setting has been added, but the example contract addresses at lines 19 and 24 remain in checksum format. This inconsistency will cause validation errors when users generate a project from this template.

This issue was previously flagged and remains unresolved. Please update the example addresses to lowercase:

-        address: 0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c
+        address: 0x9d02a17de4e68545d3a58d3a20bbbe0399e05c9c

and

-        address: 0xdEe21B97AB77a16B4b236F952e586cf8408CF32A
+        address: 0xdee21b97ab77a16b4b236f952e586cf8408cf32a
scenarios/test_codegen/config.yaml (1)

1-6: Consider adding preload optimization.

Per coding guidelines, consider adding preload_handlers: true to enable preload optimizations. This would be placed after Line 5 as a new top-level config field.

Apply this diff if desired:

 name: test_codegen
 description: Gravatar for Ethereum
 rollback_on_reorg: true
 save_full_history: false
+preload_handlers: true

As per coding guidelines.

codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1)

451-464: Verify constructor option 'enableChecksumAddresses' exists.

The wrapper forwards enableChecksumAddresses to the @envio-dev/hypersync-client constructor (Line 460), but per past review, there's no evidence this option exists in the client library. If the option doesn't exist, it will be silently ignored and the checksummed-address behavior won't be controlled.

The web search did not find documentation for the enableChecksumAddresses constructor option. Let me search the GitHub source code directly:

#!/bin/bash
# Search the hypersync-client-node repository for enableChecksumAddresses or related config
rg -n "enableChecksum" --type ts --type js
codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1)

22-24: Address format flag conflicts with template address casing.

The address_format: lowercase flag requires all configured addresses to be lowercase, but the sample ERC20 address on Line 9 remains in checksum (mixed-case) format. Either change address_format back to checksum or lowercase the address on Line 9 to match the flag.

codegenerator/cli/npm/envio/src/bindings/Ethers.res (1)

147-148: Handle nullable getTransaction results.

Provider.getTransaction can return null when a transaction is not found. The current type signature assumes non-null and may cause runtime errors. Update the external to return promise<Js.nullable<transaction>> and handle the null case in makeGetTransactionFields.

Apply this diff:

 @send
-external getTransaction: (t, ~transactionHash: string) => promise<transaction> = "getTransaction"
+external getTransaction: (t, ~transactionHash: string) => promise<Js.nullable<transaction>> = "getTransaction"

Then add null handling in makeGetTransactionFields after Line 153:

 let transaction = await getTransactionByHash(log.transactionHash)
+let transaction = switch transaction {
+| Js.Nullable.Value(tx) => tx
+| Js.Nullable.Null | Js.Nullable.Undefined =>
+  Js.Exn.raiseError("getTransaction returned null for " ++ log.transactionHash)
+}
codegenerator/cli/npm/envio/src/sources/RpcSource.res (2)

575-584: Critical: decoder never cached and address mode not set.

The getHscDecoder creates a new decoder on every call but never stores it in the hscDecoder ref. Additionally, it doesn't configure address casing behavior based on lowercaseAddresses.

Apply this diff to cache the decoder and set address mode:

 let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
 let getHscDecoder = () => {
   switch hscDecoder.contents {
   | Some(decoder) => decoder
   | None => {
       let decoder = HyperSyncClient.Decoder.fromSignatures(allEventSignatures)
+      if lowercaseAddresses {
+        decoder.disableChecksummedAddresses()
+      } else {
+        decoder.enableChecksummedAddresses()
+      }
+      hscDecoder := Some(decoder)
       decoder
     }
   }
 }

Based on past review comments.


678-699: Critical: topic0 extraction incorrectly uses Option; also ensure routedAddress normalization.

Line 684 treats log.topics[0] as returning an Option, but array indexing doesn't return option types. Use Js.Array2.unsafe_get(0) to extract the first topic (as done in the Viem branch at line 757).

Apply this diff:

-      await logs
+      logs
       ->Array.zip(parsedEvents)
       ->Array.keepMap(((
         log: Ethers.log,
         maybeDecodedEvent: Js.Nullable.t<HyperSyncClient.Decoder.decodedEvent>,
       )) => {
-        let topic0 = log.topics[0]->Option.getWithDefault("0x0"->EvmTypes.Hex.fromStringUnsafe)
+        let topic0 = log.topics->Js.Array2.unsafe_get(0)
         let routedAddress = if lowercaseAddresses {
           log.address->Address.Evm.fromAddressLowercaseOrThrow
         } else {
           log.address
         }

Based on past review comments.

🧹 Nitpick comments (3)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (2)

964-964: Remove or clarify commented field.

The commented event_decoder field adds no value without context. Either remove it if it's not needed, or add a TODO comment explaining why it's reserved for future use.

-    // event_decoder: Option<String>,

1024-1024: Remove or wire through the is_client_decoder flag

In codegenerator/cli/src/hbs_templating/codegen_templates.rs at line 1024 the is_client_decoder field is destructured but ignored, and ~shouldUseHypersyncClientDecoder=true is hard-coded at line 1128. Either drop is_client_decoder from the DataSource::Evm enum if it’s obsolete, or pass its value into the template instead.

codegenerator/cli/templates/static/codegen/src/Config.res (1)

137-146: Validation loop is unnecessary.

The validation checks global parameters lowercaseAddresses and shouldUseHypersyncClientDecoder, but iterates over chains without using the loop variable. This repeats the same check once per chain. Since both flags are function-level parameters, validate once before iterating.

Apply this diff:

+  // Validate that lowercase addresses is not used with viem decoder
+  if (
+    lowercaseAddresses &&
+    !shouldUseHypersyncClientDecoder
+  ) {
+    Js.Exn.raiseError(
+      "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
+    )
+  }
+
-  // Validate that lowercase addresses is not used with viem decoder
-  chains->Array.forEach(chain => {
-    if (
-      lowercaseAddresses &&
-      !shouldUseHypersyncClientDecoder
-    ) {
-      Js.Exn.raiseError(
-        "lowercase addresses is not supported when event_decoder is 'viem'. Please set event_decoder to 'hypersync-client' or change address_format to 'checksum'.",
-      )
-    }
-  })
-
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ed9ee5 and a001786.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • codegenerator/cli/npm/envio/evm.schema.json (2 hunks)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res (1 hunks)
  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4 hunks)
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res (8 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/entity_parsing.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (3 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (7 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (15 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs (2 hunks)
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs (2 hunks)
  • codegenerator/cli/templates/static/codegen/src/Config.res (3 hunks)
  • codegenerator/cli/templates/static/codegen/src/Env.res (0 hunks)
  • codegenerator/cli/templates/static/codegen/src/UserContext.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res (3 hunks)
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml (1 hunks)
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml (1 hunks)
  • scenarios/test_codegen/config.yaml (1 hunks)
  • scenarios/test_codegen/rescript.json (1 hunks)
  • scenarios/test_codegen/test/AddressLowercase_test.res (1 hunks)
  • scenarios/test_codegen/test/Config_test.res (1 hunks)
  • scenarios/test_codegen/test/E2EEthNode_test.res (2 hunks)
  • scenarios/test_codegen/test/Integration_ts_helpers.res (1 hunks)
  • scenarios/test_codegen/test/RpcSource_test.res (3 hunks)
  • scenarios/test_codegen/test/__mocks__/MockConfig.res (1 hunks)
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/static/codegen/src/Env.res
✅ Files skipped from review due to trivial changes (1)
  • scenarios/test_codegen/rescript.json
🚧 Files skipped from review as they are similar to previous changes (17)
  • scenarios/test_codegen/test/E2EEthNode_test.res
  • codegenerator/cli/templates/static/erc20_template/rescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/javascript/config.yaml
  • scenarios/test_codegen/test/mocks/MockConfig.res
  • codegenerator/cli/templates/dynamic/codegen/src/ConfigYAML.res.hbs
  • scenarios/test_codegen/test/Integration_ts_helpers.res
  • codegenerator/cli/src/cli_args/init_config.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/config.yaml
  • codegenerator/cli/templates/static/codegen/src/UserContext.res
  • codegenerator/cli/npm/envio/evm.schema.json
  • codegenerator/cli/templates/static/codegen/src/eventFetching/NetworkSources.res
  • codegenerator/cli/templates/dynamic/codegen/src/RegisterHandlers.res.hbs
  • codegenerator/cli/templates/static/greeter_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/javascript/config.yaml
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/javascript/config.yaml
  • scenarios/test_codegen/test/AddressLowercase_test.res
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • scenarios/test_codegen/test/RpcSource_test.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/Address.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res
  • scenarios/test_codegen/test/RpcSource_test.res
  • codegenerator/cli/templates/static/codegen/src/Config.res
  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/npm/envio/src/sources/HyperSyncClient.res
  • codegenerator/cli/npm/envio/src/sources/RpcSource.res
  • codegenerator/cli/npm/envio/src/Address.res
codegenerator/cli/templates/{static,dynamic}/codegen/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Edit template versions under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src instead of editing generated/src

Files:

  • codegenerator/cli/templates/static/codegen/src/Config.res
scenarios/test_codegen/**/config.yaml

📄 CodeRabbit inference engine (scenarios/test_codegen/.cursor/rules/hyperindex.mdc)

scenarios/test_codegen/**/config.yaml: After changing config.yaml, run: pnpm codegen
Enable preload optimizations by adding preload_handlers: true in config.yaml
If using transaction-level data (e.g., event.transaction.hash), declare it under field_selection.transaction_fields in config.yaml
Annotate config.yaml with the YAML schema directive: # yaml-language-server: $schema=./node_modules/envio/evm.schema.json

Files:

  • scenarios/test_codegen/config.yaml
{codegenerator/cli/src/human_config.rs,codegenerator/cli/src/system_config.rs,codegenerator/cli/src/hbs_templating/codegen_templates.rs}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

When tracking how a value reaches templates, follow human_config.rs → system_config.rs → hbs_templating/codegen_templates.rs

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/Config.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/npm/envio/src/bindings/Ethers.res
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/*.ts : When matching addresses in configuration objects within code, ensure keys are lowercase and compare using address.toLowerCase()

Applied to files:

  • scenarios/test_codegen/test/Config_test.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/config.yaml : In config.yaml addresses, use lowercase hex strings for consistency

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
📚 Learning: 2025-09-04T14:42:53.500Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-09-04T14:42:53.500Z
Learning: Applies to config.yaml : Enable preload_handlers: true when using Effect API for external calls

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/greeteronfuel_template/rescript/config.yaml
  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
📚 Learning: 2025-08-11T08:49:57.399Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/test_codegen/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:49:57.399Z
Learning: Applies to scenarios/test_codegen/**/config.yaml : Enable preload optimizations by adding preload_handlers: true in config.yaml

Applied to files:

  • scenarios/test_codegen/config.yaml
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/config.yaml : Add `preload_handlers: true` to config.yaml to enable preload optimisations

Applied to files:

  • scenarios/test_codegen/config.yaml
📚 Learning: 2025-08-11T08:47:04.346Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: scenarios/fuel_test/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:47:04.346Z
Learning: Applies to scenarios/fuel_test/**/*.ts : For address-based config maps in TypeScript, use lowercase keys and compare using `address.toLowerCase()` for consistent matching

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/typescript/config.yaml
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (28)
codegenerator/cli/src/config_parsing/entity_parsing.rs (3)

193-193: LGTM: Correct lifetime annotation.

The anonymous lifetime <'_> properly ties the returned TypeDef reference to the &self borrow, ensuring the borrow checker knows the reference is valid only while the Schema exists.


472-472: LGTM: Correct lifetime annotation for test helper.

The lifetime annotation <'_> correctly reflects that the returned Document borrows from the input schema: &str parameter, which is required by parse_schema.


1491-1495: Lifetime annotation is correct for cloned ObjectType
Cloning the ObjectType<'_, String> yields owned String fields with no borrow from schema_str; the signature’s lifetime parameter is required by the type definition. No changes needed.

codegenerator/cli/src/hbs_templating/codegen_templates.rs (4)

1125-1135: LGTM - lowercaseAddresses threaded correctly.

The conditional logic correctly threads config.lowercase_addresses into the generated NetworkSources.evm call, emitting the appropriate boolean literal.


1290-1291: LGTM - new fields added to ProjectTemplate.

The new boolean fields lowercase_addresses and should_use_hypersync_client_decoder are appropriately typed and follow Rust conventions.


1412-1413: LGTM - fields correctly initialized from SystemConfig.

The fields are correctly mapped from cfg.lowercase_addresses and cfg.should_use_hypersync_client_decoder, completing the flow from human_config → system_config → codegen_templates as per coding guidelines.


1535-1535: LGTM - test expectations updated correctly.

All test cases now correctly expect ~lowercaseAddresses=false in the generated NetworkSources.evm strings, matching the default configuration behavior.

Also applies to: 1590-1590, 1597-1597, 1630-1630, 1660-1660, 1671-1671

scenarios/test_codegen/config.yaml (1)

24-24: LGTM! Event decoder default set correctly.

The addition of event_decoder: "hypersync-client" as a top-level default aligns with the PR's goal to enable configurable address formatting and decoder behavior.

codegenerator/cli/npm/envio/src/bindings/Ethers.res (1)

150-185: LGTM! Lowercase address support added correctly.

The ~lowercaseAddresses: bool parameter is correctly threaded through makeGetTransactionFields and the conditional lowercasing logic for from, to, and contractAddress fields is properly implemented using Js.Nullable pattern matching.

codegenerator/cli/npm/envio/src/Address.res (1)

14-34: LGTM! Lowercase address validation added correctly.

The new fromStringLowercaseOrThrow binding and wrapper leverage viem's isAddress for validation and return a lowercased address. The intentional overshadowing pattern (documented in comments) is correctly applied: the external is invoked before being shadowed by the wrapper, avoiding viem imports in handler code. The companion fromAddressLowercaseOrThrow helper completes the API surface.

scenarios/test_codegen/test/Config_test.res (1)

12-12: LGTM!

Test expectation correctly updated to include the new lowercaseAddresses field with the default value.

codegenerator/cli/templates/static/codegen/src/Config.res (2)

118-118: LGTM!

The lowercaseAddresses field is correctly added to the Config.t type.


190-190: LGTM!

The lowercaseAddresses field is correctly included in the returned config record.

scenarios/test_codegen/test/RpcSource_test.res (3)

33-35: LGTM!

RpcSource.make correctly updated with the new required fields and appropriate test values.


50-52: LGTM!

Test configuration is appropriate, with shouldUseHypersyncClientDecoder: true paired with event signatures.


176-176: LGTM!

The lowercaseAddresses parameter correctly propagates to the Ethers provider bindings.

codegenerator/cli/npm/envio/src/sources/HyperSyncSource.res (4)

157-157: LGTM!

The lowercaseAddresses field is correctly added to the options type.


171-171: LGTM!

Parameter destructuring is correct.


185-185: LGTM!

The boolean inversion !lowercaseAddresses correctly maps to enableChecksumAddresses.


199-203: LGTM!

The conditional decoder configuration correctly applies checksum settings based on lowercaseAddresses.

codegenerator/cli/src/config_parsing/human_config.rs (2)

215-218: LGTM!

The address_format field is correctly added with appropriate attributes and clear documentation.


221-226: LGTM!

The AddressFormat enum is correctly defined with appropriate derives and serialization attributes.

codegenerator/cli/npm/envio/src/sources/RpcSource.res (2)

459-483: LGTM: options type and make signature correctly expanded.

The new fields allEventSignatures, shouldUseHypersyncClientDecoder, and lowercaseAddresses are properly added to the options type and correctly destructured in the make function signature.


753-837: Normalize addresses in Viem decoding branch under lowercaseAddresses
The Viem path (RpcSource.res:765) passes raw log.address to eventRouter.get instead of applying Address.Evm.fromAddressLowercaseOrThrow when lowercaseAddresses is true, unlike the HyperSync branch (RpcSource.res:685–689). Apply the same conditional normalization or confirm that this divergence is intentional.

codegenerator/cli/src/config_parsing/system_config.rs (4)

417-418: LGTM: new config fields properly declared.

The two new boolean fields lowercase_addresses and should_use_hypersync_client_decoder are clearly named and appropriately typed for propagating address format and decoder preferences through the system.


726-735: LGTM: derivation logic correctly implements opt-in lowercase addresses and decoder selection.

The derivation correctly defaults to checksummed addresses (lowercase_addresses = false when address_format is None) and HyperSync client decoder (true when event_decoder is None), aligning with the PR's opt-in design for lowercase addresses.


873-874: LGTM: Fuel defaults and error message formatting appropriate.

Fuel ecosystem correctly defaults to no lowercase address conversion (line 873) and HyperSync decoder (line 874). Error message reformatting at lines 1032-1049 improves readability without changing logic.

Also applies to: 1032-1049


2110-2110: LGTM: test configs correctly updated with address_format field.

Tests properly include address_format: None to use default checksummed behavior, addressing the compile error flagged in past review comments.

Based on past review comments.

Also applies to: 2157-2157

Comment on lines +45 to +53
| result =>
if lowercaseAddresses {
// NOTE: this is wasteful if these fields are not selected in the users config.
// There might be a better way to do this based on the block schema.
// However this is not extremely expensive and good enough for now (only on rpc sync also).
// The in place mutation is cheapest.
(result->Obj.magic)["miner"] = result.miner->Address.Evm.fromAddressLowercaseOrThrow
}
result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify: in-place mutation may affect cached blocks and happens on every fetch.

The miner address is mutated in-place on every successful block fetch (not just after backoff). Since blockLoader is a LazyLoader (line 518), the mutated block may be cached and shared across multiple call sites. This could cause unexpected behavior if the same block is accessed elsewhere expecting checksummed addresses.

Consider returning a transformed copy instead of mutating in-place, or ensure the loader never caches when lowercaseAddresses is enabled.

Run this script to check if the blockLoader cache could be accessed from multiple locations:


🏁 Script executed:

#!/bin/bash
# Check for other usages of blockLoader that might expect unmutated blocks
rg -nC3 'blockLoader->LazyLoader\.get' --type=res

Length of output: 27


Let's rerun the search without the --type filter:


🏁 Script executed:

#!/bin/bash
rg -nC3 'blockLoader' -g '**/*.res'
rg -nC3 'LazyLoader' -g '**/*.res'
rg -nC3 'getKnownBlockWithBackoff' -g '**/*.res'

Length of output: 9687


🏁 Script executed:

#!/bin/bash
sed -n '1,100p' codegenerator/cli/npm/envio/src/sources/RpcSource.res

Length of output: 3708


🏁 Script executed:

#!/bin/bash
# Find LazyLoader implementation
fd LazyLoader.res

Length of output: 46


🏁 Script executed:

#!/bin/bash
sed -n '1,200p' codegenerator/cli/npm/envio/src/LazyLoader.res

Length of output: 4422


🏁 Script executed:

#!/bin/bash
sed -n '400,650p' codegenerator/cli/npm/envio/src/sources/RpcSource.res

Length of output: 8842


Return a new block object instead of mutating the cached record
The in-place mutation in getKnownBlockWithBackoff (RpcSource.res) writes the lower-cased miner into the shared LazyLoader cache, so every later fetch of the same block sees a mutated address even if checksummed values are required. Clone result before altering—e.g.:

let block =
  if lowercaseAddresses {
    {...result, miner: Address.Evm.fromAddressLowercaseOrThrow(result.miner)}
  } else {
    result
  }
block

—or disable caching when lowercaseAddresses is true.

🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/sources/RpcSource.res around lines 45-53, the
function mutates the cached `result` by assigning a lower-cased `miner` into the
shared LazyLoader cache; instead clone `result` before altering so the cache is
not mutated — construct and return a new block object where `miner` is replaced
with Address.Evm.fromAddressLowercaseOrThrow(result.miner) when
`lowercaseAddresses` is true (otherwise return the original `result`), and
remove the in-place Obj.magic mutation; alternatively, if cloning is
undesirable, disable caching/avoid returning cached records when
`lowercaseAddresses` is true.

JasoonS and others added 2 commits September 30, 2025 12:33
Co-authored-by: Dmitry Zakharov <dzakh.dev@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/src/Address.res (1)

14-31: Consider renaming the external to match viem's API for clarity.

The external fromStringLowercaseOrThrow at line 16 binds to viem's isAddress (returns bool) but is shadowed by the let binding at line 23 (returns t). While the overshadowing pattern is intentional to avoid viem imports in handler code, the name mismatch between the external and the viem function creates confusion:

  • Line 12's external fromStringOrThrow clearly maps to getAddress
  • Line 16's external fromStringLowercaseOrThrow maps to isAddress (inconsistent)

Consider renaming the external to isAddress to match viem's API, making the code more maintainable:

- // NOTE: the function is named to be overshadowed by the one below, so that we don't have to import viem in the handler code
  @module("viem")
- external fromStringLowercaseOrThrow: string => bool = "isAddress" 
+ external isAddress: string => bool = "isAddress" 

  // Reassign since the function might be used in the handler code
  // and we don't want to have a "viem" import there. It's needed to keep "viem" a dependency
  // of generated code instead of adding it to the indexer project dependencies.
  // Also, we want a custom error message, which is searchable in our codebase.
  // Validate that the string is a proper address but return a lowercased value
  let fromStringLowercaseOrThrow = string => {
-   if (fromStringLowercaseOrThrow(string)) {
+   if (isAddress(string)) {
      unsafeFromString(string->Js.String2.toLowerCase)
    } else {
      Js.Exn.raiseError(
        `Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
      )
    }
  }

This change eliminates the shadowing of fromStringLowercaseOrThrow while preserving the pattern used for fromStringOrThrow and maintaining the goal of avoiding viem imports in handlers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b594d9b and 6f7033c.

📒 Files selected for processing (1)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/Address.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • codegenerator/cli/npm/envio/src/Address.res
🧠 Learnings (2)
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (3)
codegenerator/cli/npm/envio/src/Address.res (3)

33-34: LGTM!

The fromAddressLowercaseOrThrow implementation correctly converts an address to its lowercase string representation.


40-49: LGTM! Overshadowing pattern is correct.

The fromStringOrThrow wrapper correctly calls the external binding at line 12 before being shadowed. This pattern avoids viem imports in handler code while providing custom error messages, as confirmed in previous discussions.


51-51: LGTM!

The fromAddressOrThrow implementation correctly validates an address by converting to string and calling fromStringOrThrow.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@DZakh DZakh enabled auto-merge (squash) September 30, 2025 11:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/Address.res (2)

14-16: Rename the external binding to avoid confusion.

The external fromStringLowercaseOrThrow binds to viem's isAddress (which returns bool), but the name suggests it returns an address. This is confusing because the wrapper function below (lines 23-31) shadows this name and does return an address.

Consider using a clearer intermediate name like viemIsAddress or isAddressExternal for the external binding, then call that alias in the wrapper. This makes the code more maintainable and reduces confusion for future readers.

Apply this diff:

-  // NOTE: the function is named to be overshadowed by the one below, so that we don't have to import viem in the handler code
   @module("viem")
-  external fromStringLowercaseOrThrow: string => bool = "isAddress"
+  external viemIsAddress: string => bool = "isAddress"

Then update the wrapper to call the alias:

   let fromStringLowercaseOrThrow = string => {
-    if fromStringLowercaseOrThrow(string) {
+    if viemIsAddress(string) {
       unsafeFromString(string->Js.String2.toLowerCase)
     } else {

33-34: Function name is misleading—it doesn't throw.

fromAddressLowercaseOrThrow doesn't validate or throw errors; it simply lowercases an already-valid address. The name suggests validation behavior similar to fromAddressOrThrow (line 51), but this function only transforms the casing.

Consider renaming to toLowercase or asLowercase to clarify that it's a pure transformation without validation.

Apply this diff:

-  let fromAddressLowercaseOrThrow = address =>
+  let toLowercase = address =>
     address->toString->Js.String2.toLowerCase->(Utils.magic: string => t)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1dc3d1 and 7803752.

📒 Files selected for processing (1)
  • codegenerator/cli/npm/envio/src/Address.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/Address.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; compiled .js artifacts can be ignored

Files:

  • codegenerator/cli/npm/envio/src/Address.res
🧠 Learnings (2)
📚 Learning: 2025-08-11T08:42:57.311Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-08-11T08:42:57.311Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Ensure address matching uses consistent casing: use lowercase keys in config objects and compare against `address.toLowerCase()`

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
📚 Learning: 2025-07-22T07:15:55.433Z
Learnt from: CR
PR: enviodev/hyperindex#0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-07-22T07:15:55.433Z
Learning: Never suggest ReasonML syntax.

Applied to files:

  • codegenerator/cli/npm/envio/src/Address.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test

Comment on lines +23 to +31
let fromStringLowercaseOrThrow = string => {
if fromStringLowercaseOrThrow(string) {
unsafeFromString(string->Js.String2.toLowerCase)
} else {
Js.Exn.raiseError(
`Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify viem's isAddress accepts both checksummed and lowercase inputs.

The wrapper validates using isAddress then lowercases the result. Ensure viem's isAddress accepts both checksummed (e.g., 0xAbC...) and lowercase (e.g., 0xabc...) addresses, so users can pass either format.

Based on the PR discussion, this validation path may be more expensive than a simple regex but provides better UX by accepting mixed-case inputs.


🌐 Web query:

Does viem's isAddress function accept both checksummed and lowercase Ethereum addresses?

💡 Result:

Short answer: Yes — but with options.

Details: isAddress(address, { strict?: boolean }) defaults to strict: true, which enforces EIP‑55 checksums. An all-lowercase address will be considered valid only if you call isAddress(..., { strict: false }). [1]

Sources:

  • viem isAddress docs. [1]

Use non-strict validation to accept lowercase addresses
In codegenerator/cli/npm/envio/src/Address.res, update the isAddress call to pass { strict: false }, for example:

let fromStringLowercaseOrThrow = string => {
  if isAddress(string, { strict: false }) {
    unsafeFromString(string->Js.String2.toLowerCase)
  } else {
    Js.Exn.raiseError(
      `Address "${string}" is invalid. Expected a 20-byte hex string starting with 0x.`,
    )
  }
}

This ensures both EIP-55 checksummed and all-lowercase addresses are accepted.

🤖 Prompt for AI Agents
In codegenerator/cli/npm/envio/src/Address.res around lines 23 to 31, the
validation currently rejects valid lowercase Ethereum addresses; update the
boolean check to call isAddress(string, { strict: false }) so the validator
accepts both EIP-55 checksummed and all-lowercase addresses, then keep the
existing unsafeFromString(string->Js.String2.toLowerCase) and error raise logic
unchanged.

@DZakh DZakh merged commit c0a3cb9 into main Sep 30, 2025
2 checks passed
@DZakh DZakh deleted the lower-case-address branch September 30, 2025 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: ability to receive all EVM addresses as lowercase

3 participants