-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add alchemy balances provider #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds 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
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>)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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
chainIdvalue 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
📒 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
TokenBalancesRepositoryAlchemyis 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
TokenBalancesRepositoryMoralisis not imported anywhere else in the codebase. The class remains exported fromlibs/repositories/src/index.tsfor external use if needed, but the factory's switch toTokenBalancesRepositoryAlchemyis 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
tokenBalancesis an array. This prevents runtime errors from malformed responses.
72-76: LGTM: HTTP error handling is appropriate.The check for
response.okand descriptive error message properly handle non-2xx responses.
109-141: Error handling for abort/timeout is properly implemented.Verification confirms that callers of
getTokenBalanceshandleAbortErrorappropriately:
- The API route (primary caller) in
balances.tshas a try-catch block that catches all errors thrown by the service, includingAbortError- When
fetchthrowsAbortErrorfrom 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_MAPPINGfound in the codebase (TokenBalancesRepositoryAlchemy.ts, line 65) correctly validates the network value withif (!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(inTokenBalancesRepositoryAlchemy.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.
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts
Show resolved
Hide resolved
There was a problem hiding this 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.erroris 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
📒 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_MAPPINGto gate unsupported chains, checkingresponse.ok, and validating the JSON shape withisAlchemyGetTokenBalancesResponsebefore reducing balances is a solid pattern and should prevent a lot of hard‑to‑debug failures downstream.
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts
Show resolved
Hide resolved
libs/repositories/src/repos/TokenBalancesRepository/TokenBalancesRepositoryAlchemy.ts
Show resolved
Hide resolved
alfetopito
left a comment
There was a problem hiding this 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
Summary by CodeRabbit
New Features
Bug Fixes / Reliability
✏️ Tip: You can customize this high-level summary in your review settings.