Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@limitofzero
Copy link
Contributor

@limitofzero limitofzero commented Nov 11, 2025

Summary by CodeRabbit

  • New Features

    • Integrated Alchemy as the data provider for token balance retrieval across supported networks (Mainnet, Sepolia, Gnosis, Arbitrum, Polygon, Avalanche, Base, Lens, BNB, Linea).
    • Services now default to the Alchemy-backed token balances provider.
  • Bug Fixes / Reliability

    • Improved validation of provider responses and filtering of invalid or zero token balances for more reliable results.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

Walkthrough

Adds an Alchemy datasource and an Alchemy-backed TokenBalancesRepository, re-exports the repository, and updates the services factory to instantiate the Alchemy implementation instead of the Moralis implementation.

Changes

Cohort / File(s) Summary
Alchemy datasource setup
libs/repositories/src/datasources/alchemy.ts
Adds ALCHEMY_API_KEY (env), ALCHEMY_CLIENT_NETWORK_MAPPING (SupportedChainId → `string
TokenBalancesRepository Alchemy implementation
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts
Adds TokenBalancesRepositoryAlchemy with getTokenBalances({ address, chainId }) and private requestBalanceData. Resolves network, requires API key, POSTs alchemy_getTokenBalances JSON-RPC with timeout, runtime-validates response, converts hex balances to decimal strings, normalizes native token address, filters out zero/invalid balances, and surfaces HTTP/response/validation errors.
Factory and index updates
libs/services/src/factories.ts, libs/repositories/src/index.ts
Replaces Moralis wiring with TokenBalancesRepositoryAlchemy in factory and public exports; factory now returns new TokenBalancesRepositoryAlchemy() and repository index re-exports it.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Repo as TokenBalancesRepositoryAlchemy
    participant Alchemy as Alchemy API

    Client->>Repo: getTokenBalances(address, chainId)
    Repo->>Repo: resolve network (ALCHEMY_CLIENT_NETWORK_MAPPING)
    Repo->>Repo: ensure ALCHEMY_API_KEY set
    Repo->>Alchemy: POST https://{network}.g.alchemy.com/v2/{apiKey} (alchemy_getTokenBalances) with timeout
    Alchemy-->>Repo: HTTP 200 + JSON-RPC result (tokenBalances)
    Repo->>Repo: isAlchemyGetTokenBalancesResponse validation
    Repo->>Repo: map tokenBalances: hex→decimal, normalize native addr, filter zeros/errors
    Repo-->>Client: TokenBalancesResponse (Record<address, balance>)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review focus:
    • isAlchemyGetTokenBalancesResponse runtime type guard and error branches
    • Hex-to-decimal conversion and native address normalization
    • Timeout / AbortController usage and HTTP error handling
    • Behavior when ALCHEMY_API_KEY is missing or mapping yields null

Possibly related PRs

Suggested reviewers

  • alfetopito
  • shoom3301

Poem

🐇 I hopped in code to fetch each dime,
Alchemy hums and hexes turn to prime.
RPCs whisper token streams at night,
I normalize and filter till balances are right.
Little rabbit hops — tests pass in flight ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add alchemy balances provider' directly and clearly describes the main change: introducing a new Alchemy-based token balances provider implementation.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/alchemy-balances-api-integration

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab9c11e and 4957d1d.

📒 Files selected for processing (1)
  • libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts
⏰ 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). (4)
  • GitHub Check: docker (apps/twap)
  • GitHub Check: docker (apps/telegram)
  • GitHub Check: docker (apps/notification-producer)
  • GitHub Check: docker (apps/api)

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

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

@limitofzero limitofzero changed the title feat: add alchemy balances provider [DRAFT] feat: add alchemy balances provider Nov 11, 2025
@limitofzero
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 (6)
libs/services/src/factories.ts (2)

113-113: Unrelated formatting change.

The added trailing comma is a stylistic improvement but appears unrelated to the Alchemy integration.


146-146: Unrelated formatting change.

The added trailing comma is a stylistic improvement but appears unrelated to the Alchemy integration.

libs/repositories/src/datasources/alchemy.ts (1)

26-28: Consider adding input validation to URL builder.

The function assumes valid inputs but doesn't validate them. Consider adding checks for empty strings or injection risks, especially since the network parameter comes from a mapping that can be null.

Apply this diff to add basic validation:

 export function getAlchemyApiUrl(network: string, apiKey: string): string {
+  if (!network || !apiKey) {
+    throw new Error('Network and apiKey are required');
+  }
   return `https://${network}.g.alchemy.com/v2/${apiKey}`;
 }
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (3)

18-32: Consider adding JSDoc for the Alchemy response types.

The type definitions accurately model the Alchemy API response, but adding JSDoc comments would improve maintainability and help developers understand the API contract.

Example:

/**
 * Represents a single token balance from Alchemy API
 * @property contractAddress - The ERC20 token contract address
 * @property tokenBalance - The balance in hex format
 * @property error - Optional error message if balance fetch failed for this token
 */
type AlchemyTokenBalance = {
  contractAddress: string;
  tokenBalance: string;
  error?: string;
};

65-68: Improve error message specificity.

The error message "Unsupported chain" could be more helpful by including the attempted chainId value for debugging.

Apply this diff:

     const network = ALCHEMY_CLIENT_NETWORK_MAPPING[chainId];
     if (!network) {
-      throw new Error('Unsupported chain');
+      throw new Error(`Unsupported chain: ${chainId}`);
     }

78-81: Enhance error message with response details for debugging.

Including the actual response body in the error would significantly aid debugging invalid API responses in production.

