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

WIP cache oracle prices #2713

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

WIP cache oracle prices #2713

wants to merge 12 commits into from

Conversation

adamfraser
Copy link
Contributor

@adamfraser adamfraser commented Feb 3, 2025

Do not merge

Summary by CodeRabbit

  • New Features
    • Introduced an Oracle-based caching mechanism to streamline market price updates.
    • Added support for new event versions, including PerpetualMarketCreateEventV3 and UpdatePerpetualEventV3.
    • Enhanced error messaging in subscriptions with additional context.
    • Added new properties to various interfaces to include defaultFundingRate1H for better funding rate management.
    • Introduced new Athena tables for managing affiliate information and vaults.
    • Added a new branch trigger for the GitHub Actions workflow for oracle-price-candles.
  • Performance Improvements
    • Reduced the market price refresh interval from 10 seconds to 5 seconds for more timely updates.
  • Refactoring
    • Removed legacy order book mid-price caching processes to ensure a cleaner and more efficient system.
    • Updated the price retrieval mechanism to utilize the new Oracle-based system instead of the previous in-memory cache.
  • Bug Fixes
    • Eliminated outdated tests related to order book mid-price caching, ensuring test suite relevance and accuracy.

@adamfraser adamfraser requested a review from a team as a code owner February 3, 2025 20:46
Copy link
Contributor

coderabbitai bot commented Feb 3, 2025

Walkthrough

This pull request makes significant alterations by deprecating the legacy order book mid-price caching system and replacing it with a new Oracle price caching mechanism. Several files related to Redis caching, Lua scripts, and scheduled tasks have been removed or modified. Test suites for the old caching functionality have been eliminated, and the service's initialization code is updated accordingly. Additionally, the GitHub Actions workflow is modified to restrict active configurations to a single branch/job.

Changes

Files Change Summary
.github/workflows/indexer-build-and-push-dev-staging.yml Commented out multiple branch patterns (main, release/indexer/...) and jobs (dev, dev3, dev4, dev5, staging), leaving only the dev2 job active.
indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts
indexer/services/roundtable/src/index.ts
indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts
indexer/packages/redis/src/index.ts
Removed legacy order book mid-price caching functionality including functions, interfaces, variables, and export statements.
indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua
indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua
Updated Redis Lua scripts: replaced sorted set timestamp logic with a simpler key-value store and adjusted retrieval from multiple to single value using fallback for missing keys.
indexer/services/ender/src/index.ts
indexer/services/ender/src/lib/candles-generator.ts
Removed invocations of the old mid-price cache and integrated new Oracle price retrieval (getOracleCachePrice) for candle generation.
indexer/services/ender/src/handlers/markets/market-price-update-handler.ts Added call to setOraclePrice (from the new Oracle cache) and introduced extra logging to record market pair updates.
indexer/services/ender/src/caches/oracle-price-memory-cache.ts Introduced a new Oracle price cache with a defined interface, along with setOraclePrice, getOracleCachePrice, and a commented start function for future refresh loop implementation.
Tests (various files under __tests__ and src/tasks/) Removed tests related to the legacy order book mid-price caching and updated tests to reflect new Oracle price caching behavior.

Sequence Diagram(s)

sequenceDiagram
    participant MPH as MarketPriceUpdateHandler
    participant OPC as OraclePriceMemoryCache
    participant Log as Logger

    MPH->>OPC: setOraclePrice(market.pair, oraclePrice.price)
    OPC-->>OPC: Store price in oraclePriceCache
    OPC-->>MPH: Acknowledge update
    MPH->>Log: Log market pair and price update
Loading
sequenceDiagram
    participant Repo as GitHub Repository
    participant Runner as Workflow Runner
    participant Job as Build/Push Job (dev2)

    Repo->>Runner: Push commit (branch dev2)
    Runner->>Job: Trigger active job for dev2
    Job-->>Runner: Execute Docker build and push to ECR
Loading

Possibly related PRs

Suggested reviewers

  • dydxwill
  • vincentwschau

Poem

In a meadow of code, I hop along,
Leaving old caches where they don’t belong.
Oracle prices now lead the way,
In a streamlined flow day by day.
Hoppity-hip, the code’s so bright,
Bugs and old tests take flight!
🐰✌️

✨ 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (1)

38-46: Add type for the reduce accumulator.

The reduce accumulator type is inferred. Adding an explicit type would improve code maintainability and readability.

Apply this diff to add the type:

+  type AccumulatorType = {
+    priceCacheKeys: string[];
+    priceValues: string[];
+  };
+
   const { priceCacheKeys, priceValues } = cacheKeyPricePairs.reduce(
     (acc, pair) => {
       acc.priceCacheKeys.push(pair.cacheKey);
       acc.priceValues.push(pair.price);
       return acc;
     },
-    { priceCacheKeys: [] as string[], priceValues: [] as string[] },
+    { priceCacheKeys: [], priceValues: [] } as AccumulatorType,
   );
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between eb2bb4a and 54f5232.

📒 Files selected for processing (4)
  • .github/workflows/indexer-build-and-push-dev-staging.yml (2 hunks)
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (2 hunks)
  • indexer/services/roundtable/src/index.ts (1 hunks)
  • indexer/services/roundtable/src/tasks/market-updater.ts (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/indexer-build-and-push-dev-staging.yml
  • indexer/services/roundtable/src/index.ts
⏰ Context from checks skipped due to timeout of 90000ms (19)
  • GitHub Check: call-build-ecs-service-vulcan / (vulcan) Check docker image build
  • GitHub Check: call-build-ecs-service-socks / (socks) Check docker image build
  • GitHub Check: call-build-ecs-service-ender / (ender) Check docker image build
  • GitHub Check: call-build-ecs-service-roundtable / (roundtable) Check docker image build
  • GitHub Check: call-build-ecs-service-comlink / (comlink) Check docker image build
  • GitHub Check: check-build-bazooka
  • GitHub Check: test / run_command
  • GitHub Check: check-build-auxo
  • GitHub Check: run_command
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push

@@ -79,6 +79,8 @@ export default async function runTask(): Promise<void> {
Date.now() - start,
);

OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for the async cache operation.

The cacheOraclePrices call is not awaited and lacks error handling. This could lead to silent failures and potential inconsistencies in the cache.

Apply this diff to properly handle the async operation:

-    OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
+    await OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
📝 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
OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
await OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);

🛠️ Refactor suggestion

Consider moving the cache operation inside the transaction.

The cache operation is performed outside the transaction block. If the subsequent database updates fail and rollback, the cache will be inconsistent with the database state.

Move the cache operation inside the transaction block (after line 144) to maintain data consistency across Redis and Postgres:

-    OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
...
     await Transaction.commit(txId);
+    await OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
📝 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
OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
// ... previous lines of code ...
// (Previously at line 82)
// Removed the caching call from here
// OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
// ... additional code and transaction operations ...
await Transaction.commit(txId);
await OrderbookMidPricesCache.cacheOraclePrices(redisClient, perpetualMarkets, latestPrices);
// ... subsequent code ...

Comment on lines 25 to 73
export async function cacheOraclePrices(
client: RedisClient,
markets: PerpetualMarketFromDatabase[],
prices: PriceMap,
): Promise<void> {
const cacheKeyPricePairs:
({cacheKey: string, price: string})[] = markets.flatMap((market) => {
const cacheKey: string = getOrderbookMidPriceCacheKey(market.ticker);
const price = prices[market.marketId];

return price !== undefined ? { cacheKey, price } : [];
});

// Extract cache keys and prices
const { priceCacheKeys, priceValues } = cacheKeyPricePairs.reduce(
(acc, pair) => {
acc.priceCacheKeys.push(pair.cacheKey);
acc.priceValues.push(pair.price);
return acc;
},
{ priceCacheKeys: [] as string[], priceValues: [] as string[] },
);

const nowSeconds: number = Math.floor(Date.now() / 1000); // Current time in seconds

logger.info({
at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});

return new Promise<void>((resolve, reject) => {
client.evalsha(
addOrderbookMidPricesScript.hash,
priceCacheKeys.length,
...priceCacheKeys,
...priceValues,
nowSeconds,
(err: Error | null) => {
if (err) {
reject(err);
} else {
resolve();
}
},
);
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation and refactor to reduce code duplication.

The function lacks validation for empty arrays and shares similar code with fetchAndCacheOrderbookMidPrices. Consider:

  1. Adding validation for empty arrays
  2. Extracting shared Redis caching logic into a helper function

Apply this diff to improve the code:

+async function cacheOrderbookPrices(
+  client: RedisClient,
+  priceCacheKeys: string[],
+  priceValues: string[],
+): Promise<void> {
+  if (priceCacheKeys.length === 0) {
+    return;
+  }
+
+  const nowSeconds: number = Math.floor(Date.now() / 1000);
+
+  return new Promise<void>((resolve, reject) => {
+    client.evalsha(
+      addOrderbookMidPricesScript.hash,
+      priceCacheKeys.length,
+      ...priceCacheKeys,
+      ...priceValues,
+      nowSeconds,
+      (err: Error | null) => {
+        if (err) {
+          reject(err);
+        } else {
+          resolve();
+        }
+      },
+    );
+  });
+}
+
 export async function cacheOraclePrices(
   client: RedisClient,
   markets: PerpetualMarketFromDatabase[],
   prices: PriceMap,
 ): Promise<void> {
+  if (markets.length === 0) {
+    return;
+  }
+
   const cacheKeyPricePairs:
   ({cacheKey: string, price: string})[] = markets.flatMap((market) => {
     const cacheKey: string = getOrderbookMidPriceCacheKey(market.ticker);
     const price = prices[market.marketId];

     return price !== undefined ? { cacheKey, price } : [];
   });

   // Extract cache keys and prices
   const { priceCacheKeys, priceValues } = cacheKeyPricePairs.reduce(
     (acc, pair) => {
       acc.priceCacheKeys.push(pair.cacheKey);
       acc.priceValues.push(pair.price);
       return acc;
     },
     { priceCacheKeys: [] as string[], priceValues: [] as string[] },
   );

   logger.info({
-    at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
+    at: 'orderbook-mid-prices-cache#cacheOraclePrices',
     message: 'Caching orderbook mid price',
     cacheKey: priceCacheKeys[0],
     midPrice: priceValues[0],
   });

-  return new Promise<void>((resolve, reject) => {
-    client.evalsha(
-      addOrderbookMidPricesScript.hash,
-      priceCacheKeys.length,
-      ...priceCacheKeys,
-      ...priceValues,
-      nowSeconds,
-      (err: Error | null) => {
-        if (err) {
-          reject(err);
-        } else {
-          resolve();
-        }
-      },
-    );
-  });
+  return cacheOrderbookPrices(client, priceCacheKeys, priceValues);
 }

Then update fetchAndCacheOrderbookMidPrices to use the helper function:

   });

-  return new Promise<void>((resolve, reject) => {
-    client.evalsha(
-      addOrderbookMidPricesScript.hash,
-      priceCacheKeys.length,
-      ...priceCacheKeys,
-      ...priceValues,
-      nowSeconds,
-      (err: Error | null) => {
-        if (err) {
-          reject(err);
-        } else {
-          resolve();
-        }
-      },
-    );
-  });
+  return cacheOrderbookPrices(client, priceCacheKeys, priceValues);
 }
