Skip to content
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

feat: bulk fetch metadata & prices for events batch #57

Merged
merged 11 commits into from
Jan 23, 2025

Conversation

0xnigir1
Copy link
Collaborator

@0xnigir1 0xnigir1 commented Jan 21, 2025

🤖 Linear

Closes GIT-241

Description

Currently, we are fetching price/metadata information when processing each event. This is sub-optimal, since we are having the external request delay for each event.
As a better solution, we're fetching all the token/metadata data for a given batch of events prior to start processing that batch. This way, we can query all this data in parallel and have it cached when required during event processing.

Note

This PR has the assumption that we will have really high rate limit API keys for Metadata and Pricing providers to make the most of this feature

Checklist before requesting a review

  • I have conducted a self-review of my code.
  • I have conducted a QA.
  • If it is a core feature, I have included comprehensive tests.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for bulk token price retrieval across multiple timestamps.
    • Enhanced event processing with improved metadata and token price fetching.
    • Implemented round-robin gateway selection for IPFS metadata retrieval.
    • Introduced getTokenPrices method across multiple pricing providers.
    • Added a new constant for minimum granularity in pricing retrieval.
  • Improvements

    • Updated caching mechanism for token prices.
    • Refined error handling in pricing and metadata providers.
    • Introduced new constants and interfaces to support expanded functionality.
  • Technical Enhancements

    • Expanded retry mechanism to return operation results.
    • Added new methods to pricing and metadata providers.
    • Improved event orchestration and processing workflows.
    • Enhanced test coverage for new pricing methods.

@0xnigir1 0xnigir1 self-assigned this Jan 21, 2025
Copy link

linear bot commented Jan 21, 2025

Copy link

coderabbitai bot commented Jan 21, 2025

📝 Walkthrough

Walkthrough

The pull request introduces significant functional changes to the event processing workflow, particularly enhancing the capabilities for fetching metadata and token prices. Key modifications are made to the Orchestrator class, including the introduction of a new type TokenWithTimestamps and methods for bulk fetching metadata and prices for event batches. The event processing workflow is restructured to improve efficiency, including mechanisms for clearing caches after processing. Additionally, the getTokenPrices method is added to the IPricingProvider interface and implemented across multiple pricing providers, further expanding the functionality related to token price retrieval.

Changes

File Change Summary
packages/data-flow/src/orchestrator.ts - Added TokenWithTimestamps type
- Introduced methods for bulk metadata and token fetching
- Modified event processing workflow
packages/pricing/src/interfaces/pricing.interface.ts - Added getTokenPrices method to IPricingProvider interface
packages/pricing/src/providers/* - Implemented getTokenPrices in multiple pricing providers (Coingecko, Dummy, CachingProxy)
packages/metadata/src/providers/ipfs.provider.ts - Added gateway round-robin mechanism with currentGatewayIndex

Assessment against linked issues

Objective Addressed Explanation
Bulk fetch metadata and tokens from events
Filter and query metadata/tokens in parallel
Clear in-memory cache after batch processing

The changes comprehensively address the requirements outlined in GIT-241, implementing a robust mechanism for bulk fetching and processing events with efficient metadata and token price retrieval.

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@0xnigir1 0xnigir1 marked this pull request as draft January 21, 2025 23:17
@0xnigir1
Copy link
Collaborator Author

0xnigir1 commented Jan 21, 2025

@coderabbitai review

Copy link

coderabbitai bot commented Jan 21, 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.

1 similar comment
Copy link

coderabbitai bot commented Jan 21, 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

@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 (8)
packages/shared/src/retry/retry.ts (1)

Line range hint 20-30: Update JSDoc to reflect the return value change.

The method's JSDoc needs to be updated to accurately describe the new return type and possible undefined case.

 * @param operation - Async operation to execute and potentially retry
 * @param params - Optional parameters
 * @param params.abortSignal - Optional AbortSignal to cancel retries
-* @returns Promise that resolves when operation succeeds or max retries exceeded
+* @returns Promise that resolves with the operation result when successful, or undefined
 * @throws RetriableError if max retries exceeded
 * @throws Error if operation aborted or non-retriable error occurs
packages/shared/test/retry/retry.spec.ts (1)

32-32: Add test cases for undefined result scenarios.

While the success case is now properly tested, we should add test cases for scenarios where the operation might return undefined.

Consider adding these test cases:

it("handles undefined result from operation", async () => {
    const handler = new RetryHandler(new ExponentialBackoff(), mockLogger);
    const operation = vi.fn().mockResolvedValue(undefined);
    
    const result = await handler.execute(operation);
    
    expect(result).toBeUndefined();
    expect(operation).toHaveBeenCalledTimes(1);
});

Also applies to: 36-36

packages/pricing/src/providers/cachingProxy.provider.ts (2)

215-244: Consider returning the closest price instead of just the floor value

The current implementation of findClosestPrice returns the floor value (the largest timestamp less than or equal to the target timestamp). This may not always provide the closest price if a price with a slightly larger timestamp is closer to the target. Consider modifying the method to select the price with the minimal absolute difference to the target timestamp.

You could adjust the method as follows:

     // Return the price with the minimal absolute difference to the target timestamp
-    return prices[left]!;
+    if (Math.abs(prices[left]!.timestampMs - targetTimestamp) <= Math.abs(prices[right]!.timestampMs - targetTimestamp)) {
+        return prices[left]!;
+    } else {
+        return prices[right]!;
+    }

124-144: Add JSDoc comments to private methods for better documentation

The new private methods getCachedPrices, getTimestampsToFetch, getClosestPricesWithCache, and buildPriceMap are key to the functionality of the caching provider. Adding JSDoc comments to these methods would improve code readability and maintainability by providing clear explanations of their purpose and usage.

For example:

/**
 * Retrieves cached prices for the given timestamps.
 * @param tokenCode - The token code.
 * @param timestamps - An array of timestamps.
 * @returns An array of settled promises with cached price results.
 */