Apply this diff:

     const asJson = await response.json();
     if (!isAlchemyGetTokenBalancesResponse(asJson)) {
-      throw new Error('Invalid Alchemy response');
+      throw new Error(`Invalid Alchemy response: ${JSON.stringify(asJson).substring(0, 200)}`);
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6645c75 and d4cd0f7.

📒 Files selected for processing (4)
  • libs/repositories/src/datasources/alchemy.ts (1 hunks)
  • libs/repositories/src/index.ts (1 hunks)
  • libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (1 hunks)
  • libs/services/src/factories.ts (3 hunks)
🔇 Additional comments (9)
libs/repositories/src/index.ts (1)

48-48: LGTM: Export addition follows existing patterns.

The new export for TokenBalancesRepositoryAlchemy is correctly added alongside the existing Moralis export, supporting a clean migration path.

libs/services/src/factories.ts (2)

150-152: LGTM: Factory correctly instantiates Alchemy repository.

The migration from Moralis to Alchemy is clean and maintains the same interface contract.


33-33: No breaking changes from Moralis removal—the factory change is safe.

The search confirms that TokenBalancesRepositoryMoralis is not imported anywhere else in the codebase. The class remains exported from libs/repositories/src/index.ts for external use if needed, but the factory's switch to TokenBalancesRepositoryAlchemy is a localized, non-breaking change with no internal dependencies.

libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (4)

13-16: LGTM: Constants are well-defined.

The constants follow clear naming conventions and use appropriate values for JSON-RPC communication and timeout configuration.


34-57: LGTM: Type guard is thorough.

The validation correctly checks the JSON-RPC structure, result object shape, and ensures tokenBalances is an array. This prevents runtime errors from malformed responses.


72-76: LGTM: HTTP error handling is appropriate.

The check for response.ok and descriptive error message properly handle non-2xx responses.


109-141: Error handling for abort/timeout is properly implemented.

Verification confirms that callers of getTokenBalances handle AbortError appropriately:

  • The API route (primary caller) in balances.ts has a try-catch block that catches all errors thrown by the service, including AbortError
  • When fetch throws AbortError from the abort controller, it propagates through the repository and service layers and is caught at the API route level
  • The error is logged and returns a 500 response with the error message to the client

The implementation is correct as written.

libs/repositories/src/datasources/alchemy.ts (2)

9-24: Verification confirms proper null handling is already in place.

The only consumer of ALCHEMY_CLIENT_NETWORK_MAPPING found in the codebase (TokenBalancesRepositoryAlchemy.ts, line 65) correctly validates the network value with if (!network) { throw new Error('Unsupported chain'); } before use. The PLASMA network mapping's null value is safely handled throughout the codebase.


3-3: ALCHEMY_API_KEY validation is properly enforced.

The verification confirms that the sole consumer of ALCHEMY_API_KEY (in TokenBalancesRepositoryAlchemy.ts) validates its presence at lines 113–115 before use at line 120. The guard throws a clear error if the key is undefined, fully addressing the concern.

@limitofzero
Copy link
Contributor Author

https://github.com/coderabbitai review

@limitofzero limitofzero marked this pull request as ready for review December 1, 2025 16:04
@limitofzero limitofzero changed the title [DRAFT] feat: add alchemy balances provider feat: add alchemy balances provider Dec 1, 2025
@limitofzero limitofzero requested a review from a team December 1, 2025 16:15
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 (1)
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (1)

73-105: Log token-level Alchemy errors instead of silently skipping entries.

When tokenBalance.error is set you currently drop the token without any logging, which makes diagnosing missing balances harder. Consider logging at least a warning with chain and token info before skipping.

Example adjustment:

-    return asJson.result.tokenBalances.reduce((acc, tokenBalance) => {
-      if (tokenBalance.error) {
-        return acc;
-      }
+    return asJson.result.tokenBalances.reduce((acc, tokenBalance) => {
+      if (tokenBalance.error) {
+        logger.warn(
+          `[TokenBalancesRepository] Skipping token ${tokenBalance.contractAddress ?? 'unknown'} on chain ${chainId} due to Alchemy error: ${tokenBalance.error}`
+        );
+        return acc;
+      }

(Adjust log level/message to match your logging conventions.)

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dbfb26 and ab9c11e.

📒 Files selected for processing (1)
  • libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (3)
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepository.ts (3)
  • TokenBalancesRepository (12-14)
  • TokenBalanceParams (5-8)
  • TokenBalancesResponse (10-10)
libs/repositories/src/datasources/alchemy.ts (3)
  • ALCHEMY_CLIENT_NETWORK_MAPPING (9-24)
  • ALCHEMY_API_KEY (3-3)
  • getAlchemyApiUrl (26-28)
libs/shared/src/logger.ts (1)
  • logger (3-3)
⏰ 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). (4)
  • GitHub Check: docker (apps/telegram)
  • GitHub Check: docker (apps/api)
  • GitHub Check: docker (apps/notification-producer)
  • GitHub Check: docker (apps/twap)
🔇 Additional comments (1)
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts (1)

51-72: Good validation and error handling before balance processing.

Using ALCHEMY_CLIENT_NETWORK_MAPPING to gate unsupported chains, checking response.ok, and validating the JSON shape with isAlchemyGetTokenBalancesResponse before reducing balances is a solid pattern and should prevent a lot of hard‑to‑debug failures downstream.

Copy link
Contributor

@alfetopito alfetopito left a comment

Choose a reason for hiding this comment

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

Approved!

You might need to set the ALCHEMY_API_KEY env var in the infrastructure repo

@limitofzero limitofzero merged commit 4b08a9a into main Dec 8, 2025
9 checks passed
@limitofzero limitofzero deleted the feat/alchemy-balances-api-integration branch December 8, 2025 10:57
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.

4 participants