📝 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
export async function cacheOraclePrices(
client: RedisClient,
markets: PerpetualMarketFromDatabase[],
prices: PriceMap,
): Promise<void> {
const cacheKeyPricePairs:
({cacheKey: string, price: string})[] = markets.flatMap((market) => {
const cacheKey: string = getOrderbookMidPriceCacheKey(market.ticker);
const price = prices[market.marketId];
return price !== undefined ? { cacheKey, price } : [];
});
// Extract cache keys and prices
const { priceCacheKeys, priceValues } = cacheKeyPricePairs.reduce(
(acc, pair) => {
acc.priceCacheKeys.push(pair.cacheKey);
acc.priceValues.push(pair.price);
return acc;
},
{ priceCacheKeys: [] as string[], priceValues: [] as string[] },
);
const nowSeconds: number = Math.floor(Date.now() / 1000); // Current time in seconds
logger.info({
at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});
return new Promise<void>((resolve, reject) => {
client.evalsha(
addOrderbookMidPricesScript.hash,
priceCacheKeys.length,
...priceCacheKeys,
...priceValues,
nowSeconds,
(err: Error | null) => {
if (err) {
reject(err);
} else {
resolve();
}
},
);
});
}
async function cacheOrderbookPrices(
client: RedisClient,
priceCacheKeys: string[],
priceValues: string[],
): Promise<void> {
if (priceCacheKeys.length === 0) {
return;
}
const nowSeconds: number = Math.floor(Date.now() / 1000);
return new Promise<void>((resolve, reject) => {
client.evalsha(
addOrderbookMidPricesScript.hash,
priceCacheKeys.length,
...priceCacheKeys,
...priceValues,
nowSeconds,
(err: Error | null) => {
if (err) {
reject(err);
} else {
resolve();
}
},
);
});
}
export async function cacheOraclePrices(
client: RedisClient,
markets: PerpetualMarketFromDatabase[],
prices: PriceMap,
): Promise<void> {
if (markets.length === 0) {
return;
}
const cacheKeyPricePairs: ({ cacheKey: string, price: string })[] = markets.flatMap((market) => {
const cacheKey: string = getOrderbookMidPriceCacheKey(market.ticker);
const price = prices[market.marketId];
return price !== undefined ? { cacheKey, price } : [];
});
// Extract cache keys and prices
const { priceCacheKeys, priceValues } = cacheKeyPricePairs.reduce(
(acc, pair) => {
acc.priceCacheKeys.push(pair.cacheKey);
acc.priceValues.push(pair.price);
return acc;
},
{ priceCacheKeys: [] as string[], priceValues: [] as string[] },
);
logger.info({
at: 'orderbook-mid-prices-cache#cacheOraclePrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});
return cacheOrderbookPrices(client, priceCacheKeys, priceValues);
}

Comment on lines 50 to 55
logger.info({
at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the incorrect logging location identifier.

The logging location identifier is incorrect. It's using the identifier from fetchAndCacheOrderbookMidPrices instead of cacheOraclePrices.

Apply this diff to fix the logging:

     logger.info({
-      at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
+      at: 'orderbook-mid-prices-cache#cacheOraclePrices',
       message: 'Caching orderbook mid price',
       cacheKey: priceCacheKeys[0],
       midPrice: priceValues[0],
     });
📝 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
logger.info({
at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});
logger.info({
- at: 'orderbook-mid-prices-cache#fetchAndCacheOrderbookMidPrices',
+ at: 'orderbook-mid-prices-cache#cacheOraclePrices',
message: 'Caching orderbook mid price',
cacheKey: priceCacheKeys[0],
midPrice: priceValues[0],
});

@adamfraser adamfraser force-pushed the oracle-price-candles branch from 54f5232 to 2fb8ebc Compare February 3, 2025 21:08
@adamfraser adamfraser force-pushed the oracle-price-candles branch from 2fb8ebc to 0216755 Compare February 4, 2025 15:51
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (1)

25-73: 🛠️ Refactor suggestion

Add validation and refactor to reduce code duplication.

The function lacks validation for empty arrays and shares similar code with fetchAndCacheOrderbookMidPrices. Consider:

  1. Adding validation for empty arrays
  2. Extracting shared Redis caching logic into a helper function
🧹 Nitpick comments (1)
indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua (1)

5-6: LGTM! Consider adding comments about the fallback value.

The change from ZRANGE to GET aligns with the simplified caching mechanism. The use of false as a fallback value for non-existent keys is a good choice as it's explicitly handled in the TypeScript code.

Add a comment explaining why false is used as the fallback value:

 local price = redis.call("GET", key)
+-- Return false for non-existent keys to distinguish from valid price values
 results[i] = price or false
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2fb8ebc and 0216755.

📒 Files selected for processing (6)
  • .github/workflows/indexer-build-and-push-dev-staging.yml (2 hunks)
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (4 hunks)
  • indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua (1 hunks)
  • indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua (1 hunks)
  • indexer/services/roundtable/src/index.ts (1 hunks)
  • indexer/services/roundtable/src/tasks/market-updater.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • indexer/services/roundtable/src/tasks/market-updater.ts
  • indexer/services/roundtable/src/index.ts
  • .github/workflows/indexer-build-and-push-dev-staging.yml
⏰ Context from checks skipped due to timeout of 90000ms (20)
  • GitHub Check: call-build-ecs-service-vulcan / (vulcan) Check docker image build
  • GitHub Check: call-build-ecs-service-socks / (socks) Check docker image build
  • GitHub Check: call-build-ecs-service-roundtable / (roundtable) Check docker image build
  • GitHub Check: call-build-ecs-service-ender / (ender) Check docker image build
  • GitHub Check: call-build-ecs-service-comlink / (comlink) Check docker image build
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: test / run_command
  • GitHub Check: check-build-auxo
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: check-build-bazooka
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: lint
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: run_command
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: Summary
🔇 Additional comments (1)
indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (1)

152-193: LGTM! Type changes align with Redis script modifications.

The changes in getMedianPrices correctly handle the new single-price storage format, and the type updates maintain type safety.

Comment on lines +17 to +18
-- Store the latest price in a simple key-value format without expiration
redis.call("SET", priceCacheKey, price)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding TTL to prevent stale data.

The script no longer handles expiration, which could lead to stale prices remaining in Redis indefinitely. Consider using SETEX to set a TTL on the cached prices.

Apply this diff to add TTL:

-  -- Store the latest price in a simple key-value format without expiration
-  redis.call("SET", priceCacheKey, price)
+  -- Store the latest price with a 5-minute TTL to prevent stale data
+  redis.call("SETEX", priceCacheKey, 300, price)
📝 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
-- Store the latest price in a simple key-value format without expiration
redis.call("SET", priceCacheKey, price)
-- Store the latest price with a 5-minute TTL to prevent stale data
redis.call("SETEX", priceCacheKey, 300, price)

@adamfraser adamfraser force-pushed the oracle-price-candles branch from 0216755 to 4d5c4bd Compare February 4, 2025 16:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🔭 Outside diff range comments (1)
indexer/services/ender/src/validators/update-perpetual-validator.ts (1)

25-29: Fix type mismatch in createHandlers return type.

The method's return type Handler<UpdatePerpetualEventV1>[] is inconsistent with the class's type parameter which includes UpdatePerpetualEventV2 and UpdatePerpetualEventV3. This could lead to runtime errors when handling V2 and V3 events.

Apply this diff to fix the type mismatch:

-  ): Handler<UpdatePerpetualEventV1>[] {
+  ): Handler<UpdatePerpetualEventV1 | UpdatePerpetualEventV2 | UpdatePerpetualEventV3>[] {
🧹 Nitpick comments (15)
indexer/services/comlink/src/lib/helpers.ts (1)

726-763: Consider adding error handling for config validation.

The vault helper functions look good overall, but there's a potential improvement for the getVaultPnlStartDate function.

Consider adding validation for the config value and error handling:

 export function getVaultPnlStartDate(): DateTime {
+  if (!config.VAULT_PNL_START_DATE) {
+    throw new Error('VAULT_PNL_START_DATE configuration is required');
+  }
   const startDate: DateTime = DateTime.fromISO(config.VAULT_PNL_START_DATE).toUTC();
+  if (!startDate.isValid) {
+    throw new Error(`Invalid VAULT_PNL_START_DATE: ${config.VAULT_PNL_START_DATE}`);
+  }
   return startDate;
 }
indexer/packages/postgres/README.md (1)

10-11: Improve documentation clarity.

The current wording could be clearer. Consider this revision:

-In `__tests__/db/migrations.test.ts`, test cases may be expected to fail (and hence should be commented out) if a model is modified due to the latest migration.
+Note: When modifying database models in the latest migration, certain test cases in `__tests__/db/migrations.test.ts` may fail. These tests should be temporarily disabled until the next migration is added.
🧰 Tools
🪛 LanguageTool

[style] ~11-~11: Consider a shorter alternative to avoid wordiness.
Context: ... modified due to the latest migration. In order to migrate in dev and staging, you must re...

(IN_ORDER_TO_PREMIUM)

indexer/packages/postgres/src/stores/candle-table.ts (1)

229-236: Consider extracting a helper function to reduce duplication.
You are already performing nearly identical queries for handling different time windows and resolutions. Factoring out a helper could improve maintainability.

indexer/services/ender/src/caches/block-cache.ts (1)

124-127: LGTM! Consider adding logging for long initialization times.

The performance monitoring implementation is good. Consider adding a warning log when initialization takes longer than expected.

   stats.timing(
     `${config.SERVICE_NAME}.initialize_caches`,
     Date.now() - start,
   );
+  const duration = Date.now() - start;
+  if (duration > 5000) { // 5 seconds threshold
+    logger.warn({
+      at: 'block-cache#initializeAllCaches',
+      message: 'Cache initialization took longer than expected',
+      durationMs: duration,
+    });
+  }
indexer/services/comlink/src/controllers/api/v4/vault-controller.ts (3)

358-358: Returning adjusted PnL ticks
Consider caching or storing getVaultStartPnl() output locally if it’s called multiple times to reduce overhead.


549-554: Refactored getLatestPnlTicks()
Fetches PnL ticks, then adjusts them with getVaultStartPnl(). Consider adding fallback handling if latestPnlTicks is empty or if the DB call fails.


568-568: Using getVaultStartPnl() for adjustments
No immediate concerns; review performance if the method is repeatedly invoked.

indexer/packages/postgres/src/db/migrations/migration_files/20250107145033_default_1hr_funding_for_perp.ts (1)

3-7: Consider specifying precision and scale.

Using a plain decimal type without explicit precision/scale (e.g. decimal(18,6)) may lead to inconsistent values if extremely large or overly precise entries are inserted. Consider adding explicit constraints to ensure safe ranges for funding rates.

indexer/services/roundtable/src/lib/athena-ddl-tables/affiliate_info.ts (1)

8-19: Consider adding field validation for numeric values.

The table structure is well-defined, but consider adding validation for numeric fields to ensure data integrity.

For example, you could add validation in the application layer before inserting data:

function validateAffiliateInfo(data: AffiliateInfo): void {
  if (Big(data.affiliateEarnings).lt(0)) {
    throw new Error('Affiliate earnings cannot be negative');
  }
  if (data.referredMakerTrades < 0 || data.referredTakerTrades < 0) {
    throw new Error('Trade counts cannot be negative');
  }
  // Add more validations as needed
}
indexer/packages/redis/src/caches/next-funding-cache.ts (1)

12-20: Update documentation to reflect new parameter structure.

The documentation needs to be updated to describe:

  • The new parameter tickerDefaultFundingRate1HPairs
  • How the default funding rate is used in the calculation
indexer/packages/postgres/__tests__/helpers/constants.ts (1)

288-288: Document funding rate differences and extract magic values.

The different funding rates for cross (0) vs isolated (0.0001) markets should be documented and the values should be extracted into named constants for better maintainability.

Consider applying this improvement:

+// Default funding rates for different market types
+const CROSS_MARKET_DEFAULT_FUNDING_RATE = '0';
+const ISOLATED_MARKET_DEFAULT_FUNDING_RATE = '0.0001';
+
 export const defaultPerpetualMarket: PerpetualMarketCreateObject = {
   // ... other fields ...
-  defaultFundingRate1H: '0',
+  defaultFundingRate1H: CROSS_MARKET_DEFAULT_FUNDING_RATE,  // Cross markets have 0 default funding rate
 };

 export const defaultPerpetualMarket2: PerpetualMarketCreateObject = {
   // ... other fields ...
-  defaultFundingRate1H: '0',
+  defaultFundingRate1H: CROSS_MARKET_DEFAULT_FUNDING_RATE,
 };

 export const defaultPerpetualMarket3: PerpetualMarketCreateObject = {
   // ... other fields ...
-  defaultFundingRate1H: '0',
+  defaultFundingRate1H: CROSS_MARKET_DEFAULT_FUNDING_RATE,
 };

 export const isolatedPerpetualMarket: PerpetualMarketCreateObject = {
   // ... other fields ...
-  defaultFundingRate1H: '0.0001',
+  defaultFundingRate1H: ISOLATED_MARKET_DEFAULT_FUNDING_RATE,  // Isolated markets have non-zero default funding rate
 };

 export const isolatedPerpetualMarket2: PerpetualMarketCreateObject = {
   // ... other fields ...
-  defaultFundingRate1H: '0.0001',
+  defaultFundingRate1H: ISOLATED_MARKET_DEFAULT_FUNDING_RATE,
 };

Also applies to: 308-308, 328-328, 349-349, 370-370

indexer/services/comlink/public/swagger.json (1)

1141-1144: Review: Validate New Field defaultFundingRate1H

The new property "defaultFundingRate1H" has been added to the PerpetualMarketResponseObject schema with type "string". This follows the convention used for other related price and rate fields. Please verify that representing the funding rate as a string is the intended design—in scenarios where numerical operations might be required, a numeric type could be considered. Also, if this field is critical for downstream consumers, consider whether it should be added to the list of required properties.

indexer/services/ender/__tests__/helpers/indexer-proto-helpers.ts (2)

979-979: Consider consolidating duplicated TODO comments.

This TODO comment about margin fractions is duplicated across all three versions (V1, V2, V3) of the expectPerpetualMarket functions. Consider extracting it to a shared constant or documentation to maintain DRY principles.


995-995: Consider adding a comment explaining the funding rate calculation.

The conversion from 8hr PPM to 1hr rate involves multiple steps that would benefit from a clear explanation.

Add a comment like:

+    // Convert from 8hr PPM rate to 1hr rate:
+    // 1. Divide by 1_000_000 to convert from PPM
+    // 2. Divide by 8 to convert from 8hr rate to 1hr rate
     defaultFundingRate1H: ((perpetual.defaultFunding8hrPpm / 1_000_000) / 8).toString(),
indexer/services/ender/__tests__/lib/on-message.test.ts (1)

276-277: Improve type safety in test parameters.

The marketCreateEvent parameter is typed as any. This could mask type-related issues and makes the code less maintainable.

Consider using a union type:

-    marketCreateEvent: any,
+    marketCreateEvent: PerpetualMarketCreateEventV2 | PerpetualMarketCreateEventV3,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7e2b549 and 78cef84.

⛔ Files ignored due to path filters (2)
  • protocol/indexer/events/events.pb.go is excluded by !**/*.pb.go
  • protocol/x/perpetuals/types/perpetual.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (82)
  • .github/workflows/indexer-build-and-push-dev-staging.yml (2 hunks)
  • indexer/packages/postgres/README.md (1 hunks)
  • indexer/packages/postgres/__tests__/db/migrations.test.ts (1 hunks)
  • indexer/packages/postgres/__tests__/helpers/constants.ts (5 hunks)
  • indexer/packages/postgres/src/db/migrations/migration_files/20250107145033_default_1hr_funding_for_perp.ts (1 hunks)
  • indexer/packages/postgres/src/models/perpetual-market-model.ts (3 hunks)
  • indexer/packages/postgres/src/stores/candle-table.ts (2 hunks)
  • indexer/packages/postgres/src/stores/vault-pnl-ticks-view.ts (1 hunks)
  • indexer/packages/postgres/src/types/db-model-types.ts (1 hunks)
  • indexer/packages/postgres/src/types/perpetual-market-types.ts (3 hunks)
  • indexer/packages/postgres/src/types/websocket-message-types.ts (1 hunks)
  • indexer/packages/redis/__tests__/caches/next-funding-cache.test.ts (2 hunks)
  • indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts (0 hunks)
  • indexer/packages/redis/src/caches/next-funding-cache.ts (2 hunks)
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (0 hunks)
  • indexer/packages/redis/src/index.ts (0 hunks)
  • indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua (1 hunks)
  • indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua (1 hunks)
  • indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts (8 hunks)
  • indexer/packages/v4-protos/src/codegen/dydxprotocol/perpetuals/perpetual.ts (2 hunks)
  • indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts (3 hunks)
  • indexer/services/comlink/__tests__/lib/request-helpers/request-transformer.test.ts (1 hunks)
  • indexer/services/comlink/public/api-documentation.md (6 hunks)
  • indexer/services/comlink/public/swagger.json (1 hunks)
  • indexer/services/comlink/src/caches/vault-start-pnl.ts (1 hunks)
  • indexer/services/comlink/src/controllers/api/v4/vault-controller.ts (6 hunks)
  • indexer/services/comlink/src/index.ts (2 hunks)
  • indexer/services/comlink/src/lib/compliance-and-geo-check.ts (2 hunks)
  • indexer/services/comlink/src/lib/helpers.ts (4 hunks)
  • indexer/services/comlink/src/request-helpers/request-transformer.ts (1 hunks)
  • indexer/services/comlink/src/types.ts (3 hunks)
  • indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts (0 hunks)
  • indexer/services/ender/__tests__/handlers/funding-handler.test.ts (10 hunks)
  • indexer/services/ender/__tests__/handlers/perpetual-market-handler.test.ts (3 hunks)
  • indexer/services/ender/__tests__/handlers/update-perpetual-handler.test.ts (2 hunks)
  • indexer/services/ender/__tests__/helpers/constants.ts (4 hunks)
  • indexer/services/ender/__tests__/helpers/indexer-proto-helpers.ts (2 hunks)
  • indexer/services/ender/__tests__/helpers/notification-functions.test.ts (1 hunks)
  • indexer/services/ender/__tests__/helpers/redis-helpers.ts (1 hunks)
  • indexer/services/ender/__tests__/lib/candles-generator.test.ts (14 hunks)
  • indexer/services/ender/__tests__/lib/on-message.test.ts (6 hunks)
  • indexer/services/ender/__tests__/validators/perpetual-market-validator.test.ts (4 hunks)
  • indexer/services/ender/__tests__/validators/update-perpetual-validator.test.ts (3 hunks)
  • indexer/services/ender/package.json (1 hunks)
  • indexer/services/ender/src/caches/block-cache.ts (2 hunks)
  • indexer/services/ender/src/caches/candle-cache.ts (0 hunks)
  • indexer/services/ender/src/caches/oracle-price-memory-cache.ts (1 hunks)
  • indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts (0 hunks)
  • indexer/services/ender/src/config.ts (1 hunks)
  • indexer/services/ender/src/handlers/markets/market-price-update-handler.ts (2 hunks)
  • indexer/services/ender/src/handlers/perpetual-market-handler.ts (2 hunks)
  • indexer/services/ender/src/helpers/kafka-helper.ts (1 hunks)
  • indexer/services/ender/src/helpers/postgres/postgres-functions.ts (2 hunks)
  • indexer/services/ender/src/index.ts (0 hunks)
  • indexer/services/ender/src/lib/block-processor.ts (1 hunks)
  • indexer/services/ender/src/lib/candles-generator.ts (2 hunks)
  • indexer/services/ender/src/lib/helper.ts (3 hunks)
  • indexer/services/ender/src/lib/types.ts (4 hunks)
  • indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql (2 hunks)
  • indexer/services/ender/src/scripts/handlers/dydx_perpetual_market_v3_handler.sql (1 hunks)
  • indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v2_handler.sql (1 hunks)
  • indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v3_handler.sql (1 hunks)
  • indexer/services/ender/src/validators/update-perpetual-validator.ts (1 hunks)
  • indexer/services/roundtable/__tests__/helpers/pnl-ticks-helper.test.ts (1 hunks)
  • indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts (0 hunks)
  • indexer/services/roundtable/__tests__/tasks/market-updater.test.ts (2 hunks)
  • indexer/services/roundtable/src/index.ts (0 hunks)
  • indexer/services/roundtable/src/lib/athena-ddl-tables/affiliate_info.ts (1 hunks)
  • indexer/services/roundtable/src/lib/athena-ddl-tables/affiliate_referred_users.ts (1 hunks)
  • indexer/services/roundtable/src/lib/athena-ddl-tables/perpetual_markets.ts (2 hunks)
  • indexer/services/roundtable/src/lib/athena-ddl-tables/subaccount_usernames.ts (1 hunks)
  • indexer/services/roundtable/src/lib/athena-ddl-tables/vaults.ts (1 hunks)
  • indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts (0 hunks)
  • indexer/services/roundtable/src/tasks/market-updater.ts (2 hunks)
  • indexer/services/roundtable/src/tasks/update-research-environment.ts (3 hunks)
  • indexer/services/socks/__tests__/lib/subscriptions.test.ts (2 hunks)
  • indexer/services/socks/src/helpers/message.ts (1 hunks)
  • indexer/services/socks/src/lib/subscription.ts (1 hunks)
  • indexer/services/socks/src/types.ts (1 hunks)
  • proto/dydxprotocol/indexer/events/events.proto (5 hunks)
  • proto/dydxprotocol/perpetuals/perpetual.proto (1 hunks)
  • protocol/indexer/events/constants.go (1 hunks)
⛔ Files not processed due to max files limit (21)
  • protocol/indexer/events/perpetual.go
  • protocol/indexer/events/perpetual_market_create.go
  • protocol/indexer/events/perpetual_market_create_test.go
  • protocol/indexer/events/perpetual_test.go
  • protocol/testutil/keeper/clob.go
  • protocol/x/clob/abci_test.go
  • protocol/x/clob/genesis_test.go
  • protocol/x/clob/keeper/clob_pair.go
  • protocol/x/clob/keeper/clob_pair_test.go
  • protocol/x/clob/keeper/deleveraging_test.go
  • protocol/x/clob/keeper/get_price_premium_test.go
  • protocol/x/clob/keeper/liquidations_test.go
  • protocol/x/clob/keeper/msg_server_create_clob_pair_test.go
  • protocol/x/clob/keeper/msg_server_place_order_test.go
  • protocol/x/clob/keeper/orders_test.go
  • protocol/x/clob/keeper/process_operations_test.go
  • protocol/x/clob/module_test.go
  • protocol/x/listing/keeper/listing.go
  • protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross_test.go
  • protocol/x/perpetuals/keeper/perpetual.go
  • protocol/x/perpetuals/keeper/perpetual_test.go
💤 Files with no reviewable changes (10)
  • indexer/services/roundtable/src/index.ts
  • indexer/services/ender/src/caches/candle-cache.ts
  • indexer/packages/redis/src/index.ts
  • indexer/services/roundtable/tests/tasks/cache-orderbook-mid-prices.test.ts
  • indexer/packages/redis/tests/caches/orderbook-mid-prices-cache.test.ts
  • indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts
  • indexer/services/ender/src/index.ts
  • indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts
  • indexer/services/ender/tests/caches/orderbook-mid-price-memory-cache.test.ts
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts
✅ Files skipped from review due to trivial changes (5)
  • indexer/services/ender/tests/helpers/notification-functions.test.ts
  • proto/dydxprotocol/perpetuals/perpetual.proto
  • indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v2_handler.sql
  • indexer/packages/v4-protos/src/codegen/dydxprotocol/perpetuals/perpetual.ts
  • indexer/services/roundtable/tests/helpers/pnl-ticks-helper.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • indexer/services/ender/src/config.ts
  • .github/workflows/indexer-build-and-push-dev-staging.yml
  • indexer/packages/redis/src/scripts/get_orderbook_mid_prices.lua
  • indexer/services/ender/src/handlers/markets/market-price-update-handler.ts
  • indexer/services/ender/src/caches/oracle-price-memory-cache.ts
🧰 Additional context used
📓 Learnings (4)
indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql (1)
Learnt from: hwray
PR: dydxprotocol/v4-chain#2597
File: indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql:16-20
Timestamp: 2024-11-22T18:12:04.606Z
Learning: Avoid suggesting changes to deprecated functions such as `dydx_update_perpetual_v1_handler` in `indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql` if they are unchanged in the PR.
indexer/services/ender/src/helpers/postgres/postgres-functions.ts (2)
Learnt from: hwray
PR: dydxprotocol/v4-chain#2597
File: indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql:16-20
Timestamp: 2024-11-22T18:12:04.606Z
Learning: Avoid suggesting changes to deprecated functions such as `dydx_update_perpetual_v1_handler` in `indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql` if they are unchanged in the PR.
Learnt from: hwray
PR: dydxprotocol/v4-chain#2597
File: indexer/services/ender/src/helpers/postgres/postgres-functions.ts:47-48
Timestamp: 2024-11-22T18:12:38.778Z
Learning: Prefer to maintain old `v1` handler files, such as `dydx_update_perpetual_handler.sql`, instead of removing them, even when new versioned handlers are added.
indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v3_handler.sql (1)
Learnt from: hwray
PR: dydxprotocol/v4-chain#2597
File: indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql:16-20
Timestamp: 2024-11-22T18:12:04.606Z
Learning: Avoid suggesting changes to deprecated functions such as `dydx_update_perpetual_v1_handler` in `indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql` if they are unchanged in the PR.
indexer/services/ender/src/scripts/handlers/dydx_perpetual_market_v3_handler.sql (1)
Learnt from: hwray
PR: dydxprotocol/v4-chain#2597
File: indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql:16-20
Timestamp: 2024-11-22T18:12:04.606Z
Learning: Avoid suggesting changes to deprecated functions such as `dydx_update_perpetual_v1_handler` in `indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v1_handler.sql` if they are unchanged in the PR.
🪛 Biome (1.9.4)
indexer/services/ender/__tests__/handlers/perpetual-market-handler.test.ts

[error] 106-106: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🪛 LanguageTool
indexer/packages/postgres/README.md

[style] ~11-~11: Consider a shorter alternative to avoid wordiness.
Context: ... modified due to the latest migration. In order to migrate in dev and staging, you must re...

(IN_ORDER_TO_PREMIUM)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Summary
🔇 Additional comments (87)
indexer/services/comlink/src/lib/compliance-and-geo-check.ts (2)

17-20: LGTM!

The import statement correctly includes both create4xxResponse and handleInternalServerError from the helpers module.


52-80: LGTM! Robust error handling added.

The try-catch block properly handles potential database query errors by calling handleInternalServerError with appropriate context.

indexer/services/comlink/src/lib/helpers.ts (3)

27-27: LGTM!

The import statement correctly includes the required types and utilities for vault functionality.


51-51: LGTM!

The VaultMapping type is correctly imported from the types module.


87-87: LGTM!

The handleInternalServerError function is now correctly exported for use in other modules.

indexer/services/socks/src/helpers/message.ts (1)

12-27: LGTM! Enhanced error message context.

The addition of optional channel and id parameters to createErrorMessage improves error reporting by providing more context about the subscription that failed.

indexer/services/socks/src/types.ts (1)

68-72: LGTM! Interface updated to support enhanced error messages.

The addition of optional channel and id properties to the ErrorMessage interface aligns with the function signature changes and maintains backward compatibility.

indexer/services/socks/src/lib/subscription.ts (1)

168-178: LGTM! Enhanced error message with subscription context.

The error message now includes the channel and id of the failed subscription, providing better context for debugging.

indexer/services/socks/__tests__/lib/subscriptions.test.ts (2)

247-249: LGTM! Test coverage updated for enhanced error messages.

The test expectations are updated to verify that error messages include the channel and id of the failed subscription.


283-285: LGTM! Test coverage for blocked error messages.

The test case for blocked subscriptions is updated to verify the enhanced error message format.

indexer/packages/postgres/__tests__/db/migrations.test.ts (2)

37-39: Consider a more robust approach to handling model modifications.

While skipping tests that fail due to model modifications is a temporary solution, it might hide potential issues. Consider:

  1. Adding a configuration flag to conditionally run these tests.
  2. Implementing test isolation to prevent model changes from affecting other tests.
  3. Creating separate test suites for model-dependent and model-independent tests.

This would provide better test coverage and make the test suite more maintainable.

Would you like me to propose a more robust testing approach that handles model modifications without skipping tests?

Also applies to: 53-55


26-35: LGTM! Clear and descriptive test name.

The new test description "test UP and DOWN for most recent migration without seed data" is more descriptive and helps developers understand the test's purpose.

indexer/services/ender/src/lib/types.ts (3)

10-10: LGTM! New event types imported correctly.

The new event types PerpetualMarketCreateEventV3 and UpdatePerpetualEventV3 are imported following the existing pattern and naming convention.

Also applies to: 36-36


133-139: LGTM! PerpetualMarketCreateEventV3 union case added correctly.

The new union case follows the established pattern and includes all required properties.


163-169: LGTM! UpdatePerpetualEventV3 union case added correctly.

The new union case follows the established pattern and includes all required properties.

Let's verify the version progression and usage of these new event types:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Verify version progression and usage of the new event types.

# Test 1: Check for any skipped versions
echo "Checking for version progression..."
rg -A 5 "PerpetualMarketCreateEvent[Vv][0-9]+"
rg -A 5 "UpdatePerpetualEvent[Vv][0-9]+"

# Test 2: Check for handlers of these new event types
echo "Checking for handlers..."
rg -A 10 "PerpetualMarketCreateEventV3"
rg -A 10 "UpdatePerpetualEventV3"

Length of output: 80530


Approval: UpdatePerpetualEventV3 union case added successfully.

The version progression and usage for update events have been confirmed. The new event type appears in the expected helper files, protobuf registrations, and test references alongside its V1 and V2 counterparts.

  • The update event version (V3) is properly registered and decoded.
  • Handlers and tests show appropriate references to UpdatePerpetualEventV3.
indexer/packages/postgres/src/stores/candle-table.ts (5)

4-4: New import looks fine.
No issues found with this added import statement.


178-180: Good early-return check.
Returning an empty object when tickers.length === 0 helps avoid unnecessary DB queries.


183-185: Initialization of candlesMap is correct.
This ensures each ticker key is primed before further population.


187-207: Potential SQL injection risk with raw query building.
This comment references a prior concern in the review history about constructing SQL strings by interpolating array values. If tickers came from untrusted input, it could introduce a vulnerability. It’s safer to use parameter placeholders or a query builder approach.
[duplicate_comment, critical_issue]

Suggested fix using parameter placeholders:

- "ticker" IN (${tickers.map((ticker) => { return `'${ticker}'`; }).join(',')}) AND
+ "ticker" IN (${tickers.map(() => '?').join(',')}) AND

Then supply tickers as parameters to the .raw(...) call.


208-228: Repeated SQL injection concern.
The same risk applies here. Please consider using parameter placeholders or a query builder method instead of direct string interpolation.
[duplicate_comment, critical_issue]

indexer/services/ender/src/caches/block-cache.ts (2)

110-110: LGTM!

Good addition of timestamp capture for performance monitoring.


109-128: Verify performance impact across environments.

Since this is part of a larger caching system transition, please ensure the performance monitoring is tested across different environments with varying load conditions. This will help establish baseline metrics for the new Oracle price caching system.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Check for any existing performance metrics for cache initialization

# Search for existing performance monitoring code
rg -A 2 "stats\.timing.*initialize_caches" --type ts

Length of output: 54


🏁 Script executed:

#!/bin/bash
# Display context lines from `indexer/services/ender/src/caches/block-cache.ts`
# to verify the presence and context of the performance monitoring code.
sed -n '100,140p' indexer/services/ender/src/caches/block-cache.ts

Length of output: 1363


Performance monitoring code is in place—please verify its behavior under differing load conditions.

The current implementation in indexer/services/ender/src/caches/block-cache.ts includes the stats.timing call to capture cache initialization metrics. However, as noted, it's important to test these performance measurements in various environments (e.g., staging vs. production) to ensure that the new Oracle price caching system's performance is accurately profiled under realistic load conditions.

  • Verify baseline metrics across environments.
  • Confirm that any performance degradation or improvement during the caching system transition is captured.
indexer/services/comlink/src/controllers/api/v4/vault-controller.ts (6)

1-1: No issues with new stats import
Looks fine.


43-43: Confirmed usage of getVaultStartPnl
Import aligns with usage below; no issues found.


112-112: Refined function call
Switching to _.values(vaultSubaccounts) matches the function signature expecting an array of vault objects.


167-167: Updated call to match signature
getLatestPnlTicks() now requires no arguments, aligning with the refactored method.


352-356: Ensure valid return from getVaultPnlStartDate()
If there's a possibility of an invalid or undefined date, handle it to avoid runtime errors.


561-565: Parameter alignment in VaultPnlTicksView.getVaultsPnl
Passing interval, window size, and start date is consistent with the new signature.

indexer/packages/v4-protos/src/codegen/dydxprotocol/indexer/events/events.ts (6)

962-963: Ensure callers are updated to use the newer version.

Marking the old interface as deprecated is good practice. Make sure all references to PerpetualMarketCreateEventV2 are updated to the newer PerpetualMarketCreateEventV3, to avoid confusion and potential mismatches.


965-966: Coordinate deprecation with downstream consumers.

This deprecation notice will help external integrators identify obsolete usage, but a clear timeline and migration guide can further streamline the transition to PerpetualMarketCreateEventV3.


1041-1042: Confirm all bridging logic is removed or updated.

Another deprecation marker. Please double-check whether bridging logic or fallback code references this SDK type. If so, it may need removal or updating.


1111-1262: Review the new PerpetualMarketCreateEventV3 interface consistency.

The new V3 interface includes defaultFunding8hrPpm. Ensure that event producers and consumers handle this field precisely. If the field is truly mandatory, verify that code generating these events provides it correctly, and that consumers won’t break when receiving this attribute.


1496-1497: Validate migration to UpdatePerpetualEventV3.

The doc block deprecation calls out V2 as obsolete. Confirm that event emission or consumption code no longer depends on this old version.


1499-1500: Deprecated block references.

Adding another deprecated marker is fine, but ensure internal references to UpdatePerpetualEventV2 are fully removed or replaced to avoid confusion.

indexer/packages/postgres/src/db/migrations/migration_files/20250107145033_default_1hr_funding_for_perp.ts (1)

9-13: Reverse migration logic looks correct.

Dropping the column on down() ensures a clean rollback. Just be sure no existing data is needed if rolling back.

indexer/packages/redis/src/scripts/add_orderbook_mid_prices.lua (1)

17-21: Reiterate TTL addition for preventing stale data.

Storing a simple key-value without expiration may lead to outdated cached prices if updates stop. A previous review comment (lines 17-18) suggested adding TTL to mitigate stale data. That recommendation still holds.

indexer/services/roundtable/src/lib/athena-ddl-tables/subaccount_usernames.ts (1)

1-32: LGTM! Well-structured implementation for Athena table creation.

The code follows a consistent pattern with proper SQL escaping and clear separation of raw and formatted column definitions.

indexer/services/roundtable/src/lib/athena-ddl-tables/affiliate_referred_users.ts (1)

1-34: LGTM! Well-structured implementation for Athena table creation.

The code follows a consistent pattern with proper SQL escaping and appropriate data types (bigint for block numbers).

indexer/services/roundtable/src/lib/athena-ddl-tables/vaults.ts (1)

1-39: LGTM! Well-structured implementation for Athena table creation.

The code follows a consistent pattern with proper SQL escaping and appropriate timestamp casting for date fields.

indexer/services/comlink/src/caches/vault-start-pnl.ts (2)

13-21: Add error handling for cache initialization.

The startVaultStartPnlCache function should handle potential errors during initialization to prevent silent failures.


27-33: LGTM! Well-implemented test-only function.

The clearVaultStartPnl function properly restricts usage to test environment and maintains a clean state.

indexer/services/ender/__tests__/helpers/redis-helpers.ts (1)

11-21: LGTM! Changes align with the new caching system.

The updated function signature and implementation correctly handle the new funding rate structure with default values.

indexer/services/roundtable/src/lib/athena-ddl-tables/affiliate_info.ts (1)

33-48: LGTM! Well-structured table generation functions.

The implementation follows best practices for Athena table creation with proper type casting.

indexer/services/ender/src/handlers/perpetual-market-handler.ts (1)

17-20: LGTM! Clean addition of V3 event support.

The changes correctly extend the handler to support the new event version while maintaining backward compatibility.

indexer/services/roundtable/src/lib/athena-ddl-tables/perpetual_markets.ts (1)

25-26: LGTM! The new column is well-integrated.

The addition of defaultFundingRate1H column is consistent across both table definitions and follows the established pattern of type casting.

Also applies to: 45-46

indexer/services/comlink/src/index.ts (1)

8-8: LGTM! Cache initialization is properly integrated.

The vault start PnL cache initialization follows the existing pattern and is properly awaited.

Also applies to: 46-47

indexer/packages/redis/src/caches/next-funding-cache.ts (1)

21-47: LGTM! The funding rate calculation is properly updated.

The changes correctly:

  • Accept an array of tuples containing ticker and default funding rate
  • Add the default funding rate to the calculated average
indexer/packages/redis/__tests__/caches/next-funding-cache.test.ts (1)

20-28: LGTM! Test cases are comprehensive and well-documented.

The test cases:

  • Cover the new default funding rate behavior
  • Include edge cases
  • Have clear comments explaining calculations

Also applies to: 36-44, 48-54

indexer/packages/postgres/src/types/perpetual-market-types.ts (1)

21-21: Verify the type and add documentation for the new funding rate field.

The new defaultFundingRate1H field is added consistently across interfaces and enums, but it would benefit from documentation explaining:

  • The expected format and range of values
  • The units of measurement (e.g., percentage, basis points)
  • Any validation requirements

Also applies to: 40-40, 59-59

protocol/indexer/events/constants.go (1)

35-35: Verify version synchronization with indexer service.

The version increments for PerpetualMarketEventVersion and UpdatePerpetualEventVersion should be synchronized with the corresponding versions in the indexer service.

Also applies to: 37-37

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Check version synchronization between protocol and indexer
# Test: Search for version constants in indexer code
rg -A 1 'PerpetualMarketEventVersion|UpdatePerpetualEventVersion' indexer/

Length of output: 76


🏁 Script executed:

#!/bin/bash
# Description: Search entire repository for version constant definitions to verify synchronization between protocol and indexer service.
echo "Searching for PerpetualMarketEventVersion:"
rg "PerpetualMarketEventVersion" .

echo "Searching for UpdatePerpetualEventVersion:"
rg "UpdatePerpetualEventVersion" .

Length of output: 3585


Version constants are synchronized with the indexer service.

The repository inspection confirms that both PerpetualMarketEventVersion and UpdatePerpetualEventVersion are set to 3 in protocol/indexer/events/constants.go and referenced consistently across tests and keeper implementations.

indexer/packages/postgres/src/stores/vault-pnl-ticks-view.ts (2)

66-88: Add error handling to the new function.

The new getLatestVaultPnl function should handle potential database errors consistently with other functions in the codebase.


71-82: LGTM! Efficient query implementation.

The SQL query efficiently retrieves the latest PnL for each subaccount using:

  • DISTINCT ON to get unique subaccount records
  • Correct ordering by blockTime DESC to get the most recent records
indexer/packages/postgres/src/models/perpetual-market-model.ts (1)

89-89: LGTM! The new field is well-defined and properly integrated.

The defaultFundingRate1H field is correctly added to the model with:

  • Proper type validation in jsonSchema
  • Correct SQL to JSON conversion mapping
  • Optional field in the class definition

Also applies to: 119-119, 157-157

indexer/services/ender/src/helpers/postgres/postgres-functions.ts (1)

41-41: LGTM! Handler scripts are properly versioned.

The new V3 handler scripts are added while maintaining the existing V1 and V2 handlers, which aligns with the best practice of maintaining backward compatibility.

Also applies to: 50-50

indexer/services/ender/__tests__/validators/perpetual-market-validator.test.ts (1)

5-5: LGTM! Test coverage is properly extended for V3 events.

The test suite is correctly updated to include V3 events while maintaining existing test coverage for V1 and V2 events.

Also applies to: 16-16, 54-59, 64-65, 95-96, 104-105, 113-114, 119-120

indexer/services/ender/__tests__/handlers/update-perpetual-handler.test.ts (1)

17-17: LGTM! Test coverage is properly extended for V3 events.

The test suite is correctly updated to include V3 events while maintaining existing test coverage for V1 and V2 events.

Also applies to: 25-25, 76-80, 84-85

indexer/services/roundtable/src/tasks/market-updater.ts (1)

55-62: LGTM! The new data structure enhances funding rate management.

The change from tickers to tickerDefaultFundingRate1HPairs improves the handling of funding rates by including default rates, with a safe fallback value of '0' for null rates.

indexer/packages/postgres/src/types/websocket-message-types.ts (1)

220-220: LGTM! The interface update is consistent with the funding rate enhancements.

The addition of defaultFundingRate1H as an optional property is correctly placed in the "Fields that are very unlikely to change" section.

indexer/services/ender/__tests__/handlers/perpetual-market-handler.test.ts (2)

95-101: LGTM! Test coverage extended for V3 events.

The test suite is correctly updated to include support for PerpetualMarketCreateEventV3.


106-106: 🛠️ Refactor suggestion

Replace Function type with explicit function signature.

Using the Function type is discouraged as it accepts any function-like value, which can lead to type-related bugs.

Replace with an explicit function signature:

-expectPerpetualMarket: Function,
+expectPerpetualMarket: (
+  perpetualMarket: PerpetualMarketFromDatabase,
+  event: PerpetualMarketCreateEventV1 | PerpetualMarketCreateEventV2 | PerpetualMarketCreateEventV3
+) => void,

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 106-106: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

indexer/packages/postgres/src/types/db-model-types.ts (1)

98-98: LGTM! The interface update aligns with the funding rate enhancements.

The addition of defaultFundingRate1H as an optional property is consistent with the changes across the codebase.

indexer/services/roundtable/src/tasks/update-research-environment.ts (1)

21-22: LGTM! New Athena tables added correctly.

The implementation follows the existing pattern for adding new tables to Athena.

Also applies to: 36-36, 42-42, 65-68

indexer/services/ender/src/helpers/kafka-helper.ts (1)

350-350: LGTM! New funding rate field added correctly.

The defaultFundingRate1H field is correctly added to the market message contents.

indexer/services/ender/src/lib/helper.ts (1)

176-183: LGTM! Version 3 event support added correctly.

The implementation properly handles the new event versions while maintaining backward compatibility.

Also applies to: 228-235

indexer/services/comlink/__tests__/lib/request-helpers/request-transformer.test.ts (1)

84-84: LGTM! Test expectations updated correctly.

The test has been properly updated to include the new defaultFundingRate1H field in the expected response object.

indexer/services/ender/src/lib/block-processor.ts (1)

52-52: LGTM! Added support for version 3 events.

The changes correctly extend the validator mappings to support version 3 of PERPETUAL_MARKET and UPDATE_PERPETUAL subtypes, following the existing pattern.

Also applies to: 56-56

indexer/services/ender/__tests__/handlers/funding-handler.test.ts (1)

15-15: LGTM! Added test cases for funding rate calculation.

The changes improve test coverage by:

  1. Testing non-zero and zero funding values
  2. Verifying the next funding rate calculation with different default funding rates
  3. Creating test markets with specific configurations

Also applies to: 46-46, 139-191

indexer/services/ender/__tests__/helpers/constants.ts (1)

29-30: LGTM! Added test constants for version 3 events.

The changes add test constants that:

  1. Follow the existing pattern of defining test data
  2. Include the new defaultFunding8hrPpm field
  3. Test different market types (CROSS vs ISOLATED)

Also applies to: 40-40, 165-193, 244-252

indexer/services/comlink/src/types.ts (1)

27-27: LGTM! Enhanced type definitions.

The changes:

  1. Add type-safe mapping for vault data
  2. Add optional funding rate field to market response
  3. Follow TypeScript best practices

Also applies to: 355-355, 696-698

indexer/services/ender/src/lib/candles-generator.ts (2)

29-29: LGTM! Importing the new oracle price cache function.

The change from orderbook mid-price to oracle price cache aligns with the architectural shift in price data management.


541-541: Verify the impact of switching to oracle prices.

The switch from orderbook mid-prices to oracle prices for the price map could affect:

  1. Price accuracy - Oracle prices might have different update frequencies
  2. System performance - Different caching mechanisms could affect latency
  3. Market data consistency - Ensure all dependent systems are updated to use oracle prices

Run the following script to verify the usage of oracle prices:

indexer/services/comlink/src/request-helpers/request-transformer.ts (1)

392-392: LGTM! Adding defaultFundingRate1H to the response object.

The addition of defaultFundingRate1H enhances the API response with funding rate information.

indexer/services/roundtable/__tests__/tasks/market-updater.test.ts (3)

147-147: LGTM! Clarifying test case description.

The rename from "funding rates" to "funding samples" better reflects the actual test scenario.


384-408: LGTM! Adding test coverage for non-zero default funding rates.

The test ensures that no message is sent when there are no funding samples, even with non-zero default funding rates.


409-484: LGTM! Adding test coverage for zero funding samples.

The test verifies that a message is sent when:

  1. The funding sample is zero
  2. The nextFundingRate differs from the current rate
indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts (3)

27-27: LGTM! Importing vault start PNL cache functions.

The import adds necessary functions for managing the vault start PNL cache state in tests.


135-135: LGTM! Clearing vault start PNL cache between tests.

Properly isolates tests by clearing the cache state in afterEach.


658-658: LGTM! Initializing vault start PNL cache after creating PNL ticks.

Ensures the cache is properly initialized with the created PNL ticks data.

indexer/services/ender/__tests__/lib/candles-generator.test.ts (1)

38-39: LGTM! Good improvements in DateTime handling and price caching.

The changes improve the code by:

  1. Using luxon's DateTime for consistent time handling
  2. Implementing proper oracle price caching
  3. Maintaining clear test structure
indexer/services/ender/src/scripts/handlers/dydx_update_perpetual_v3_handler.sql (1)

1-47: SQL Update Handler Implementation Looks Good
The implementation of dydx_update_perpetual_v3_handler is well-documented and follows a clear, maintainable structure. The use of constants (e.g., PPM_EXPONENT and FUNDING_RATE_FROM_PROTOCOL_IN_HOURS) and the calculation of defaultFundingRate1H via dydx_trim_scale is both clear and concise. Make sure that the expected types within event_data are validated upstream to avoid conversion issues.

indexer/services/ender/src/scripts/handlers/dydx_perpetual_market_v3_handler.sql (1)

1-46: SQL Market Creation Handler (V3) is Well-Structured
The dydx_perpetual_market_v3_handler function is neatly implemented. Field extraction and conversions (including the use of dydx_from_jsonlib_long and dydx_trim_scale) are consistent with the project’s practices. The use of an INSERT with record expansion simplifies the insertion logic. Just ensure that the structure of event_data always provides the values expected by the target table schema.

indexer/services/ender/src/scripts/handlers/dydx_block_processor_ordered_handlers.sql (2)

59-61: Added Support for Perpetual Market Event Version 3
The new case for "perpetual_market" events (version 3) correctly routes the events to dydx_perpetual_market_v3_handler(event_data). Please verify that this branch is covered by tests and that the handler’s output integrates smoothly with consumers downstream.


72-73: Enhanced Update Perpetual Handling for Version 3
Adding a new clause for "update_perpetual" events (version 3) that calls dydx_update_perpetual_v3_handler(event_data) extends the function’s functionality without impacting legacy logic. Confirm that existing handlers (for versions 1 and 2) are still functioning as expected and that tests have been updated to cover all cases.

proto/dydxprotocol/indexer/events/events.proto (2)

377-485: Update to Perpetual Market Create Events – Introducing V3
The introduction of PerpetualMarketCreateEventV3 with the new field default_funding8hr_ppm provides enhanced detail for funding rate information. Ensure that downstream consumers and documentation are updated to clarify the differences between this field and the legacy funding rate representations (e.g., the SQL function’s defaultFundingRate1H).


577-641: Deprecation and Introduction of Update Perpetual Event V3
Deprecating UpdatePerpetualEventV2 in favor of the new UpdatePerpetualEventV3 (which now includes additional fields such as ticker and the default_funding8hr_ppm) modernizes the event structure. Verify that all protocol consumers know about this change and that necessary migrations or version-handling logic are in place.

indexer/services/comlink/public/api-documentation.md (2)

2498-2499: Clarify the new field description for defaultFundingRate1H.

In the first market object (property1) the diff adds the following two lines:

+      "baseOpenInterest": "string",
+      "defaultFundingRate1H": "string"

While the syntax is correct and the field is consistently added, it would be beneficial to provide a clear description for both baseOpenInterest and especially the new defaultFundingRate1H field. This additional detail will help API consumers understand the meaning and usage of the new funding rate information.


2522-2523: Ensure consistency in the market object schema.

In the second market object (property2) you have similarly added:

+      "baseOpenInterest": "string",
+      "defaultFundingRate1H": "string"

This mirrors the changes in the first market object. Please double-check that the corresponding OpenAPI/Swagger schema (if applicable) and any supporting documentation (or developer guides) are updated accordingly so that the new field is documented consistently across all parts of the API.

✅ Verification successful

Error: No shell scripts or web queries found


🏁 Script executed:

#!/bin/bash
# Search across the repository to verify that the new fields in the market object
# ("baseOpenInterest" and "defaultFundingRate1H") are documented consistently 
# alongside the existing fields (like "maintenanceMarginFraction" and "openInterest").

echo "Searching for 'baseOpenInterest'"
rg "baseOpenInterest"

echo "Searching for 'defaultFundingRate1H'"
rg "defaultFundingRate1H"

echo "Searching for 'maintenanceMarginFraction'"
rg "maintenanceMarginFraction" --context 3

echo "Searching for 'openInterest'"
rg "openInterest" --context 3

Length of output: 66386


Consistent Documentation Verified

The search results confirm that the new properties (baseOpenInterest and defaultFundingRate1H) are documented in the same manner as the other market object fields. They appear consistently in both the OpenAPI/Swagger schema (in swagger.json) and supporting documentation (in api-documentation.md), as well as in the relevant TypeScript types and tests.

  • The new fields are defined as "string" in the API docs.
  • Corresponding definitions exist in the Swagger schema and tests, mirroring the implementation of other market object fields.

No discrepancies were found across the API documentation.

@@ -7,6 +7,8 @@ Add a knex migration by running `pnpm run migrate:make <create_fake_table>`

Run the migration with `pnpm run migrate`

In `__tests__/db/migrations.test.ts`, test cases may be expected to fail (and hence should be commented out) if a model is modified due to the latest migration.

In order to migrate in dev and staging, you must redeploy and run bazooka.

TODO(CORE-512): Add info/resources around bazooka. [Doc](https://www.notion.so/dydx/Engineering-Runbook-15064661da9643188ce33e341b68e7bb#cb2283d80ef14a51924f3bd1a538fd82).
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Follow up on documentation TODO.

The TODO item (CORE-512) indicates missing documentation about the bazooka deployment tool. Since this is a WIP PR, please ensure this documentation is completed before merging.

Run this script to check the status of the TODO item:


🏁 Script executed:

#!/bin/bash
# Description: Check if the TODO item is still open

gh issue view CORE-512 2>/dev/null || echo "Issue not found"

Length of output: 65

Documentation Follow-Up: CORE-512 Issue is Missing

  • The shell script output indicates that GitHub issue CORE-512 does not exist.
  • Confirm whether the documentation for the bazooka deployment tool has been completed.
  • If the documentation work is still pending, please either create a new issue to track it or update/remove the corresponding TODO in the code.

Comment on lines +1583 to +1672
/**
* UpdatePerpetualEventV3 message contains all the information about an update
* to a perpetual on the dYdX chain.
*/

export interface UpdatePerpetualEventV3 {
/**
* Unique Perpetual id.
* Defined in perpetuals.perpetual
*/
id: number;
/**
* The name of the `Perpetual` (e.g. `BTC-USD`).
* Defined in perpetuals.perpetual
*/

ticker: string;
/**
* Unique id of market param associated with this perpetual market.
* Defined in perpetuals.perpetual
*/

marketId: number;
/**
* The exponent for converting an atomic amount (`size = 1`)
* to a full coin. For example, if `AtomicResolution = -8`
* then a `PerpetualPosition` with `size = 1e8` is equivalent to
* a position size of one full coin.
* Defined in perpetuals.perpetual
*/

atomicResolution: number;
/**
* The liquidity_tier that this perpetual is associated with.
* Defined in perpetuals.perpetual
*/

liquidityTier: number;
/** Market type of the perpetual. */

marketType: PerpetualMarketType;
/** Default 8hr funding rate in parts-per-million. */

defaultFunding8hrPpm: number;
}
/**
* UpdatePerpetualEventV3 message contains all the information about an update
* to a perpetual on the dYdX chain.
*/

export interface UpdatePerpetualEventV3SDKType {
/**
* Unique Perpetual id.
* Defined in perpetuals.perpetual
*/
id: number;
/**
* The name of the `Perpetual` (e.g. `BTC-USD`).
* Defined in perpetuals.perpetual
*/

ticker: string;
/**
* Unique id of market param associated with this perpetual market.
* Defined in perpetuals.perpetual
*/

market_id: number;
/**
* The exponent for converting an atomic amount (`size = 1`)
* to a full coin. For example, if `AtomicResolution = -8`
* then a `PerpetualPosition` with `size = 1e8` is equivalent to
* a position size of one full coin.
* Defined in perpetuals.perpetual
*/

atomic_resolution: number;
/**
* The liquidity_tier that this perpetual is associated with.
* Defined in perpetuals.perpetual
*/

liquidity_tier: number;
/** Market type of the perpetual. */

market_type: PerpetualMarketTypeSDKType;
/** Default 8hr funding rate in parts-per-million. */

default_funding8hr_ppm: number;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Check the new UpdatePerpetualEventV3 usage carefully.

The addition of defaultFunding8hrPpm can introduce breaking changes for older logic. Confirm that all related migrations, database updates, and event-consumer code paths are aligned with the new attribute.

Do you want me to generate compatibility checks or backfill logic for older records so that the new field is never null or inaccurately populated?

import { getVaultMapping, getVaultPnlStartDate } from '../lib/helpers';
import { VaultMapping } from '../types';

let vaultStartPnl: PnlTicksFromDatabase[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add initialization check in getter function.

The getVaultStartPnl function should verify that the cache has been initialized before returning the value.

+let initialized = false;
 let vaultStartPnl: PnlTicksFromDatabase[] = [];
 
 export function getVaultStartPnl(): PnlTicksFromDatabase[] {
+  if (!initialized) {
+    throw new Error('Vault start PnL cache has not been initialized');
+  }
   return vaultStartPnl;
 }

Also applies to: 23-25

Comment on lines +60 to +64
[
'UpdatePerpetualEventV3',
UpdatePerpetualEventV3.encode(defaultUpdatePerpetualEventV3).finish(),
defaultUpdatePerpetualEventV3,
],
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify test coverage for V3-specific fields.

While the basic validation is tested, consider adding test cases specific to the new fields in UpdatePerpetualEventV3 (e.g., defaultFundingRate1H).

Also applies to: 68-68


🏁 Script executed:

#!/bin/bash
# Description: Check test coverage for V3-specific fields
# Test: Search for test cases related to new fields in V3
rg -A 5 'defaultFundingRate1H.*test' indexer/services/ender/__tests__/

Length of output: 72


I'll run additional searches to verify if there are any explicit tests for V3-specific fields (like defaultFundingRate1H). In particular, I'm looking for any occurrences of this field or related funding rate terminology in the tests (and ensuring the V3 tests reference all relevant fields). Please execute the following script:

This will help confirm if additional test cases or validations for defaultFundingRate1H (and possibly other V3-specific fields) are present.


🏁 Script executed:

#!/bin/bash
echo "Searching for 'defaultFundingRate1H' in test files:"
rg -n "defaultFundingRate1H" indexer/services/ender/__tests__/

echo "Searching for any 'fundingRate' references for broader context:"
rg -n "fundingRate" indexer/services/ender/__tests__/

echo "Searching for 'UpdatePerpetualEventV3' references in test files:"
rg -n "UpdatePerpetualEventV3" indexer/services/ender/__tests__/

Length of output: 3278

Enhance V3-specific field validation in tests

The current tests for UpdatePerpetualEventV3 (in update-perpetual-validator.test.ts) validate the basic structure via encoding/decoding, but explicit assertions for V3-specific fields—such as defaultFundingRate1H—are missing. While this field is exercised across helper and funding-handler tests, it isn’t directly validated in the V3 validator test cases. It’s recommended to add explicit test cases for these new fields to ensure their intended behavior is fully covered.

  • Location: indexer/services/ender/tests/validators/update-perpetual-validator.test.ts (lines 60–64)

@@ -7,7 +7,7 @@
"start": "node --heapsnapshot-signal=SIGUSR2 -r dd-trace/init -r dotenv-flow/config build/src/index.js",
"build": "rm -rf build/ && tsc && cp -r src/scripts build/src/scripts",
"build:prod": "pnpm run build",
"build:watch": "pnpm run build -- --watch",
"build:watch": "rm -rf build/ && tsc --watch && cp -r src/scripts build/src/scripts",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Review Build:watch Script – Consider Concurrency for File Copy
The new "build:watch" command now cleans the build directory and then runs tsc --watch followed by copying scripts. However, since tsc --watch is a long-running (blocking) command, the subsequent cp -r src/scripts build/src/scripts might never execute. Consider using a tool like concurrently (or npm-run-all) to run the watcher and the copy step in parallel, or separate the copy task into a pre‑build/post‑build step.

@adamfraser adamfraser force-pushed the oracle-price-candles branch from 78cef84 to fa9e6b5 Compare February 6, 2025 16:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (2)
indexer/services/ender/src/lib/candles-generator.ts (2)

532-546:

🧩 Analysis chain

Rename function and update related documentation to reflect oracle price usage.

The function now returns oracle prices instead of orderbook mid prices, but the name and documentation haven't been updated to reflect this change.

Apply these changes:

-/**
- * Get the cached orderbook mid price for a given ticker
-*/
+/**
+ * Get the cached oracle price for a given ticker
+*/
-export function getOrderbookMidPriceMap(): { [ticker: string]: OrderbookMidPrice } {
+export function getOraclePriceMap(): { [ticker: string]: OrderbookMidPrice } {
   const start: number = Date.now();
   const perpetualMarkets = Object.values(perpetualMarketRefresher.getPerpetualMarketsMap());

   const priceMap: { [ticker: string]: OrderbookMidPrice } = {};
   perpetualMarkets.forEach((perpetualMarket: PerpetualMarketFromDatabase) => {
     priceMap[perpetualMarket.ticker] = getOracleCachePrice(perpetualMarket.ticker);
   });

-  stats.timing(`${config.SERVICE_NAME}.get_orderbook_mid_price_map.timing`, Date.now() - start);
+  stats.timing(`${config.SERVICE_NAME}.get_oracle_price_map.timing`, Date.now() - start);
   return priceMap;
 }

Additionally, update all references to this function in the codebase.


🏁 Script executed:

#!/bin/bash
# Find all references to getOrderbookMidPriceMap in the codebase
rg "getOrderbookMidPriceMap"

Length of output: 539


Rename function and update documentation & references for oracle pricing.

The code now returns oracle prices, but the function name, its JSDoc, and the stats metric still reference "orderbook mid price." Additionally, the test files are still importing and using getOrderbookMidPriceMap. You should:

  • Rename the function (e.g., to getOraclePriceMap) and update its JSDoc.
  • Update the timing metric name accordingly.
  • Update all codebase references (including in tests such as indexer/services/ender/__tests__/lib/candles-generator.test.ts) to use the new function name.

374-388:

🧩 Analysis chain

Consider updating database schema to reflect oracle price usage.

The code now uses oracle prices, but the database columns and variable names still reference orderbook mid prices (e.g., orderbookMidPriceClose, orderbookMidPriceOpen). Consider creating a follow-up task to:

  1. Create new columns for oracle prices
  2. Migrate existing data
  3. Update all references in the code
  4. Remove old columns

This should be done as a separate PR to ensure safe data migration.

Also applies to: 406-420, 480-490


🏁 Script executed:

#!/bin/bash
# Find all references to orderbookMidPrice in the codebase
rg "orderbookMidPrice"

# Find database migration files
fd -e sql

Length of output: 16569


Follow-Up: Address Inconsistent Usage of Orderbook Mid Price Naming

The codebase still widely references “orderbookMidPrice” (and its variants) in the candles generator, tests, API docs, and even in migration scripts. Given that we’re transitioning to oracle prices, a follow-up task is needed to update these references and related database schema. For example:

  • File updates:

    • Update variable names in indexer/services/ender/src/lib/candles-generator.ts to use oracle price naming.
    • Modify test files (e.g., indexer/services/ender/__tests__/lib/candles-generator.test.ts) to reflect the new naming conventions.
  • Database/schema updates:

    • Create new columns for oracle prices and migrate existing data.
    • Update migration files (e.g., in indexer/packages/postgres/src/db/migrations/migration_files/20240627152937_candles_add_mid_book_price_open_and_close.ts) to handle the intended removal or replacement of the old columns.
  • Documentation updates:

    • Ensure API documentation and related files (e.g., indexer/services/comlink/public/api-documentation.md and swagger.json) are updated accordingly.

A separate PR should be scheduled to safely transition the schema and code to properly accommodate the oracle price usage.

🧹 Nitpick comments (2)
indexer/services/roundtable/src/tasks/market-updater.ts (1)

55-62: LGTM! Consider adding type safety.

The implementation correctly handles null values and includes clear documentation. For better type safety, consider defining an interface for the tuple type.

+type TickerFundingRatePair = [string, string];
+
 const tickerDefaultFundingRate1HPairs: [string, string][] = _.map(
indexer/services/ender/__tests__/lib/candles-generator.test.ts (1)

676-689: Enhance test coverage for the orderbook price map.

The new test case verifies the basic functionality of getOrderbookMidPriceMap, but consider adding test cases for:

  1. Empty cache scenario
  2. Invalid price formats
  3. Price updates
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 78cef84 and fa9e6b5.

📒 Files selected for processing (16)
  • .github/workflows/indexer-build-and-push-dev-staging.yml (2 hunks)
  • .github/workflows/indexer-build-and-push-mainnet.yml (1 hunks)
  • indexer/packages/redis/__tests__/caches/orderbook-mid-prices-cache.test.ts (0 hunks)
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts (0 hunks)
  • indexer/packages/redis/src/index.ts (0 hunks)
  • indexer/services/ender/__tests__/caches/orderbook-mid-price-memory-cache.test.ts (0 hunks)
  • indexer/services/ender/__tests__/lib/candles-generator.test.ts (14 hunks)
  • indexer/services/ender/src/caches/oracle-price-memory-cache.ts (1 hunks)
  • indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts (0 hunks)
  • indexer/services/ender/src/handlers/markets/market-price-update-handler.ts (2 hunks)
  • indexer/services/ender/src/index.ts (0 hunks)
  • indexer/services/ender/src/lib/candles-generator.ts (2 hunks)
  • indexer/services/roundtable/__tests__/tasks/cache-orderbook-mid-prices.test.ts (0 hunks)
  • indexer/services/roundtable/src/index.ts (0 hunks)
  • indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts (0 hunks)
  • indexer/services/roundtable/src/tasks/market-updater.ts (2 hunks)
💤 Files with no reviewable changes (9)
  • indexer/packages/redis/src/index.ts
  • indexer/services/roundtable/src/index.ts
  • indexer/services/ender/src/index.ts
  • indexer/services/roundtable/src/tasks/cache-orderbook-mid-prices.ts
  • indexer/services/ender/tests/caches/orderbook-mid-price-memory-cache.test.ts
  • indexer/services/roundtable/tests/tasks/cache-orderbook-mid-prices.test.ts
  • indexer/services/ender/src/caches/orderbook-mid-price-memory-cache.ts
  • indexer/packages/redis/tests/caches/orderbook-mid-prices-cache.test.ts
  • indexer/packages/redis/src/caches/orderbook-mid-prices-cache.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/indexer-build-and-push-dev-staging.yml
  • indexer/services/ender/src/handlers/markets/market-price-update-handler.ts
  • indexer/services/ender/src/caches/oracle-price-memory-cache.ts
⏰ Context from checks skipped due to timeout of 90000ms (24)
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
🔇 Additional comments (8)
.github/workflows/indexer-build-and-push-mainnet.yml (1)

9-9: New Branch Trigger for 'oracle-price-candles' Added

The addition of the 'oracle-price-candles' branch in the push trigger is clear and aligns with the objective to include Oracle price caching updates. Ensure that all subsequent processes (e.g., build and push jobs) are compatible with changes deployed via this new branch.

indexer/services/roundtable/src/tasks/market-updater.ts (2)

80-80: LGTM! Cache function call is properly updated.

The NextFundingCache.getNextFunding call is correctly updated to use the new parameter structure and is properly awaited within Promise.all.


109-152: Consider moving the cache operation inside the transaction block.

The cache operation (getNextFunding) is performed outside the transaction block. If the subsequent database updates fail and rollback, the cache will be inconsistent with the database state.

Move the cache operation inside the transaction block to maintain data consistency across Redis and Postgres:

     const txId: number = await Transaction.start();
     try {
+      const fundingRates = await NextFundingCache.getNextFunding(
+        redisClient,
+        tickerDefaultFundingRate1HPairs,
+      );
       await PerpetualMarketTable.updateMarketCheckerFields(
indexer/services/ender/src/lib/candles-generator.ts (1)

29-29: LGTM!

The import for getOracleCachePrice is correctly placed with other cache-related imports.

indexer/services/ender/__tests__/lib/candles-generator.test.ts (4)

38-39: LGTM: Import changes align with the new oracle price caching mechanism.

The addition of DateTime from luxon and setOraclePrice from the oracle price memory cache reflects the transition from orderbook mid-price caching to oracle price caching.


73-75: LGTM: Helper function updated to use oracle price.

The setCachePrice helper function has been correctly updated to use setOraclePrice instead of the deprecated orderbook mid-price cache.


145-146: Verify oracle price consistency across test cases.

The test cases have been updated to use oracle prices instead of orderbook mid-prices. However, ensure that the expected values are consistent with the new oracle price mechanism:

  1. Some test cases expect null values (lines 377-378)
  2. Others expect specific price values
  3. Some test cases expect undefined values

Also applies to: 191-192, 316-317, 346-347, 377-378, 539-540, 568-569, 667-668

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for all oracle price related assertions
rg -A 2 'orderbookMidPrice(Open|Close).*[:=]' 

Length of output: 12364


Oracle Price Consistency Verified

The test cases clearly account for all three scenarios—explicit numeric values (e.g., '110000', '80500'), null, and undefined—which aligns with the new oracle price mechanism. No discrepancies were observed in the expected values.

  • The test at indexer/services/ender/tests/lib/candles-generator.test.ts (lines 145-146) sets explicit oracle price values.
  • Other test cases correctly expect null or undefined based on specific conditions.

42-45: Verify the time handling logic.

The test setup now uses DateTime for time calculations and mocks. Ensure that:

  1. The time calculations are consistent across all test cases
  2. The mock time reset in afterEach properly restores the system time

Also applies to: 56-57, 64-64

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for all DateTime usage to verify consistency
rg -A 2 'DateTime\.' 

Length of output: 78160


Time Handling Logic Verified

After reviewing the DateTime usage across the tests—particularly in the candles generator tests—it’s evident that the time calculations are consistent. The test constants are defined using DateTime.utc(), and the helper (which calls something like DateTime.fromSeconds(...).toUTC()) consistently returns a UTC DateTime. In addition, tests that mock time (using constructs such as jest.spyOn(DateTime, 'now')) appear to correctly reset or restore the mock (typically via afterEach or Jest’s auto–mock clearing) ensuring the system time is properly reinstated after each test.

  • Test constants (e.g. in helpers/constants.ts) use DateTime.utc(), ensuring a consistent UTC base.
  • Time arithmetic—including adding or subtracting minutes—is uniformly applied (with .toISO() or .toUTC().toISO()), yielding equivalent UTC-formatted strings.
  • The mechanism for mocking the current time in tests adheres to Jest practices, with afterEach (or equivalent resets) restoring the original system time across tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

2 participants