private async getCachedPrices(
    tokenCode: TokenCode,
    timestamps: number[],
): Promise<PromiseSettledResult<CacheResult>[]> {
    // method implementation...
}

Also applies to: 146-155, 157-185, 187-206

packages/data-flow/src/orchestrator.ts (1)

213-223: Add JSDoc comments to new private methods for clarity

The methods getMetadataFromEvents, getTokensFromEvents, bulkFetchMetadata, and bulkFetchTokens are crucial for the batch processing logic. Including JSDoc comments for these methods would enhance understanding for future maintainers and align with the coding guidelines.

For example:

/**
 * Extracts unique metadata IDs from a list of events.
 * @param events - An array of indexer fetched events.
 * @returns A promise that resolves to an array of metadata IDs.
 */
private async getMetadataFromEvents(events: AnyIndexerFetchedEvent[]): Promise<string[]> {
    // method implementation...
}

Also applies to: 225-254, 338-355, 357-396

packages/pricing/src/interfaces/pricing.interface.ts (1)

29-36: Add error handling documentation.

The JSDoc should document the exceptions that can be thrown, similar to the getTokenPrice method. This helps implementers handle errors consistently.

Add the following to the JSDoc:

     * @param tokenCode - The code of the token.
     * @param timestamps - Array of timestamps for which to retrieve prices.
     * @returns A promise that resolves to the prices of the token for each requested timestamp.
     * The returned prices may not have the exact timestamps requested. Depends on the implementation.
+    * @throws {UnsupportedToken} if the token is not supported by the pricing provider.
+    * @throws {NetworkException} if the network is not reachable.
+    * @throws {UnknownFetchException} if the pricing provider returns an unknown error.
     */
packages/metadata/src/providers/ipfs.provider.ts (1)

40-44: Optimize gateway array creation.

Creating a new array for each metadata fetch is inefficient, especially with high request volumes.

Consider caching the ordered gateways array and updating it only when currentGatewayIndex wraps around:

-        // Create array of gateways starting from current index
-        const orderedGateways = Array.from({ length: this.gateways.length }, () =>
-            this.getNextGateway(),
-        );
+        // Use the next gateway directly
+        const startIndex = this.currentGatewayIndex;
+        for (let i = 0; i < this.gateways.length; i++) {
+            const gateway = this.gateways[(startIndex + i) % this.gateways.length]!;
packages/pricing/src/providers/coingecko.provider.ts (1)

147-197: Consider rate limiting and performance optimizations.

The implementation is solid but could benefit from a few enhancements:

  1. The error message shows "getTokenPrice" instead of "getTokenPrices"
  2. The interval parameter is hardcoded to "5m"
  3. No rate limiting consideration for bulk requests

Consider these improvements:

async getTokenPrices(tokenCode: TokenCode, timestamps: number[]): Promise<TokenPrice[]> {
    const tokenId = TokenMapping[tokenCode];
    if (!tokenId) {
        throw new UnsupportedToken(tokenCode, {
            className: CoingeckoProvider.name,
-           methodName: "getTokenPrice",
+           methodName: "getTokenPrices",
        });
    }

+   // Deduplicate timestamps to minimize API load
+   const uniqueTimestamps = Array.from(new Set(timestamps));
    
-   if (timestamps.length === 0) {
+   if (uniqueTimestamps.length === 0) {
        return [];
    }

-   const effectiveMin = Math.min(...timestamps);
-   let effectiveMax = Math.max(...timestamps);
+   const effectiveMin = Math.min(...uniqueTimestamps);
+   let effectiveMax = Math.max(...uniqueTimestamps);

    if (effectiveMin === effectiveMax || effectiveMin > effectiveMax) {
        return [];
    }

    if (effectiveMax - effectiveMin < MIN_GRANULARITY_MS) {
        effectiveMax = effectiveMin + MIN_GRANULARITY_MS;
    }

+   // Calculate optimal interval based on time range
+   const timeRange = effectiveMax - effectiveMin;
+   const interval = timeRange > 30 * 24 * 60 * 60 * 1000 ? '1d' : '5m';

-   const path = `/coins/${tokenId}/market_chart/range?vs_currency=usd&from=${effectiveMin}&to=${effectiveMax}&precision=full&interval=5m`;
+   const path = `/coins/${tokenId}/market_chart/range?vs_currency=usd&from=${effectiveMin}&to=${effectiveMax}&precision=full&interval=${interval}`;

    try {
        const { data } = await this.axios.get<CoingeckoPriceChartData>(path);
-       return data.prices.map(([timestampMs, priceUsd]) => ({
+       const priceMap = new Map(data.prices.map(([ts, price]) => [ts, price]));
+       return timestamps.map(ts => ({
-           timestampMs,
-           priceUsd,
+           timestampMs: ts,
+           priceUsd: priceMap.get(ts) ?? priceMap.get(findClosestTimestamp(ts, Array.from(priceMap.keys()))) ?? 0,
        }));
    } catch (error: unknown) {
        if (isAxiosError(error)) {
            this.handleAxiosError(error, path);
        }

        const errorMessage =
            `Unknown Coingecko API error: failed to fetch token price ` +
            stringify(error, Object.getOwnPropertyNames(error));

        throw new UnknownPricingException(errorMessage, {
            className: CoingeckoProvider.name,
-           methodName: "getTokenPrice",
+           methodName: "getTokenPrices",
            additionalData: {
                path,
            },
        });
    }
}

Add this helper function:

function findClosestTimestamp(target: number, timestamps: number[]): number {
    return timestamps.reduce((prev, curr) => 
        Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev
    );
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50196d6 and a8f1426.

📒 Files selected for processing (20)
  • packages/data-flow/src/orchestrator.ts (9 hunks)
  • packages/data-flow/test/unit/orchestrator.spec.ts (1 hunks)
  • packages/data-flow/test/unit/retroactiveProcessor.spec.ts (1 hunks)
  • packages/metadata/src/providers/ipfs.provider.ts (3 hunks)
  • packages/pricing/src/constants/index.ts (1 hunks)
  • packages/pricing/src/interfaces/pricing.interface.ts (1 hunks)
  • packages/pricing/src/internal.ts (1 hunks)
  • packages/pricing/src/providers/cachingProxy.provider.ts (3 hunks)
  • packages/pricing/src/providers/coingecko.provider.ts (2 hunks)
  • packages/pricing/src/providers/dummy.provider.ts (1 hunks)
  • packages/processors/test/allo/handlers/poolCreated.handler.spec.ts (1 hunks)
  • packages/processors/test/allo/handlers/poolFunded.handler.spec.ts (1 hunks)
  • packages/processors/test/allo/handlers/poolMetadataUpdated.handler.spec.ts (1 hunks)
  • packages/processors/test/strategy/directAllocation/handlers/directAllocated.handler.spec.ts (1 hunks)
  • packages/processors/test/strategy/directGrantsLite/directGrantsLite.handler.spec.ts (1 hunks)
  • packages/processors/test/strategy/directGrantsLite/handlers/allocated.handler.spec.ts (1 hunks)
  • packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts (1 hunks)
  • packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts (1 hunks)
  • packages/shared/src/retry/retry.ts (2 hunks)
  • packages/shared/test/retry/retry.spec.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/pricing/src/constants/index.ts
🧰 Additional context used
📓 Path-based instructions (19)
packages/pricing/src/internal.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/strategy/directAllocation/handlers/directAllocated.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/allo/handlers/poolFunded.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/shared/test/retry/retry.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/src/providers/dummy.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/data-flow/test/unit/orchestrator.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/metadata/src/providers/ipfs.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/shared/src/retry/retry.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/src/providers/coingecko.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/allo/handlers/poolMetadataUpdated.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/allo/handlers/poolCreated.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/data-flow/src/orchestrator.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/strategy/directGrantsLite/handlers/allocated.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/strategy/directGrantsLite/directGrantsLite.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/src/interfaces/pricing.interface.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/data-flow/test/unit/retroactiveProcessor.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/src/providers/cachingProxy.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

🔇 Additional comments (16)
packages/shared/src/retry/retry.ts (1)

31-32: LGTM! The changes enhance the method's functionality while maintaining type safety.

The modifications to return the operation's result are well-implemented:

  • Proper generic type usage
  • Clear initialization of result variable
  • Consistent error handling
  • Clean return statement placement

Also applies to: 36-36, 65-66

packages/data-flow/src/orchestrator.ts (1)

305-309: Review the necessity of clearing caches before each batch

In bulkFetchMetadataAndPricesForBatch, caches for the metadata and pricing providers are cleared before fetching data for each batch. This could lead to reduced caching benefits and potential performance issues, as cached data from previous batches is discarded. Consider evaluating whether it's necessary to clear the caches before each batch or if the caching strategy can be adjusted to retain useful cached data across batches.

Would you like to review the caching strategy or run a verification to assess the impact of not clearing the caches before each batch?

packages/pricing/src/internal.ts (1)

2-2: Ensure consistent export patterns

The addition of export * from "./constants/index.js"; broadens the module's exports. Verify that this change does not introduce any unintended side effects, such as exposing internal constants that should remain private, and that it aligns with the project's module export practices.

Please confirm that all exported constants are intended to be publicly available and do not conflict with existing exports.

packages/pricing/src/providers/dummy.provider.ts (1)

24-31: LGTM! Clean implementation of bulk price fetching.

The implementation correctly maps each timestamp to a TokenPrice object, maintaining consistency with the single price method. The approach is suitable for testing purposes.

packages/metadata/src/providers/ipfs.provider.ts (1)

11-11: Consider thread safety in multi-instance scenarios.

The currentGatewayIndex could lead to race conditions if multiple instances of IpfsProvider are used concurrently.

Consider using atomic operations or a more robust load balancing mechanism. For example:

  1. Use a connection pool
  2. Implement a stateless round-robin using request timestamp
  3. Use a distributed load balancer
packages/processors/test/allo/handlers/poolFunded.handler.spec.ts (1)

59-59: Add test coverage for bulk price fetching.

The getTokenPrices mock is added but not utilized in any test cases. This leaves the bulk price fetching functionality untested.

Add test cases to verify:

  1. Bulk price fetching behavior
  2. Error handling for bulk requests
  3. Edge cases (empty timestamps array, invalid tokens)
packages/processors/test/allo/handlers/poolMetadataUpdated.handler.spec.ts (1)

71-71: LGTM!

The mock provider correctly implements the updated interface.

packages/processors/test/strategy/directGrantsLite/directGrantsLite.handler.spec.ts (1)

87-87: LGTM!

The mock provider correctly implements the updated interface.

packages/data-flow/test/unit/retroactiveProcessor.spec.ts (2)

147-147: LGTM! Test setup properly updated for bulk token price fetching.

The test setup is correctly updated to include the new getTokenPrices method in the pricingProvider mock, maintaining consistency with the existing getTokenPrice method.


147-147: Add test cases for bulk token price fetching.

While the mock setup is correct, there are no test cases verifying the bulk token price fetching functionality. Consider adding test cases to cover:

  • Successful bulk token price fetching
  • Error handling scenarios
  • Performance comparison with individual fetches

Would you like me to help generate comprehensive test cases for the bulk token price fetching functionality?

packages/data-flow/test/unit/orchestrator.spec.ts (1)

106-106: LGTM! Test setup properly updated for bulk token price fetching.

The test setup is correctly updated to include the new getTokenPrices method in the pricingProvider mock, maintaining consistency with the existing getTokenPrice method.

packages/processors/test/strategy/directAllocation/handlers/directAllocated.handler.spec.ts (1)

44-44: Add tests for bulk price fetching functionality.

The getTokenPrices mock is added but not utilized in any test cases. Consider adding test coverage for bulk price fetching scenarios to ensure the new functionality works as expected.

Would you like me to help generate test cases for bulk price fetching scenarios?

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts (1)

49-49: Add tests for bulk price fetching functionality.

While the file has comprehensive test coverage for existing functionality, the newly added getTokenPrices mock is not utilized in any test cases. Consider adding test coverage for bulk price fetching scenarios.

Would you like me to help generate test cases for bulk price fetching scenarios that align with the existing test patterns in this file?

packages/processors/test/strategy/directGrantsLite/handlers/allocated.handler.spec.ts (1)

44-44: Add tests for bulk price fetching functionality.

The file has thorough test coverage for various scenarios, but the newly added getTokenPrices mock is not utilized. Consider adding test cases for bulk price fetching to maintain the same level of test coverage for the new functionality.

Would you like me to help generate test cases for bulk price fetching that cover similar edge cases as the existing tests?

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.spec.ts (1)

115-115: Add tests for bulk price fetching functionality.

While the file has thorough test coverage for fetchMatchAmount and other functionality, the newly added getTokenPrices mock is not utilized. Consider adding test cases for bulk price fetching scenarios.

Would you like me to help generate test cases for bulk price fetching that integrate with the existing fetchMatchAmount tests?

packages/processors/test/allo/handlers/poolCreated.handler.spec.ts (1)

59-59: Add test coverage for the new getTokenPrices method.

The newly added getTokenPrices method in mockPricingProvider is not covered by any test cases. This method appears to be part of the bulk fetching feature mentioned in the PR objectives.

Let's verify if there are any existing tests for bulk price fetching:

Would you like me to help generate test cases for bulk price fetching scenarios?

@0xnigir1 0xnigir1 marked this pull request as ready for review January 22, 2025 01:22
@0xnigir1
Copy link
Collaborator Author

@coderabbitai review

Copy link

coderabbitai bot commented Jan 22, 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.

@0xnigir1 0xnigir1 requested review from jahabeebs and 0xkenj1 January 22, 2025 01:23
Copy link

@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 (9)
packages/shared/test/retry/retry.spec.ts (1)

39-46: Consider adding logger assertion for completeness.

The test case effectively covers the undefined result scenario. Consider adding an assertion to verify logger behavior for consistency with other test cases:

 expect(result).toBeUndefined();
 expect(operation).toHaveBeenCalledTimes(1);
+expect(mockLogger.debug).not.toHaveBeenCalled();
packages/data-flow/src/orchestrator.ts (7)

37-40: Add JSDoc comments for the new TokenWithTimestamps type.

To enhance code readability and maintainability, please include JSDoc comments explaining the purpose and usage of this new type.


212-223: Add JSDoc comments for getMetadataFromEvents method.

Including JSDoc comments will improve maintainability by documenting the method's purpose, parameters, and return value.


224-255: Add JSDoc comments for getTokensFromEvents method.

Including documentation will aid in understanding and maintaining the code by explaining the method's functionality, parameters, and return value.


Line range hint 284-299: Add JSDoc comments for getNextEventsBatch method.

To maintain consistency and improve readability, please document this method with JSDoc, explaining its purpose, parameters, and return value.


Line range hint 320-335: Add JSDoc comments for enqueueEvents method.

To improve code maintainability, include JSDoc comments describing the purpose, parameters, and behavior of the enqueueEvents method.


336-356: Add JSDoc comments for bulkFetchMetadata method.

Including documentation will aid in understanding and maintaining the code by explaining the method's functionality, parameters, and return type.


358-382: Add JSDoc comments for bulkFetchTokens method.

To maintain consistency and enhance readability, please add JSDoc comments outlining the method's purpose, parameters, and expected outcomes.

packages/pricing/test/providers/coingecko.provider.spec.ts (1)

183-222: Test suite needs additional edge cases.

While the current test coverage is good, consider adding these test cases:

  1. Verify correct price mapping for multiple timestamps
  2. Test behavior when some timestamps are invalid
  3. Test handling of network errors (500 status)

Here's a suggested test case for multiple timestamps:

it("correctly maps prices for multiple timestamps", async () => {
    const timestamps = [1000, 2000, 3000];
    mock.get.mockResolvedValue({
        data: {
            prices: [
                [1000, 1500],
                [2000, 1600],
                [3000, 1700],
            ],
        },
    });

    const result = await provider.getTokenPrices("ETH" as TokenCode, timestamps);
    expect(result).toEqual([
        { timestampMs: 1000, priceUsd: 1500 },
        { timestampMs: 2000, priceUsd: 1600 },
        { timestampMs: 3000, priceUsd: 1700 },
    ]);
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8f1426 and b2202fa.

📒 Files selected for processing (8)
  • packages/data-flow/src/orchestrator.ts (9 hunks)
  • packages/data-flow/test/unit/orchestrator.spec.ts (6 hunks)
  • packages/metadata/src/providers/ipfs.provider.ts (2 hunks)
  • packages/pricing/src/providers/coingecko.provider.ts (2 hunks)
  • packages/pricing/test/providers/cachingProxy.provider.spec.ts (1 hunks)
  • packages/pricing/test/providers/coingecko.provider.spec.ts (1 hunks)
  • packages/pricing/test/providers/dummy.provider.spec.ts (1 hunks)
  • packages/shared/test/retry/retry.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
packages/metadata/src/providers/ipfs.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/test/providers/dummy.provider.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/shared/test/retry/retry.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/test/providers/coingecko.provider.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/test/providers/cachingProxy.provider.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/pricing/src/providers/coingecko.provider.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/data-flow/test/unit/orchestrator.spec.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

packages/data-flow/src/orchestrator.ts (1)

Pattern **/*.ts: Review the TypeScript code for adherence to the following guidelines:
- Avoid over-abstraction that may lead to coupling; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid using any; prefer unknown where necessary.
- Use runtime type-checking for environment variables (e.g., using Zod).
- Follow the internal module pattern to prevent circular dependencies.
- When building libraries, ensure an external.ts file explicitly lists components/types/interfaces to expose, and these are imported/exported in the entry index.ts.
- Use bigint as-is when received from external APIs; only cast to Number if exposing the value through an API.
- Ensure all code components (functions, methods, classes, interfaces) are documented with JSDoc.
- Static Async Factory Functions (async constructors) are encouraged.

🔇 Additional comments (9)
packages/shared/test/retry/retry.spec.ts (1)

32-37: LGTM! Good test enhancement.

The addition of result assertion improves test coverage by verifying both the behavior (operation call count) and the output value.

packages/data-flow/test/unit/orchestrator.spec.ts (3)

775-793: Good test coverage for getMetadataFromEvents.

The tests adequately cover scenarios including duplicates and events without metadata.


796-868: Comprehensive tests for getTokensFromEvents.

The test cases effectively cover duplicates, zero amounts, and invalid tokens, ensuring robust validation of the method's logic.


870-918: Effective testing of bulkFetchMetadataAndPricesForBatch method.

The tests verify both success and failure scenarios, ensuring the orchestrator handles fetch operations correctly even when some fetches fail.

packages/pricing/test/providers/dummy.provider.spec.ts (1)

19-38: Good addition of test cases for getTokenPrices method.

The new tests effectively verify the functionality for both populated and empty timestamps arrays.

packages/pricing/test/providers/cachingProxy.provider.spec.ts (2)

12-14: LGTM! Mock provider correctly implements new interface methods.

The mock provider now implements both getTokenPrices and clearCache methods, aligning with the IPricingProvider & ICacheable interface.


18-19: LGTM! Mock cache correctly implements async behavior.

The mock cache's set method now properly returns a Promise, accurately reflecting the asynchronous nature of cache operations.

packages/pricing/src/providers/coingecko.provider.ts (2)

164-166: LGTM! Proper handling of minimum granularity.

The code correctly adjusts the time range when it's smaller than MIN_GRANULARITY_MS.


151-154: ⚠️ Potential issue

Fix incorrect method name in error context.

The error context references "getTokenPrice" instead of "getTokenPrices".

Apply this fix:

             throw new UnsupportedToken(tokenCode, {
                 className: CoingeckoProvider.name,
-                methodName: "getTokenPrice",
+                methodName: "getTokenPrices",
             });

Likely invalid or redundant comment.

Comment on lines 300 to 319
/**
* Clear caches and fetch metadata and prices for the batch
*/
private async bulkFetchMetadataAndPricesForBatch(
events: AnyIndexerFetchedEvent[],
): Promise<void> {
// Clear caches
if (this.dependencies.metadataProvider.clearCache) {
await this.dependencies.metadataProvider.clearCache();
}

const metadataIds = await this.getMetadataFromEvents(events);
const tokens = await this.getTokensFromEvents(events);

await Promise.allSettled([
this.bulkFetchMetadata(metadataIds),
this.bulkFetchTokens(tokens),
]);
}

Copy link

@coderabbitai coderabbitai bot Jan 22, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle potential errors from bulkFetchMetadata and bulkFetchTokens.

While using Promise.allSettled prevents unhandled promise rejections, you should inspect the results to handle any failures appropriately, such as logging errors or retrying failed operations.

Apply this diff to handle errors from bulkFetchMetadata and bulkFetchTokens:

-        await Promise.allSettled([
+        const results = await Promise.allSettled([
             this.bulkFetchMetadata(metadataIds),
             this.bulkFetchTokens(tokens),
         ]);
+
+        results.forEach((result, index) => {
+            if (result.status === 'rejected') {
+                const operation = index === 0 ? 'bulkFetchMetadata' : 'bulkFetchTokens';
+                this.logger.error(`Error in ${operation}: ${result.reason}`, {
+                    className: Orchestrator.name,
+                    chainId: this.chainId,
+                });
+            }
+        });

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we're fine without handling errors here, this is a performance optimization but in case some fetch fails, we would try one more time to fetch the data on the processor

Copy link

Choose a reason for hiding this comment

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

@0xnigir1 Understood, thanks for explaining the error handling strategy. I'll keep this in mind for future reviews.


✏️ Learnings added
Learnt from: 0xnigir1
PR: defi-wonderland/grants-stack-indexer-v2#57
File: packages/data-flow/src/orchestrator.ts:300-319
Timestamp: 2025-01-22T01:29:58.582Z
Learning: In the Orchestrator's bulkFetchMetadataAndPricesForBatch method, error handling is not required as it's a performance optimization. If the bulk fetch fails, the data will be fetched again during processing in the processor.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@@ -8,6 +8,7 @@ import { EmptyGatewaysUrlsException, InvalidContentException, isValidCid } from

export class IpfsProvider implements IMetadataProvider {
private readonly axiosInstance: AxiosInstance;
private currentGatewayIndex: number = 0;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider thread safety for gateway index.

The currentGatewayIndex should be updated atomically to prevent race conditions in concurrent requests.

Consider using a synchronized method to update the index:

private synchronized updateGatewayIndex(): number {
    this.currentGatewayIndex = (this.currentGatewayIndex + 1) % this.gateways.length;
    return this.currentGatewayIndex;
}

Comment on lines +34 to +36
const startIndex = this.currentGatewayIndex;
for (let i = 0; i < this.gateways.length; i++) {
const gateway = this.gateways[(startIndex + i) % this.gateways.length]!;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve gateway rotation logic.

The current implementation doesn't update currentGatewayIndex after successful requests, which could lead to uneven gateway utilization.

Consider updating the index after successful requests:

-        const startIndex = this.currentGatewayIndex;
-        for (let i = 0; i < this.gateways.length; i++) {
-            const gateway = this.gateways[(startIndex + i) % this.gateways.length]!;
+        const totalGateways = this.gateways.length;
+        for (let attempt = 0; attempt < totalGateways; attempt++) {
+            const gateway = this.gateways[this.currentGatewayIndex]!;
+            this.currentGatewayIndex = (this.currentGatewayIndex + 1) % totalGateways;
📝 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
const startIndex = this.currentGatewayIndex;
for (let i = 0; i < this.gateways.length; i++) {
const gateway = this.gateways[(startIndex + i) % this.gateways.length]!;
const totalGateways = this.gateways.length;
for (let attempt = 0; attempt < totalGateways; attempt++) {
const gateway = this.gateways[this.currentGatewayIndex]!;
this.currentGatewayIndex = (this.currentGatewayIndex + 1) % totalGateways;

Comment on lines 187 to 188
methodName: "getTokenPrice",
additionalData: {
Copy link

@coderabbitai coderabbitai bot Jan 22, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect method name in error context.

Similar to the previous issue, the error context references the wrong method name.

Apply this fix:

                 className: CoingeckoProvider.name,
-                methodName: "getTokenPrice",
+                methodName: "getTokenPrices",

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

The rabbit is right here ^

Copy link

Choose a reason for hiding this comment

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

@jahabeebs Thanks for confirming! Yes, it's important to maintain consistency in error contexts to help with debugging.


✏️ Learnings added
Learnt from: jahabeebs
PR: defi-wonderland/grants-stack-indexer-v2#57
File: packages/pricing/src/providers/coingecko.provider.ts:187-188
Timestamp: 2025-01-22T19:10:33.446Z
Learning: In TypeScript code, ensure that error contexts reference the correct method name where the error occurred, especially in catch blocks. For example, if an error occurs in method `getTokenPrices`, the error context should use "getTokenPrices" as the method name, not "getTokenPrice".

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed: 6126ed6

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!


for (const event of events) {
if ("metadata" in event.params) {
ids.add(event.params.metadata[1]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
ids.add(event.params.metadata[1]);
ids.add(event.params.metadata[1]);

is metadata[1] safe ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes is safe to use it this way

}
}

return Array.from(ids);
Copy link
Collaborator

Choose a reason for hiding this comment

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

are u using a set to avoid repeats ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

exactly

@@ -197,6 +209,51 @@ export class Orchestrator {
});
}

private async getMetadataFromEvents(events: AnyIndexerFetchedEvent[]): Promise<string[]> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

natspec

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

return Array.from(ids);
}

private async getTokensFromEvents(
Copy link
Collaborator

Choose a reason for hiding this comment

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

natspec

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment on lines +230 to +233
if (
"token" in event.params &&
"amount" in event.params &&
BigInt(event.params.amount) > 0n
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we add runtime validation here ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sorry what validation are u specifically referring to?

Copy link
Collaborator

Choose a reason for hiding this comment

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

typings runtime validations , same as metadata

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

will track in Linear to see where this validation fits the best in the system

const ids = new Set<string>();

for (const event of events) {
if ("metadata" in event.params) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we add an extra validation to check metadata structure

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

here isn't relevant as different events have different structure, I'd leave that to the event processor


/**
* Fetch all possible prices for the batch
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

complete natspecs

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -0,0 +1 @@
export const MIN_GRANULARITY_MS = 300_000; // 5 minutes
Copy link
Collaborator

Choose a reason for hiding this comment

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

add more context about coingecko and reference link pls 🙏

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

): Promise<void> {
// Clear caches
if (this.dependencies.metadataProvider.clearCache) {
await this.dependencies.metadataProvider.clearCache();
Copy link
Collaborator

Choose a reason for hiding this comment

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

token prices will live longer with a ttl , right ? i was wondering if a memory overflow could happen in this scenario, lets talk about this offline

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed the issue as per discussed offline

Base automatically changed from feat/in-memory-caches to dev January 22, 2025 12:43
@@ -31,6 +34,11 @@ import { EventsProcessor } from "./eventsProcessor.js";
import { InvalidEvent } from "./exceptions/index.js";
import { CoreDependencies, DataLoader, delay, IQueue, iStrategyAbi, Queue } from "./internal.js";

type TokenWithTimestamps = {
token: Token;
timestamps: number[];
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the exact type of the timestamps? Maybe we should define a type like NumberMs to prevent conversion confusion

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

could be nice, i'll analyze how much impact it has on the codebase. if it's too big, i'll update the name to timestampsMs to be a bit clearer and leave the typing as tech debt

* Enqueue new events from the events fetcher using the last processed event as a starting point
*/
private async enqueueEvents(): Promise<void> {
private async getNextEventsBatch(): Promise<AnyIndexerFetchedEvent[]> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docs

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

),
);

const metadata: unknown[] = [];
Copy link
Collaborator

Choose a reason for hiding this comment

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

In the future we should try to parse or validate the metadata at sone basic level to be sure we can actually use it & make sure that we aren't typing it as unknown in the whole app

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

metadata parsing (using Zod schemas) is done in the processors, is not Orchestrator responsibility. metadata has different shapes depending on the event but the Orchestrator doesn't know this

@@ -755,6 +770,152 @@ describe("Orchestrator", { sequential: true }, () => {
expect(logger.error).not.toHaveBeenCalled();
});
});

describe("getMetadataFromEvents", () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about a failure case? It's unknown so what if we can't parse it or can't get usable info from the metadata?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this enhancement is related to speed and performance of the system. whether metadata is correct or not is task of the processors (which will eventually fail or not)

.filter((price): price is TokenPrice => !!price);
}

private async getCachedPrices(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docs (and for the rest of the file)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment on lines 187 to 188
methodName: "getTokenPrice",
additionalData: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The rabbit is right here ^

Copy link

@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 (8)
packages/data-flow/src/orchestrator.ts (3)

37-40: Consider using a more specific type for timestamps.

Based on past discussions, consider either:

  1. Creating a NumberMs type to prevent conversion confusion, or
  2. Renaming the field to timestampsMs to be more explicit about the unit.
 type TokenWithTimestamps = {
     token: Token;
-    timestamps: number[];
+    timestampsMs: number[];
 };

230-264: Token extraction logic is robust and well-documented.

The implementation includes good practices:

  • Filtering out zero amounts
  • Deduplicating timestamps
  • Sorting timestamps for consistency
  • Proper null checks for token resolution

Consider extracting the magic number 0n into a named constant for better readability.

+const ZERO_AMOUNT = 0n;
+
 private getTokensFromEvents(events: AnyIndexerFetchedEvent[]): TokenWithTimestamps[] {
     // ...
     if (
         "token" in event.params &&
         "amount" in event.params &&
-        BigInt(event.params.amount) > 0n
+        BigInt(event.params.amount) > ZERO_AMOUNT
     ) {

320-334: Bulk fetching implementation is efficient and fault-tolerant.

Good practices observed:

  • Cache clearing before fetching
  • Parallel execution using Promise.allSettled
  • Graceful handling of partial failures

Consider adding debug logging for cache clearing operations to aid in troubleshooting.

     // Clear caches if the provider supports it
+    this.logger.debug('Clearing metadata and pricing caches', {
+        className: Orchestrator.name,
+        chainId: this.chainId
+    });
     await this.dependencies.metadataProvider.clearCache?.();
     await this.dependencies.pricingProvider.clearCache?.();
packages/pricing/src/providers/coingecko.provider.ts (2)

147-193: Consider optimizing the error message for bulk operations.

The error message "failed to fetch token price" could be more specific since we're fetching multiple prices.

Apply this diff to improve the error message:

-                `Unknown Coingecko API error: failed to fetch token price ` +
+                `Unknown Coingecko API error: failed to fetch token prices ` +

164-166: Consider adding a maximum time range limit.

The code adjusts the minimum time range but doesn't limit the maximum range. Large time ranges could lead to excessive data fetching and potential rate limiting.

Consider adding a maximum time range check:

 if (effectiveMax - effectiveMin < MIN_GRANULARITY_MS) {
     effectiveMax = effectiveMin + MIN_GRANULARITY_MS;
 }
+const MAX_TIME_RANGE = 30 * 24 * 60 * 60 * 1000; // 30 days
+if (effectiveMax - effectiveMin > MAX_TIME_RANGE) {
+    throw new NonRetriableError(
+        `Time range exceeds maximum allowed (${MAX_TIME_RANGE}ms)`,
+        {
+            className: CoingeckoProvider.name,
+            methodName: "getTokenPrices",
+        },
+    );
+}
packages/pricing/src/providers/cachingProxy.provider.ts (3)

54-68: Consider adding a retry mechanism for cache operations.

The non-blocking cache operation is good for performance, but consider adding a retry mechanism for failed cache operations to improve cache hit rates.

Consider implementing a retry mechanism:

+    private async retryCache<T>(
+        operation: () => Promise<T>,
+        errorMessage: string,
+        retries = 3,
+        delay = 1000,
+    ): Promise<T> {
+        for (let i = 0; i < retries; i++) {
+            try {
+                return await operation();
+            } catch (error) {
+                if (i === retries - 1) {
+                    this.logger.debug(errorMessage, { error });
+                    throw error;
+                }
+                await new Promise((resolve) => setTimeout(resolve, delay));
+            }
+        }
+        throw new Error('Unreachable');
+    }

     // In getTokenPrice method:
-    this.cache
-        .set(
+    this.retryCache(
+        () => this.cache.set(
             {
                 tokenCode,
                 timestampMs: startTimestampMs,
             },
             price,
-        )
-        .catch((error) => {
-            this.logger.debug(
-                `Failed to cache price for token ${tokenCode} at ${startTimestampMs}`,
-                { error },
-            );
-        });
+        ),
+        `Failed to cache price for token ${tokenCode} at ${startTimestampMs}`,
+    ).catch(() => {});

239-269: Optimize binary search implementation.

The binary search implementation can be simplified and made more efficient.

Consider this optimized implementation:

     private findClosestPrice(prices: TokenPrice[], targetTimestamp: number): TokenPrice | null {
         if (prices.length === 0) {
             return null;
         }
 
-        // Handle edge cases
-        if (targetTimestamp <= prices[0]!.timestampMs) return prices[0]!;
-        if (targetTimestamp >= prices[prices.length - 1]!.timestampMs)
-            return prices[prices.length - 1]!;
-
-        // Binary search
         let left = 0;
         let right = prices.length - 1;
 
-        while (left + 1 < right) {
+        while (left <= right) {
             const mid = Math.floor((left + right) / 2);
+            const midPrice = prices[mid]!;
 
-            if (prices[mid]!.timestampMs === targetTimestamp) {
-                return prices[mid]!;
+            if (midPrice.timestampMs === targetTimestamp) {
+                return midPrice;
             }
 
-            if (prices[mid]!.timestampMs < targetTimestamp) {
+            if (midPrice.timestampMs < targetTimestamp) {
                 left = mid;
             } else {
                 right = mid;
             }
         }
 
-        // Return the floor value (largest timestamp <= target)
-        return prices[left]!;
+        // Find closest price
+        const leftDiff = Math.abs(prices[left]!.timestampMs - targetTimestamp);
+        const rightDiff = right < prices.length ? Math.abs(prices[right]!.timestampMs - targetTimestamp) : Infinity;
+        return leftDiff <= rightDiff ? prices[left]! : prices[right]!;
     }

191-192: Document the fire-and-forget pattern.

The comment "Fire and forget cache operation" should be expanded to explain why this pattern is used.

Consider expanding the comment:

-                // Fire and forget cache operation
+                // Fire and forget cache operation to avoid blocking the response
+                // Cache failures are logged but don't affect the price lookup
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2202fa and deff69e.

📒 Files selected for processing (4)
  • packages/data-flow/src/orchestrator.ts (10 hunks)
  • packages/pricing/src/constants/index.ts (1 hunks)
  • packages/pricing/src/providers/cachingProxy.provider.ts (3 hunks)
  • packages/pricing/src/providers/coingecko.provider.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/pricing/src/constants/index.ts
🧰 Additional context used
📓 Path-based instructions (3)
packages/pricing/src/providers/coingecko.provider.ts (1)

Pattern **/*.ts: Review TypeScript files for adherence to the following guidelines:
- Avoid over-abstraction; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid any; use unknown when necessary.
- Use runtime type-checking for environment variables (e.g., Zod).
- Prevent circular dependencies with the internal module pattern.
- Libraries should have an external.ts file explicitly listing public exports.
- Use bigint as-is; cast to Number only when exposing values via APIs.
- Document all code with JSDoc.
- Encourage static async factory functions for constructors.

  • Avoid overly nitpicky feedback beyond these best practices.
packages/data-flow/src/orchestrator.ts (1)

Pattern **/*.ts: Review TypeScript files for adherence to the following guidelines:
- Avoid over-abstraction; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid any; use unknown when necessary.
- Use runtime type-checking for environment variables (e.g., Zod).
- Prevent circular dependencies with the internal module pattern.
- Libraries should have an external.ts file explicitly listing public exports.
- Use bigint as-is; cast to Number only when exposing values via APIs.
- Document all code with JSDoc.
- Encourage static async factory functions for constructors.

  • Avoid overly nitpicky feedback beyond these best practices.
packages/pricing/src/providers/cachingProxy.provider.ts (1)

Pattern **/*.ts: Review TypeScript files for adherence to the following guidelines:
- Avoid over-abstraction; prioritize composition over inheritance.
- Use dependency injection and follow SOLID principles.
- Avoid any; use unknown when necessary.
- Use runtime type-checking for environment variables (e.g., Zod).
- Prevent circular dependencies with the internal module pattern.
- Libraries should have an external.ts file explicitly listing public exports.
- Use bigint as-is; cast to Number only when exposing values via APIs.
- Document all code with JSDoc.
- Encourage static async factory functions for constructors.

  • Avoid overly nitpicky feedback beyond these best practices.
📓 Learnings (1)
packages/pricing/src/providers/coingecko.provider.ts (1)
Learnt from: jahabeebs
PR: defi-wonderland/grants-stack-indexer-v2#57
File: packages/pricing/src/providers/coingecko.provider.ts:187-188
Timestamp: 2025-01-22T19:10:33.586Z
Learning: In TypeScript code, ensure that error contexts reference the correct method name where the error occurred, especially in catch blocks. For example, if an error occurs in method `getTokenPrices`, the error context should use "getTokenPrices" as the method name, not "getTokenPrice".
🔇 Additional comments (6)
packages/data-flow/src/orchestrator.ts (2)

Line range hint 42-69: Documentation is comprehensive and well-structured.

The class documentation clearly explains the new bulk fetching step and its benefits.


128-132: Implementation aligns with performance optimization goals.

The sequential flow of getting events, bulk fetching data, and then enqueueing is logically sound. As discussed in past reviews, error handling is intentionally omitted here since failed fetches will be retried during processing.

packages/pricing/src/providers/coingecko.provider.ts (3)

16-16: LGTM!

The import of MIN_GRANULARITY_MS is correctly added to support the new functionality.


130-130: LGTM!

The error handling is correctly updated to use the new method name parameter.


195-195: LGTM!

The method signature update correctly includes the new methodName parameter.

packages/pricing/src/providers/cachingProxy.provider.ts (1)

6-9: LGTM!

The CacheResult type is well-defined and appropriately captures both the timestamp and optional price.

Copy link
Collaborator

@jahabeebs jahabeebs left a comment

Choose a reason for hiding this comment

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

👍

Comment on lines +230 to +233
if (
"token" in event.params &&
"amount" in event.params &&
BigInt(event.params.amount) > 0n
Copy link
Collaborator

Choose a reason for hiding this comment

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

typings runtime validations , same as metadata

@0xnigir1 0xnigir1 merged commit 5c9e321 into dev Jan 23, 2025
7 checks passed
@0xnigir1 0xnigir1 deleted the feat/bulk-fetch-events-batch branch January 23, 2025 16:40
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.

3 participants