Skip to content

Conversation

@premiumjibles
Copy link
Contributor

@premiumjibles premiumjibles commented Dec 17, 2025

This adds graceful error handling to the affiliate revenue endpoint. Ensuring that if one swapper api fails we at least get partial data. It also will indicate in the API response which failed, ensuring we can show some kind of indicator in the UI.

Testing:

  • Make sure unchained ain't dead

If you want to properly test this locally:

  1. Install dependencies (from repo root)
    cd /home/sean/Repos/shapeshift-unchained
    yarn install

  2. Copy and configure env
    cp node/proxy/sample.env node/proxy/.env
    // Edit node/proxy/.env with real API keys (BEBOP_API_KEY, ZRX_API_KEY, etc.)

  3. Start reverse proxy (from repo root)
    docker-compose up -d reverse-proxy

  4. Start proxy API
    cd node/proxy
    docker-compose up

  5. Test endpoint (in another terminal)

curl "http://api.proxy.localhost/api/v1/affiliate/revenue?startTimestamp=$(( $(date +%s) - 604800 ))&endTimestamp=$(date +%s)"

Screenshots

image

Summary by CodeRabbit

  • New Features

    • Response now includes daily breakdown (byDate), per-service totals (byService), and failedProviders.
    • Added support for additional affiliate providers and improved caching for faster responses.
  • Bug Fixes

    • Improved resilience: partial results returned when individual providers fail, with per-provider failure tracking and normalized error messages.
  • API

    • Query parameters changed: startDate/endDate now expect YYYY-MM-DD.

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

@premiumjibles premiumjibles requested a review from a team as a code owner December 17, 2025 00:01
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

📝 Walkthrough

Walkthrough

Reworks affiliate revenue aggregation: parallelizes provider fetches with Promise.allSettled, tracks per-provider failures, adds per-day (byDate) and per-service breakdowns, extends Fees and AffiliateRevenueResponse, introduces per-provider modules with caching/utilities, and changes controller API to accept startDate/endDate (YYYY‑MM‑DD).

Changes

Cohort / File(s) Summary
Aggregator & API surface
node/proxy/api/src/affiliateRevenue/index.ts, node/proxy/api/src/controller.ts, node/proxy/api/src/models.ts, node/proxy/api/src/swagger.json
Switched to Promise.allSettled, added failedProviders, byDate aggregation, updated Fees and AffiliateRevenueResponse types, and changed controller params from timestamps to startDate/endDate.
New provider modules (core logic)
node/proxy/api/src/affiliateRevenue/*/*.{ts,tsx} (e.g., bebop/*, butterswap/*, chainflip/*, mayachain/*, nearIntents/*, portals/*, relay/*, thorchain/*, zrx/*)
Added/rewrote per-service implementations exposing getFees(startTimestamp,endTimestamp) with paging, caching, API calls, per-date grouping and provider-specific constants/types. Removed several legacy single-file providers and replaced with modular implementations.
Caching & shared helpers
node/proxy/api/src/affiliateRevenue/cache.ts, .../*/utils.ts
Introduced LRU-based fee/token/decimals caches, date helpers, cache key utilities, splitDateRange/grouping, and provider-specific helpers (RPC, retries, block estimation, asset parsing, price/decimals resolution).
Provider constants & types
node/proxy/api/src/affiliateRevenue/*/constants.ts, .../*/types.ts
New constant modules (API URLs, selectors, addresses, mappings) and typed response shapes for each provider; environment-key guards added in several constants files.
Portals (complex multi-chain)
node/proxy/api/src/affiliateRevenue/portals/{portals.ts,utils.ts,types.ts,constants.ts}
New multi-chain portals implementation: event decoding, transfer resolution, price lookup, asset id building, caching, and orchestrated per-chain fee construction.
Index barrels & re-exports
node/proxy/api/src/affiliateRevenue/*/index.ts
Added re-exports for each provider's getFees to standardize public surface.
Build / deps / misc
node/proxy/api/package.json, .gitignore, node/proxy/sample.env
Added lru-cache and viem deps, updated .gitignore to ignore docker-compose.override.yml, and normalized trailing newline in sample.env.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Controller
  participant Aggregator
  participant Cache
  participant ProviderA as Provider (e.g., bebop)
  participant ProviderB as Provider (e.g., butterswap)
  participant External as External APIs

  Client->>Controller: GET /affiliate/revenue?startDate&endDate
  Controller->>Aggregator: toTimestamps(startDate,endDate)
  Aggregator->>Cache: splitDateRange & tryGetCachedFees (parallel per-date)
  par Parallel provider fetches
    Aggregator->>ProviderA: getFees(startTs,endTs)
    Aggregator->>ProviderB: getFees(startTs,endTs)
  and Providers->>Cache: per-date read/write (tryGetCachedFees/saveCachedFees)
  Providers->>External: API / RPC / explorer calls
  External-->>Providers: responses
  Providers-->>Aggregator: resolved fees (or throw)
  end
  Aggregator->>Aggregator: Promise.allSettled(results) -> collect successes & failedProviders
  Aggregator->>Aggregator: group byDate, compute byService and totalUsd
  Aggregator-->>Controller: AffiliateRevenueResponse { totalUsd, byService, byDate, failedProviders }
  Controller-->>Client: 200 OK (JSON)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

🐰
I hopped through code with careful paws and cheer,
Grouped every provider far and near,
If one falls short, I still recall—
I count the days and note them all. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: finish implementing affiliate revenue endpoint' directly aligns with the PR objective to complete the affiliate revenue endpoint with graceful error handling, caching, and data aggregation across multiple providers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 11435_graceful_errors

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
node/proxy/api/src/swagger.json (1)

131-145: Consider adding maxItems constraint to the array.

The failedProviders field is correctly defined and marked as required. The array is naturally bounded by the number of services (7), but adding an explicit maxItems constraint would make this clear in the API contract.

Based on the static analysis hint, you could apply this diff:

 					"failedProviders": {
 						"items": {
 							"$ref": "#/components/schemas/Service"
 						},
-						"type": "array"
+						"type": "array",
+						"maxItems": 7
 					},
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 026c8f1 and 579ccea.

📒 Files selected for processing (3)
  • node/proxy/api/src/affiliateRevenue/index.ts (4 hunks)
  • node/proxy/api/src/models.ts (1 hunks)
  • node/proxy/api/src/swagger.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
node/proxy/api/src/affiliateRevenue/index.ts (1)
node/proxy/api/src/models.ts (1)
  • Service (6-6)
🪛 Checkov (3.2.334)
node/proxy/api/src/swagger.json

[medium] 131-135: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check
🔇 Additional comments (4)
node/proxy/api/src/models.ts (1)

10-10: LGTM!

The addition of failedProviders field correctly tracks which services failed, enabling the UI to display appropriate indicators.

node/proxy/api/src/affiliateRevenue/index.ts (2)

24-43: LGTM!

The switch to Promise.allSettled correctly implements graceful error handling. Failed providers are properly tracked and logged, while successful results are aggregated.


57-61: LGTM!

The return object correctly includes failedProviders, matching the updated AffiliateRevenueResponse interface.

node/proxy/api/src/swagger.json (1)

114-125: LGTM!

The Service enum schema correctly reflects all defined services and aligns with the TypeScript type definition.

@premiumjibles premiumjibles changed the title feat: add graceful error handling to affiliate revenue endpoint feat: finish implementing affiliate revenue endpoint Dec 29, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

♻️ Duplicate comments (1)
node/proxy/api/src/affiliateRevenue/index.ts (1)

14-24: Order-dependent mapping between providerNames and Promise.allSettled is fragile.

The providerNames array must be kept in sync with the order of promises in Promise.allSettled. If a developer adds or reorders providers, failures could be attributed to the wrong provider. This was flagged in a previous review.

Consider using a provider registry pattern as suggested previously.

Also applies to: 54-64

🧹 Nitpick comments (23)
node/proxy/api/src/affiliateRevenue/mayachain/types.ts (1)

1-11: Type definition is correct, but duplicates thorchain's FeesResponse.

This type is identical to FeesResponse in node/proxy/api/src/affiliateRevenue/thorchain/types.ts. Consider extracting a shared type to a common location to reduce duplication, unless the APIs are expected to diverge in the future.

node/proxy/api/src/affiliateRevenue/zrx/zrx.ts (1)

22-29: Consider adding timeout and error handling for the API request.

The axios request lacks a timeout configuration. Long-running or hanging requests could block the entire fetch operation. Given the PR's goal of graceful error handling, consider:

  1. Adding a request timeout
  2. Adding try-catch with meaningful error context
🔎 Proposed improvement
       const { data } = await axios.get<TradesResponse>(`${ZRX_API_URL}/${service}`, {
         params: { cursor, startTimestamp, endTimestamp },
         headers: {
           '0x-api-key': ZRX_API_KEY,
           '0x-version': 'v2',
         },
+        timeout: 30000, // 30 second timeout
       })
node/proxy/api/src/affiliateRevenue/thorchain/types.ts (1)

1-11: Consider extracting the duplicated type to a shared location.

The FeesResponse type is identical to the one in node/proxy/api/src/affiliateRevenue/mayachain/types.ts. Consider extracting this shared type definition to a common location (e.g., node/proxy/api/src/affiliateRevenue/types.ts or node/proxy/api/src/affiliateRevenue/common/types.ts) to follow the DRY principle and maintain consistency.

🔎 Suggested refactor

Create a shared types file and import from both modules:

// In a shared location like node/proxy/api/src/affiliateRevenue/common/types.ts
export type ChainFeesResponse = {
  fees: Array<{
    address: string
    amount: string
    asset: string
    blockHash: string
    blockHeight: number
    timestamp: number
    txId: string
  }>
}

Then import and re-export or alias in both thorchain and mayachain modules.

node/proxy/api/src/affiliateRevenue/relay/constants.ts (1)

4-4: Consider centralizing shared constants.

SHAPESHIFT_REFERRER is duplicated in multiple files (relay and bebop constants). Consider moving shared constants like this to the main affiliateRevenue/constants.ts file to maintain a single source of truth.

node/proxy/api/src/affiliateRevenue/mayachain/constants.ts (1)

1-4: Consider centralizing duplicate constants.

PRICE_API_URL and MILLISECONDS_PER_SECOND are duplicated in both mayachain and thorchain constants files with identical values. Consider moving these shared constants to the main affiliateRevenue/constants.ts file to reduce duplication and ensure consistency.

node/proxy/api/src/affiliateRevenue/bebop/constants.ts (1)

6-8: Consider centralizing duplicate constants.

Both SHAPESHIFT_REFERRER and FEE_BPS_DENOMINATOR are duplicated across multiple modules:

  • SHAPESHIFT_REFERRER also in relay/constants.ts
  • FEE_BPS_DENOMINATOR also in nearIntents and portals constants

Consider moving these to the main affiliateRevenue/constants.ts file to maintain a single source of truth.

node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (2)

21-24: Top-level throw may crash application on startup.

The guard at line 24 executes at module load time. If NEAR_INTENTS_API_KEY is unset, the entire application will crash during startup, preventing other providers from functioning. Given the PR's goal of graceful error handling, consider deferring this check to runtime when getFees is called.

🔎 Proposed fix
-export const NEAR_INTENTS_API_KEY = process.env.NEAR_INTENTS_API_KEY
+export const NEAR_INTENTS_API_KEY = process.env.NEAR_INTENTS_API_KEY ?? ''
 export const FEE_BPS_DENOMINATOR = 10000
-
-if (!NEAR_INTENTS_API_KEY) throw new Error('NEAR_INTENTS_API_KEY env var not set')

Then validate in the getFees function:

if (!NEAR_INTENTS_API_KEY) {
  throw new Error('NEAR_INTENTS_API_KEY env var not set')
}

43-43: Hardcoded chain ID for monad.

The monad mapping uses a hardcoded value 'eip155:143' while all other chains use imported constants. Consider adding a MONAD_CHAIN_ID constant to ../constants for consistency and maintainability.

node/proxy/api/src/affiliateRevenue/relay/relay.ts (1)

22-30: Consider adding request timeout.

The axios request has no timeout configured. If the Relay API becomes unresponsive, this could block indefinitely. Other network-related issues could also cause hanging requests.

🔎 Proposed fix
     const { data } = await axios.get<RelayResponse>(`${RELAY_API_URL}/requests/v2`, {
       params: {
         referrer: SHAPESHIFT_REFERRER,
         startTimestamp,
         endTimestamp,
         status: 'success',
         continuation,
       },
+      timeout: 30000, // 30 second timeout
     })
node/proxy/api/src/affiliateRevenue/thorchain/thorchain.ts (1)

42-53: Price fetched per API call may cause inconsistent USD values.

getRunePriceUsd() is called inside fetchFeesFromAPI, which can be invoked multiple times (for cached date ranges and recent data). If the RUNE price changes between calls, fees from the same query will have inconsistent USD valuations.

Consider fetching the price once in getFees and passing it to fetchFeesFromAPI.

🔎 Proposed fix
-const fetchFeesFromAPI = async (startTimestamp: number, endTimestamp: number): Promise<Fees[]> => {
+const fetchFeesFromAPI = async (startTimestamp: number, endTimestamp: number, runePriceUsd: number): Promise<Fees[]> => {
   const start = startTimestamp * MILLISECONDS_PER_SECOND
   const end = endTimestamp * MILLISECONDS_PER_SECOND

   const { data } = await axios.get<FeesResponse>(THORCHAIN_API_URL, {
     params: { start, end },
   })

-  const runePriceUsd = await getRunePriceUsd()
-
   return data.fees.map(fee => transformFee(fee, runePriceUsd))
 }

 export const getFees = async (startTimestamp: number, endTimestamp: number): Promise<Fees[]> => {
+  const runePriceUsd = await getRunePriceUsd()
   const threshold = getCacheableThreshold()
   // ... update calls to fetchFeesFromAPI to pass runePriceUsd
node/proxy/api/src/affiliateRevenue/portals/portals.ts (1)

322-326: Silent failure handling for per-chain fetching.

Failed chain fetches are silently dropped without logging. This could make debugging difficult when a specific chain's data is missing. Consider adding logging for rejected results.

🔎 Proposed fix
   for (const result of results) {
     if (result.status === 'fulfilled') {
       allFees.push(...result.value)
+    } else {
+      console.error(`[portals] Chain fetch failed:`, result.reason)
     }
   }
node/proxy/api/src/affiliateRevenue/chainflip/chainflip.ts (1)

38-53: Consider using swapRequestNativeId as the transaction identifier.

The txHash is set to an empty string, but the GraphQL response includes swapRequestNativeId which could serve as a unique identifier for each swap. This would improve traceability and debugging.

🔎 Proposed fix
       fees.push({
         chainId,
         assetId,
         service: 'chainflip',
-        txHash: '',
+        txHash: swap.swapRequestNativeId,
         timestamp: Math.floor(new Date(swap.completedBlockTimestamp).getTime() / 1000),
         amount: '0',
         amountUsd: swap.affiliateBroker1FeeValueUsd,
       })
node/proxy/api/src/affiliateRevenue/butterswap/butterswap.ts (1)

98-99: Potential precision loss with large fee values.

Converting BigInt to Number via Number(feesPerDay) can lose precision for values exceeding Number.MAX_SAFE_INTEGER (~9 quadrillion). For USDT with 6 decimals, this threshold is ~9 billion USD per day, which is unlikely but worth noting.

Additionally, integer division on line 98 discards any remainder, which could result in small undercounting. Consider distributing the remainder across some days or using the total for USD calculation.

node/proxy/api/src/affiliateRevenue/nearIntents/nearIntents.ts (1)

23-25: Consider moving the API URL to constants.

The API URL is hardcoded inline. For consistency with other modules (e.g., CHAINFLIP_API_URL, BEBOP_API_URL), consider extracting this to a constant in ./constants.ts.

🔎 Proposed change

In constants.ts:

export const NEAR_INTENTS_API_URL = 'https://explorer.near-intents.org/api/v0/transactions-pages'

In nearIntents.ts:

+import { FEE_BPS_DENOMINATOR, NEAR_INTENTS_API_KEY, NEAR_INTENTS_API_URL } from './constants'

     const { data } = await axios.get<TransactionsResponse>(
-      'https://explorer.near-intents.org/api/v0/transactions-pages',
+      NEAR_INTENTS_API_URL,
node/proxy/api/src/affiliateRevenue/portals/constants.ts (1)

21-22: FEE_BPS_DENOMINATOR is duplicated across multiple modules.

This constant is defined in bebop/constants.ts, nearIntents/constants.ts, and here. Consider extracting it to the shared ../constants.ts to avoid duplication.

node/proxy/api/src/affiliateRevenue/butterswap/constants.ts (1)

16-25: Consider adding inline documentation for fallback tokens.

These hardcoded addresses lack context. A brief comment explaining what these tokens represent (e.g., "common ButterSwap tokens on MAP chain") would aid maintainability.

Suggested improvement
+// Fallback token addresses on MAP chain used when token list API is unavailable
 export const FALLBACK_TOKENS = [
   '0x05ab928d446d8ce6761e368c8e7be03c3168a9ec',
   // ... rest of tokens
 ]
node/proxy/api/src/affiliateRevenue/zrx/types.ts (1)

1-5: Consider exporting the Fee type.

The Fee type is used in TradesResponse but isn't exported. If consumers need to reference this type independently, it should be exported.

Suggested fix
-type Fee = {
+export type Fee = {
   token?: string
   amount?: string
   amountUsd?: string
 }
node/proxy/api/src/affiliateRevenue/portals/utils.ts (4)

8-12: Add timeout to external API call.

The axios.get call to the explorer API lacks a timeout, which could cause the request to hang indefinitely if the explorer is unresponsive.

Suggested fix
 export const getTransactionTimestamp = async (explorerUrl: string, txHash: string): Promise<number> => {
   const url = `${explorerUrl}/api/v2/transactions/${txHash}`
-  const { data } = await axios.get<BlockscoutTransaction>(url)
+  const { data } = await axios.get<BlockscoutTransaction>(url, { timeout: 10000 })
   return Math.floor(new Date(data.timestamp).getTime() / 1000)
 }

14-28: Add a comment explaining the magic number 258.

The minimum data length check of 258 should be documented to explain its derivation (e.g., ABI-encoded 5 parameters × 32 bytes + 2 byte prefix + overhead).

Suggested improvement
 export const decodePortalEventData = (data: string): DecodedPortalEvent | null => {
+  // Minimum length: 0x prefix (2) + 5 ABI-encoded params (5 × 64 hex chars = 320) = 322
+  // Using 258 as conservative minimum for valid portal event data
   if (!data || data.length < 258) return null

47-64: Add timeout to token decimals API calls.

Both Blockscout and Etherscan API calls lack timeouts. This is especially important since these calls are made during fee calculation flows.

Suggested fix
   try {
     if (explorerType === 'blockscout') {
-      const { data } = await axios.get<{ decimals?: string }>(`${explorerUrl}/api/v2/tokens/${tokenAddress}`)
+      const { data } = await axios.get<{ decimals?: string }>(`${explorerUrl}/api/v2/tokens/${tokenAddress}`, { timeout: 10000 })
       const decimals = parseInt(data.decimals ?? '18')
       saveCachedDecimals(cacheKey, decimals)
       return decimals
     }

-    const { data } = await axios.get<{ result?: Array<{ divisor?: string }> }>(`${explorerUrl}/api`, {
+    const { data } = await axios.get<{ result?: Array<{ divisor?: string }> }>(`${explorerUrl}/api`, {
+      timeout: 10000,
       params: { module: 'token', action: 'tokeninfo', contractaddress: tokenAddress },
     })

73-110: Module-level priceCache object can grow unbounded.

Unlike feeCache, tokenTransferCache, and decimalsCache which use LRUCache with size limits, this priceCache is a plain object that can grow indefinitely. Consider using LRUCache for consistency and memory safety.

Suggested fix
+import { LRUCache } from 'lru-cache'
+
-const priceCache: Record<string, { price: number | null; timestamp: number }> = {}
-const PRICE_CACHE_TTL = 1000 * 60 * 5 // 5 minutes
+const priceCache = new LRUCache<string, number | null>({
+  max: 1000,
+  ttl: 1000 * 60 * 5, // 5 minutes
+})

 export const getTokenPrice = async (chainId: string, tokenAddress: string): Promise<number | null> => {
   const cacheKey = `${chainId}:${tokenAddress.toLowerCase()}`
-  const cached = priceCache[cacheKey]
-  if (cached && Date.now() - cached.timestamp < PRICE_CACHE_TTL) {
-    return cached.price
-  }
+  const cached = priceCache.get(cacheKey)
+  if (cached !== undefined) return cached
   // ... rest of function, replace priceCache[cacheKey] = { price, timestamp: Date.now() } with priceCache.set(cacheKey, price)

Also add timeouts to the CoinGecko API calls on lines 92 and 101.

node/proxy/api/src/affiliateRevenue/cache.ts (2)

24-27: Potential edge case with toISOString().split('T')[0].

The return type annotation guarantees string, but split('T')[0] could theoretically return undefined if the ISO string format changes. TypeScript won't catch this. Consider adding a non-null assertion or fallback for defensive coding.

Suggested fix
 export const timestampToDate = (timestamp: number): string => {
   const date = new Date(timestamp * 1000)
-  return date.toISOString().split('T')[0]
+  return date.toISOString().split('T')[0] ?? ''
 }

50-52: Off-by-one second in getDateEndTimestamp.

23:59:59 is 1 second before midnight. This could cause edge cases where transactions at exactly 23:59:59.5 might be included or excluded unexpectedly. Consider using T23:59:59.999Z or adjusting the comparison logic.

Suggested fix
 export const getDateEndTimestamp = (date: string): number => {
-  return Math.floor(new Date(date + 'T23:59:59Z').getTime() / 1000)
+  return Math.floor(new Date(date + 'T23:59:59.999Z').getTime() / 1000)
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 579ccea and e93a7bc.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (56)
  • .gitignore
  • node/proxy/api/package.json
  • node/proxy/api/src/affiliateRevenue/bebop.ts
  • node/proxy/api/src/affiliateRevenue/bebop/bebop.ts
  • node/proxy/api/src/affiliateRevenue/bebop/constants.ts
  • node/proxy/api/src/affiliateRevenue/bebop/index.ts
  • node/proxy/api/src/affiliateRevenue/bebop/types.ts
  • node/proxy/api/src/affiliateRevenue/butterswap/butterswap.ts
  • node/proxy/api/src/affiliateRevenue/butterswap/constants.ts
  • node/proxy/api/src/affiliateRevenue/butterswap/index.ts
  • node/proxy/api/src/affiliateRevenue/butterswap/types.ts
  • node/proxy/api/src/affiliateRevenue/butterswap/utils.ts
  • node/proxy/api/src/affiliateRevenue/cache.ts
  • node/proxy/api/src/affiliateRevenue/chainflip.ts
  • node/proxy/api/src/affiliateRevenue/chainflip/chainflip.ts
  • node/proxy/api/src/affiliateRevenue/chainflip/constants.ts
  • node/proxy/api/src/affiliateRevenue/chainflip/index.ts
  • node/proxy/api/src/affiliateRevenue/chainflip/types.ts
  • node/proxy/api/src/affiliateRevenue/constants.ts
  • node/proxy/api/src/affiliateRevenue/index.ts
  • node/proxy/api/src/affiliateRevenue/mayachain.ts
  • node/proxy/api/src/affiliateRevenue/mayachain/constants.ts
  • node/proxy/api/src/affiliateRevenue/mayachain/index.ts
  • node/proxy/api/src/affiliateRevenue/mayachain/mayachain.ts
  • node/proxy/api/src/affiliateRevenue/mayachain/types.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents/index.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents/nearIntents.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents/types.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents/utils.ts
  • node/proxy/api/src/affiliateRevenue/portals.ts
  • node/proxy/api/src/affiliateRevenue/portals/constants.ts
  • node/proxy/api/src/affiliateRevenue/portals/index.ts
  • node/proxy/api/src/affiliateRevenue/portals/portals.ts
  • node/proxy/api/src/affiliateRevenue/portals/types.ts
  • node/proxy/api/src/affiliateRevenue/portals/utils.ts
  • node/proxy/api/src/affiliateRevenue/relay/constants.ts
  • node/proxy/api/src/affiliateRevenue/relay/index.ts
  • node/proxy/api/src/affiliateRevenue/relay/relay.ts
  • node/proxy/api/src/affiliateRevenue/relay/types.ts
  • node/proxy/api/src/affiliateRevenue/relay/utils.ts
  • node/proxy/api/src/affiliateRevenue/thorchain.ts
  • node/proxy/api/src/affiliateRevenue/thorchain/constants.ts
  • node/proxy/api/src/affiliateRevenue/thorchain/index.ts
  • node/proxy/api/src/affiliateRevenue/thorchain/thorchain.ts
  • node/proxy/api/src/affiliateRevenue/thorchain/types.ts
  • node/proxy/api/src/affiliateRevenue/zrx.ts
  • node/proxy/api/src/affiliateRevenue/zrx/constants.ts
  • node/proxy/api/src/affiliateRevenue/zrx/index.ts
  • node/proxy/api/src/affiliateRevenue/zrx/types.ts
  • node/proxy/api/src/affiliateRevenue/zrx/zrx.ts
  • node/proxy/api/src/controller.ts
  • node/proxy/api/src/models.ts
  • node/proxy/api/src/swagger.json
  • node/proxy/sample.env
💤 Files with no reviewable changes (7)
  • node/proxy/api/src/affiliateRevenue/bebop.ts
  • node/proxy/api/src/affiliateRevenue/nearIntents.ts
  • node/proxy/api/src/affiliateRevenue/portals.ts
  • node/proxy/api/src/affiliateRevenue/chainflip.ts
  • node/proxy/api/src/affiliateRevenue/mayachain.ts
  • node/proxy/api/src/affiliateRevenue/zrx.ts
  • node/proxy/api/src/affiliateRevenue/thorchain.ts
✅ Files skipped from review due to trivial changes (2)
  • node/proxy/sample.env
  • .gitignore
🧰 Additional context used
🧬 Code graph analysis (22)
node/proxy/api/src/affiliateRevenue/butterswap/utils.ts (3)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • MAP_RPC_URL (37-37)
node/proxy/api/src/affiliateRevenue/butterswap/constants.ts (2)
  • MAP_RPC_URL (3-3)
  • BLOCK_TIME_SECONDS (5-5)
node/proxy/api/src/affiliateRevenue/butterswap/types.ts (1)
  • RpcResponse (1-6)
node/proxy/api/src/affiliateRevenue/thorchain/constants.ts (1)
node/proxy/api/src/affiliateRevenue/mayachain/constants.ts (2)
  • PRICE_API_URL (2-2)
  • MILLISECONDS_PER_SECOND (3-3)
node/proxy/api/src/affiliateRevenue/relay/relay.ts (8)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/relay/types.ts (1)
  • RelayResponse (45-48)
node/proxy/api/src/affiliateRevenue/relay/constants.ts (2)
  • RELAY_API_URL (3-3)
  • SHAPESHIFT_REFERRER (4-4)
node/proxy/api/src/affiliateRevenue/bebop/constants.ts (1)
  • SHAPESHIFT_REFERRER (6-6)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • DAO_TREASURY_BASE (9-9)
node/proxy/api/src/affiliateRevenue/relay/utils.ts (2)
  • getChainConfig (7-26)
  • buildAssetId (28-48)
node/proxy/api/src/affiliateRevenue/relay/index.ts (1)
  • getFees (1-1)
node/proxy/api/src/affiliateRevenue/cache.ts (7)
  • getCacheableThreshold (54-58)
  • splitDateRange (74-93)
  • tryGetCachedFees (64-67)
  • getDateStartTimestamp (46-48)
  • getDateEndTimestamp (50-52)
  • groupFeesByDate (95-107)
  • saveCachedFees (69-72)
node/proxy/api/src/affiliateRevenue/thorchain/types.ts (1)
node/proxy/api/src/affiliateRevenue/mayachain/types.ts (1)
  • FeesResponse (1-11)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
node/proxy/api/src/affiliateRevenue/butterswap/constants.ts (5)
  • MAP_CHAIN_ID (3-3)
  • BUTTERSWAP_CONTRACT (3-3)
  • MAP_USDT_ADDRESS (3-3)
  • MAP_RPC_URL (3-3)
  • BUTTERSWAP_AFFILIATE_ID (3-3)
node/proxy/api/src/affiliateRevenue/zrx/zrx.ts (12)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/zrx/constants.ts (3)
  • SERVICES (10-10)
  • ZRX_API_URL (9-9)
  • NATIVE_TOKEN_ADDRESS (3-3)
node/proxy/api/src/affiliateRevenue/zrx/types.ts (1)
  • TradesResponse (7-37)
node/proxy/api/src/affiliateRevenue/constants.ts (2)
  • NATIVE_TOKEN_ADDRESS (1-1)
  • SLIP44 (41-53)
node/proxy/api/src/affiliateRevenue/bebop/bebop.ts (1)
  • getFees (48-89)
node/proxy/api/src/affiliateRevenue/butterswap/butterswap.ts (1)
  • getFees (72-110)
node/proxy/api/src/affiliateRevenue/chainflip/chainflip.ts (1)
  • getFees (62-103)
node/proxy/api/src/affiliateRevenue/mayachain/mayachain.ts (1)
  • getFees (55-96)
node/proxy/api/src/affiliateRevenue/nearIntents/nearIntents.ts (1)
  • getFees (89-130)
node/proxy/api/src/affiliateRevenue/portals/portals.ts (1)
  • getFees (281-329)
node/proxy/api/src/affiliateRevenue/relay/relay.ts (1)
  • getFees (70-111)
node/proxy/api/src/affiliateRevenue/cache.ts (7)
  • getCacheableThreshold (54-58)
  • splitDateRange (74-93)
  • tryGetCachedFees (64-67)
  • getDateStartTimestamp (46-48)
  • getDateEndTimestamp (50-52)
  • groupFeesByDate (95-107)
  • saveCachedFees (69-72)
node/proxy/api/src/affiliateRevenue/mayachain/types.ts (1)
node/proxy/api/src/affiliateRevenue/thorchain/types.ts (1)
  • FeesResponse (1-11)
node/proxy/api/src/controller.ts (2)
node/proxy/api/src/models.ts (1)
  • AffiliateRevenueResponse (23-28)
go/pkg/api/api.go (1)
  • Error (7-10)
node/proxy/api/src/affiliateRevenue/thorchain/thorchain.ts (5)
node/proxy/api/src/affiliateRevenue/thorchain/constants.ts (4)
  • PRICE_API_URL (2-2)
  • RUNE_DECIMALS (4-4)
  • MILLISECONDS_PER_SECOND (3-3)
  • THORCHAIN_API_URL (1-1)
node/proxy/api/src/affiliateRevenue/thorchain/types.ts (1)
  • FeesResponse (1-11)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • THORCHAIN_CHAIN_ID (18-18)
node/proxy/api/src/affiliateRevenue/cache.ts (7)
  • getCacheableThreshold (54-58)
  • splitDateRange (74-93)
  • tryGetCachedFees (64-67)
  • getDateStartTimestamp (46-48)
  • getDateEndTimestamp (50-52)
  • groupFeesByDate (95-107)
  • saveCachedFees (69-72)
node/proxy/api/src/affiliateRevenue/nearIntents/nearIntents.ts (5)
node/proxy/api/src/affiliateRevenue/nearIntents/types.ts (1)
  • TransactionsResponse (3-35)
node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (2)
  • NEAR_INTENTS_API_KEY (21-21)
  • FEE_BPS_DENOMINATOR (22-22)
node/proxy/api/src/affiliateRevenue/nearIntents/utils.ts (2)
  • sleep (62-62)
  • parseNearIntentsAsset (26-60)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/cache.ts (7)
  • getCacheableThreshold (54-58)
  • splitDateRange (74-93)
  • tryGetCachedFees (64-67)
  • getDateStartTimestamp (46-48)
  • getDateEndTimestamp (50-52)
  • groupFeesByDate (95-107)
  • saveCachedFees (69-72)
node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (1)
node/proxy/api/src/affiliateRevenue/constants.ts (17)
  • ETHEREUM_CHAIN_ID (24-24)
  • ARBITRUM_CHAIN_ID (31-31)
  • BASE_CHAIN_ID (29-29)
  • GNOSIS_CHAIN_ID (27-27)
  • BSC_CHAIN_ID (26-26)
  • POLYGON_CHAIN_ID (28-28)
  • AVALANCHE_CHAIN_ID (32-32)
  • OPTIMISM_CHAIN_ID (25-25)
  • BITCOIN_CHAIN_ID (12-12)
  • DOGECOIN_CHAIN_ID (13-13)
  • ZCASH_CHAIN_ID (14-14)
  • SOLANA_CHAIN_ID (15-15)
  • TRON_CHAIN_ID (16-16)
  • SUI_CHAIN_ID (17-17)
  • NEAR_CHAIN_ID (20-20)
  • STARKNET_CHAIN_ID (21-21)
  • SLIP44 (41-53)
node/proxy/api/src/affiliateRevenue/portals/constants.ts (4)
node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (1)
  • FEE_BPS_DENOMINATOR (22-22)
node/proxy/api/src/affiliateRevenue/bebop/constants.ts (1)
  • FEE_BPS_DENOMINATOR (8-8)
node/proxy/api/src/affiliateRevenue/portals/types.ts (1)
  • ChainConfig (3-10)
node/proxy/api/src/affiliateRevenue/constants.ts (14)
  • ETHEREUM_CHAIN_ID (24-24)
  • DAO_TREASURY_ETHEREUM (2-2)
  • ARBITRUM_CHAIN_ID (31-31)
  • DAO_TREASURY_ARBITRUM (8-8)
  • OPTIMISM_CHAIN_ID (25-25)
  • DAO_TREASURY_OPTIMISM (3-3)
  • BASE_CHAIN_ID (29-29)
  • DAO_TREASURY_BASE (9-9)
  • POLYGON_CHAIN_ID (28-28)
  • DAO_TREASURY_POLYGON (5-5)
  • GNOSIS_CHAIN_ID (27-27)
  • DAO_TREASURY_GNOSIS (6-6)
  • BSC_CHAIN_ID (26-26)
  • AVALANCHE_CHAIN_ID (32-32)
node/proxy/api/src/affiliateRevenue/bebop/types.ts (1)
node/proxy/api/src/affiliateRevenue/zrx/types.ts (1)
  • TradesResponse (7-37)
node/proxy/api/src/affiliateRevenue/bebop/constants.ts (4)
go/pkg/api/api.go (1)
  • Error (7-10)
node/proxy/api/src/affiliateRevenue/relay/constants.ts (1)
  • SHAPESHIFT_REFERRER (4-4)
node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (1)
  • FEE_BPS_DENOMINATOR (22-22)
node/proxy/api/src/affiliateRevenue/portals/constants.ts (1)
  • FEE_BPS_DENOMINATOR (22-22)
node/proxy/api/src/affiliateRevenue/relay/constants.ts (2)
node/proxy/api/src/affiliateRevenue/bebop/constants.ts (1)
  • SHAPESHIFT_REFERRER (6-6)
node/proxy/api/src/affiliateRevenue/constants.ts (4)
  • SOLANA_CHAIN_ID (15-15)
  • SLIP44 (41-53)
  • BITCOIN_CHAIN_ID (12-12)
  • TRON_CHAIN_ID (16-16)
node/proxy/api/src/affiliateRevenue/index.ts (2)
node/proxy/api/src/models.ts (3)
  • Service (16-16)
  • AffiliateRevenueResponse (23-28)
  • services (5-15)
node/proxy/api/src/affiliateRevenue/cache.ts (1)
  • timestampToDate (24-27)
node/proxy/api/src/affiliateRevenue/relay/utils.ts (1)
node/proxy/api/src/affiliateRevenue/relay/constants.ts (1)
  • NON_EVM_CHAINS (6-12)
node/proxy/api/src/affiliateRevenue/portals/utils.ts (5)
node/proxy/api/src/affiliateRevenue/portals/types.ts (2)
  • BlockscoutTransaction (40-43)
  • DecodedPortalEvent (90-95)
node/proxy/api/src/affiliateRevenue/portals/constants.ts (5)
  • PORTAL_EVENT_ABI (25-31)
  • AFFILIATE_FEE_BPS (21-21)
  • FEE_BPS_DENOMINATOR (22-22)
  • COINGECKO_CHAINS (100-109)
  • COINGECKO_API_BASE (111-111)
node/proxy/api/src/affiliateRevenue/cache.ts (2)
  • getCachedDecimals (118-120)
  • saveCachedDecimals (122-124)
node/proxy/api/src/affiliateRevenue/nearIntents/utils.ts (1)
  • buildAssetId (13-24)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • SLIP44 (41-53)
node/proxy/api/src/affiliateRevenue/zrx/types.ts (2)
go/pkg/cosmos/tx.go (1)
  • Fee (281-294)
node/proxy/api/src/affiliateRevenue/bebop/types.ts (1)
  • TradesResponse (1-37)
node/proxy/api/src/affiliateRevenue/chainflip/chainflip.ts (5)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/chainflip/types.ts (1)
  • GraphQLResponse (1-17)
node/proxy/api/src/affiliateRevenue/chainflip/constants.ts (4)
  • CHAINFLIP_API_URL (1-1)
  • GET_AFFILIATE_SWAPS_QUERY (5-38)
  • SHAPESHIFT_BROKER_ID (3-3)
  • PAGE_SIZE (2-2)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • ETHEREUM_CHAIN_ID (24-24)
node/proxy/api/src/affiliateRevenue/cache.ts (7)
  • getCacheableThreshold (54-58)
  • splitDateRange (74-93)
  • tryGetCachedFees (64-67)
  • getDateStartTimestamp (46-48)
  • getDateEndTimestamp (50-52)
  • groupFeesByDate (95-107)
  • saveCachedFees (69-72)
node/proxy/api/src/affiliateRevenue/cache.ts (1)
node/proxy/api/src/affiliateRevenue/index.ts (1)
  • Fees (39-47)
node/proxy/api/src/affiliateRevenue/nearIntents/utils.ts (2)
node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (2)
  • NEAR_INTENTS_TO_CHAIN_ID (26-44)
  • SLIP44_BY_NETWORK (46-55)
node/proxy/api/src/affiliateRevenue/constants.ts (1)
  • SLIP44 (41-53)
🪛 Checkov (3.2.334)
node/proxy/api/src/swagger.json

[medium] 175-180: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check
🔇 Additional comments (57)
node/proxy/api/src/affiliateRevenue/zrx/zrx.ts (1)

58-98: Caching implementation is well-structured.

The date-range splitting, batch fetching of missing dates, and per-day caching approach is efficient and follows the established pattern across other affiliate revenue modules.

node/proxy/api/src/affiliateRevenue/zrx/index.ts (1)

1-1: Clean barrel export pattern.

Consistent with other affiliate revenue module structures.

node/proxy/api/src/affiliateRevenue/nearIntents/index.ts (1)

1-1: LGTM!

Standard barrel export, consistent with the module structure pattern.

node/proxy/api/src/affiliateRevenue/mayachain/index.ts (1)

1-1: LGTM!

Consistent barrel export pattern for the Mayachain module.

node/proxy/api/src/affiliateRevenue/relay/index.ts (1)

1-1: LGTM!

Consistent barrel export pattern for the Relay module.

node/proxy/api/src/affiliateRevenue/chainflip/index.ts (1)

1-1: LGTM!

The barrel export follows the standard pattern and correctly exposes the getFees function from the chainflip module.

node/proxy/api/src/affiliateRevenue/thorchain/index.ts (1)

1-1: LGTM!

The barrel export follows the standard pattern and correctly exposes the getFees function from the thorchain module.

node/proxy/api/src/affiliateRevenue/portals/index.ts (1)

1-1: LGTM!

The barrel export follows the standard pattern and correctly exposes the getFees function from the portals module.

node/proxy/api/src/affiliateRevenue/bebop/index.ts (1)

1-1: LGTM!

The barrel export follows the standard pattern and correctly exposes the getFees function from the bebop module.

node/proxy/api/src/affiliateRevenue/butterswap/index.ts (1)

1-1: LGTM!

The barrel export follows the standard pattern and correctly exposes the getFees function from the butterswap module.

node/proxy/api/src/affiliateRevenue/butterswap/types.ts (2)

8-15: LGTM!

The TokenListResponse type structure is clear and appropriate for modeling the butterswap token list API response.


1-6: Consumer code properly handles JSON-RPC error semantics—no action needed.

The rpcCall function in utils.ts correctly checks for the presence of error (line 18) and throws before accessing result (line 22). This prevents processing invalid response states where both fields might theoretically exist according to the type definition.

While the type definition is permissive in allowing both result and error fields simultaneously, the runtime behavior enforces the correct JSON-RPC 2.0 semantics where they are mutually exclusive in practice.

node/proxy/api/src/affiliateRevenue/mayachain/mayachain.ts (1)

27-40: LGTM!

The fee transformation logic correctly maps external API fields to the internal Fees format, and the timestamp conversion from milliseconds to seconds (line 36) is accurate.

node/proxy/api/src/affiliateRevenue/constants.ts (1)

10-56: LGTM!

The constants are well-organized and follow standard formats (CAIP-2 for chain IDs, SLIP44 for coin types). The use of as const on the SLIP44 object provides proper type narrowing.

node/proxy/api/src/affiliateRevenue/butterswap/utils.ts (1)

25-33: LGTM!

The block estimation logic is correct: it calculates the time difference, divides by block time, and properly clamps the result to valid bounds.

node/proxy/api/src/affiliateRevenue/bebop/types.ts (1)

1-37: LGTM!

The type definition is well-structured with appropriate use of optional fields and union types.

node/proxy/api/src/affiliateRevenue/chainflip/types.ts (1)

1-17: LGTM!

The GraphQL response type is properly structured and appropriately models the expected API response shape.

node/proxy/api/src/affiliateRevenue/thorchain/constants.ts (1)

1-4: LGTM!

The constants are correctly defined. Note that the duplication of PRICE_API_URL and MILLISECONDS_PER_SECOND with mayachain constants has been flagged for potential centralization in the mayachain file review.

node/proxy/api/src/affiliateRevenue/bebop/constants.ts (1)

1-3: Verify the fail-fast behavior for missing API key.

The module throws immediately if BEBOP_API_KEY is not set, which will happen at module load time. This means:

  • Any import of this module will fail if the key is missing
  • The application cannot start without the key, even if Bebop functionality isn't used

Please confirm this fail-fast behavior is intentional. If the key is only needed when Bebop is actually called, consider lazy evaluation or moving the check to the function that uses it.

node/proxy/api/src/affiliateRevenue/nearIntents/constants.ts (1)

46-55: LGTM!

The SLIP44 mapping correctly covers non-EVM networks. EVM networks can default to SLIP44.ETHEREUM (60) in the consuming code.

node/proxy/api/src/affiliateRevenue/relay/relay.ts (1)

70-111: LGTM!

The caching implementation follows a consistent pattern with other provider modules, properly splitting cacheable historical dates from recent data, and logging cache statistics.

node/proxy/api/src/affiliateRevenue/thorchain/thorchain.ts (1)

55-96: LGTM!

The caching implementation correctly handles date-based splitting and follows the established pattern used by other provider modules.

node/proxy/api/src/affiliateRevenue/relay/types.ts (1)

1-34: LGTM!

The type definitions properly model the Relay API response structure with appropriate optional fields.

node/proxy/api/src/affiliateRevenue/chainflip/constants.ts (1)

1-38: LGTM!

The constants are well-defined with appropriate naming. The GraphQL query is properly parameterized and includes necessary pagination and filtering.

node/proxy/api/src/affiliateRevenue/portals/portals.ts (1)

125-171: LGTM!

The Etherscan implementation efficiently uses topic filtering and implements early exit when reaching the start timestamp boundary.

node/proxy/api/src/affiliateRevenue/index.ts (2)

26-37: LGTM!

The formatError helper provides good error context for debugging, handling axios errors with status codes and generic errors appropriately.


76-101: LGTM!

The aggregation logic correctly builds per-date and per-service breakdowns, and properly handles the new byDate and failedProviders fields in the response.

node/proxy/api/src/affiliateRevenue/nearIntents/types.ts (1)

1-35: LGTM!

The type definitions are well-structured, accurately model the Near Intents API response, and properly support pagination with optional nextPage/prevPage fields.

node/proxy/api/src/affiliateRevenue/chainflip/chainflip.ts (1)

62-103: LGTM!

The caching logic is well-implemented with efficient batching of cache misses into a single API call, proper date-based grouping, and separate handling for recent (non-cacheable) data.

node/proxy/api/src/affiliateRevenue/butterswap/butterswap.ts (3)

26-46: LGTM!

The token list fetching with TTL-based caching and graceful fallback to static tokens provides good resilience against API failures.


48-66: LGTM!

The RPC calls for block number and balance queries are properly implemented with correct ABI encoding via viem.


81-87: LGTM!

Good error handling pattern that wraps balance query failures with a descriptive error message while preserving the original error context.

node/proxy/api/src/affiliateRevenue/nearIntents/nearIntents.ts (2)

63-75: LGTM!

The fee calculation correctly uses basis points, and the multi-source txHash fallback chain provides good resilience. The 1-second delay between page fetches is a reasonable rate-limiting precaution.


89-130: LGTM!

The caching logic follows the established pattern across provider modules and correctly uses 'all' as the chain identifier since Near Intents transactions span multiple chains.

node/proxy/api/src/models.ts (1)

5-28: LGTM!

The type definitions properly support the graceful error handling feature:

  • services array includes all providers
  • DailyRevenue enables per-day breakdowns
  • failedProviders: Service[] allows the API to indicate which providers failed, enabling the UI to show appropriate indicators
node/proxy/api/src/affiliateRevenue/relay/utils.ts (2)

3-26: LGTM!

The chain detection logic is well-structured with explicit mappings for known non-EVM chains in NON_EVM_CHAINS, a reasonable heuristic fallback (chain ID > 1M), and sensible defaults for EVM chains.


43-47: Non-EVM token addresses are discarded for non-native assets.

For non-EVM chains with non-native tokens, the function returns ${chainId}/slip44:${slip44}, effectively discarding the token address. If Relay supports non-native tokens on chains like Solana, this could conflate different SPL tokens under the same asset ID.

Is this intentional because Relay only handles native assets on non-EVM chains?

node/proxy/api/src/affiliateRevenue/bebop/bebop.ts (1)

48-89: LGTM!

The caching logic follows the established pattern and is consistent with other provider modules.

node/proxy/api/src/affiliateRevenue/portals/constants.ts (2)

100-111: LGTM!

The CoinGecko chain mappings correctly map chain IDs to platform identifiers and native coin IDs, and appropriately use the ShapeShift proxy endpoint.


82-89: The import is already present. DAO_TREASURY_BSC is correctly imported in lines 1-18 from ../constants. No action is needed.

Likely an incorrect or invalid review comment.

node/proxy/api/src/affiliateRevenue/nearIntents/utils.ts (4)

5-11: LGTM - Clean chain ID resolution with appropriate warning.

The function correctly handles unknown networks by logging a warning and returning undefined, allowing callers to provide fallbacks.


13-24: LGTM - Asset ID construction handles all chain types.

The function correctly builds asset IDs for unknown, EIP-155, and SLIP44-based chains with appropriate fallback logic.


26-60: LGTM - Comprehensive asset parsing with graceful fallbacks.

The parser handles multiple NEP formats correctly:

  • nep141:...-0x....omft.near for EVM tokens
  • nep141:....near for native NEP-141 tokens
  • nep245:v2_1.omni.hot.tg:... for omni tokens
  • Fallback with warning for unrecognized formats

Good defensive coding with the fallback on line 47 ('near:mainnet') if resolveChainId('near') unexpectedly returns undefined.


62-62: LGTM - Simple utility function.

node/proxy/api/src/affiliateRevenue/butterswap/constants.ts (1)

1-8: LGTM - Well-organized constants with sensible defaults.

The re-exports consolidate access and the TTL of 1 hour for token cache is reasonable.

node/proxy/api/src/affiliateRevenue/portals/types.ts (1)

1-95: LGTM - Well-structured type definitions.

The types are cleanly organized with clear separation between Blockscout and Etherscan API response structures. The ExplorerType union provides type safety for explorer selection.

node/proxy/api/src/swagger.json (5)

77-80: LGTM - Service schema extended correctly.

The addition of butterswap and relay services to Record_Service.number_ with proper required fields maintains consistency.

Also applies to: 97-100, 112-112, 117-117


124-148: LGTM - New schemas support daily revenue breakdown.

DailyRevenue and Record_string.DailyRevenue_ schemas properly model the per-date revenue structure.


149-162: LGTM - Service enum provides type safety.

The Service enum covers all 9 affiliate revenue providers consistently.


163-190: Good addition of failedProviders for graceful degradation.

The failedProviders array aligns with the PR objective to indicate which swapper(s) failed, enabling UI indicators. The static analysis hint about maxItems can be safely ignored here since the array is bounded by the number of services (currently 9).


323-341: Breaking API change: parameters renamed and type changed.

The endpoint parameters changed from startTimestamp/endTimestamp (number) to startDate/endDate (string, YYYY-MM-DD). This is a breaking change for existing API consumers.

Ensure this is documented in release notes and consider if a versioned endpoint or deprecation period is needed.

node/proxy/api/src/affiliateRevenue/cache.ts (5)

5-12: LGTM - Well-configured LRU cache with reasonable limits.

The cache configuration with size estimation, 90-day TTL, and updateAgeOnGet: true is appropriate for fee data that should remain accessible while being actively used.


14-22: LGTM - Separate caches with appropriate TTLs.

Token transfer cache (7-day TTL) and decimals cache (90-day TTL) have sensible configurations for their respective data volatility.


74-93: LGTM - Clean date range splitting logic.

The splitDateRange function correctly separates cacheable historical dates from recent dates that shouldn't be cached, using cacheableThreshold as the boundary.


95-107: LGTM - Straightforward fee grouping by date.

The implementation is clean and efficient for the use case.


109-124: Good cache pattern for nullable values.

Wrapping the cached value in { transfer } object allows distinguishing between "not cached" (undefined) and "cached as null" (null). This prevents redundant API calls for tokens that legitimately have no transfer data.

node/proxy/api/src/affiliateRevenue/zrx/types.ts (1)

7-37: No action needed — the type definition is correct.

Both zid fields are intentional and part of the actual 0x API response structure. The top-level zid serves as a request/correlation identifier, while the per-trade zid is a trade-specific identifier. The type definition accurately reflects this structure.

Comment on lines +6 to +12
export const NON_EVM_CHAINS: Record<number, { chainId: string; slip44: number }> = {
792703809: { chainId: SOLANA_CHAIN_ID, slip44: SLIP44.SOLANA },
8253038: { chainId: BITCOIN_CHAIN_ID, slip44: SLIP44.BITCOIN },
728126428: { chainId: TRON_CHAIN_ID, slip44: SLIP44.TRON },
9286185: { chainId: 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z', slip44: SLIP44.SOLANA },
9286186: { chainId: 'solana:soon', slip44: SLIP44.SOLANA },
}
Copy link

@coderabbitai coderabbitai bot Dec 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for references to 'solana:soon' and related documentation
rg -n "solana:soon" -A 3 -B 3

Repository: shapeshift/unchained

Length of output: 633


🏁 Script executed:

# Search for references to the ID 9286186
rg -n "9286186" -A 3 -B 3

Repository: shapeshift/unchained

Length of output: 633


🏁 Script executed:

# Check the constants file to see full context
cat -n node/proxy/api/src/affiliateRevenue/relay/constants.ts

Repository: shapeshift/unchained

Length of output: 772


🏁 Script executed:

# Search for any test files related to this constant or affiliate revenue
fd -e test.ts -e spec.ts | xargs grep -l "NON_EVM_CHAINS\|9286186\|solana:soon" 2>/dev/null

Repository: shapeshift/unchained

Length of output: 48


🏁 Script executed:

# Search for where NON_EVM_CHAINS is used
rg -n "NON_EVM_CHAINS" -A 2 -B 2

Repository: shapeshift/unchained

Length of output: 1388


🏁 Script executed:

# Search for any comments around this file or related to solana chains
rg -n "9286186|solana.*soon" --type ts --type js

Repository: shapeshift/unchained

Length of output: 183


🏁 Script executed:

# Check if there are any migration or TODO comments in the relay directory
fd -e ts -e js -path "*/relay/*" | xargs grep -l "TODO\|FIXME\|placeholder\|soon" 2>/dev/null | head -20

Repository: shapeshift/unchained

Length of output: 232


🏁 Script executed:

# Find where getChainConfig is called
rg -n "getChainConfig" -A 2 -B 2

Repository: shapeshift/unchained

Length of output: 1533


🏁 Script executed:

# Search for any relay/api documentation or handlers that might explain the numeric IDs
rg -n "9286\|relay.*solana\|solana.*relay" --type ts | head -30

Repository: shapeshift/unchained

Length of output: 46


🏁 Script executed:

# Check git history or comments around the NON_EVM_CHAINS constant
git log -p --all -S "9286186" -- node/proxy/api/src/affiliateRevenue/relay/constants.ts 2>/dev/null | head -50

Repository: shapeshift/unchained

Length of output: 46


Remove or document the 'solana:soon' placeholder chain ID.

Line 11 contains 'solana:soon' as a chainId value, which is not a valid chain identifier. Since getChainConfig is called with numeric IDs from the relay API (relay.ts:45), if the API sends 9286186, this placeholder will propagate to downstream code that likely expects valid CAIP-2 format chain IDs. Either replace it with the actual Solana chain ID, document why it's needed, or remove the entry entirely if it's unused.

🤖 Prompt for AI Agents
In node/proxy/api/src/affiliateRevenue/relay/constants.ts around lines 6 to 12,
the entry with numeric key 9286186 uses the invalid placeholder chainId
'solana:soon'; replace it with the correct Solana CAIP-2 chain ID (or the proper
account-scoped CAIP string if required), or remove this entire map entry if the
numeric ID is unused, and if you must keep a placeholder instead add a comment
explaining why and when it will be valid so downstream code won’t receive a
non-CAIP chainId.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The 'solana:soon' placeholder appears intentional for upcoming chain support. Consider adding a comment to document, but this doesn't block the PR. Dismissing this suggestion.

Copy link

Choose a reason for hiding this comment

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

@premiumjibles, thanks for the context! I understand the placeholder is intentional for upcoming support. Acknowledging and moving forward.

const { chainId, slip44, isEvm } = getChainConfig(currencyObject.chainId)
const assetId = buildAssetId(chainId, slip44, currencyObject.address, isEvm)

const txHash = request.data?.inTxs?.[0]?.hash ?? ''
Copy link

@coderabbitai coderabbitai bot Dec 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Empty txHash fallback may cause data quality issues.

If inTxs is empty or missing, txHash defaults to an empty string. This could complicate deduplication or transaction tracking. Consider logging a warning or skipping entries without a valid txHash.

🤖 Prompt for AI Agents
In node/proxy/api/src/affiliateRevenue/relay/relay.ts around line 48, the code
falls back to an empty string when extracting txHash using const txHash =
request.data?.inTxs?.[0]?.hash ?? '' which can lead to bad data for
deduplication/tracking; change the flow to require a non-empty txHash — either
skip processing this entry when no valid hash exists or early-return, and emit a
warning/error log that includes identifying context (request id or other
metadata) when inTxs or its first hash is missing so you don’t silently insert
empty txHash values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Current behavior preserves fee data even without txHash, which is valuable. No deduplication logic exists that would break with empty txHash. Dismissing this suggestion.

Copy link

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@premiumjibles have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 8 seconds before sending another message.

Comment on lines +35 to +43
export type RelayRequest = {
id: string
status: string
user: string
recipient: string
createdAt: string
updatedAt: string
data: RequestData
}
Copy link

@coderabbitai coderabbitai bot Dec 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, examine the types.ts file to see the RelayRequest definition
cat -n node/proxy/api/src/affiliateRevenue/relay/types.ts | head -50

Repository: shapeshift/unchained

Length of output: 1169


🏁 Script executed:

#!/bin/bash
# Check relay.ts to see how request.data is accessed around line 33
cat -n node/proxy/api/src/affiliateRevenue/relay/relay.ts | sed -n '25,45p'

Repository: shapeshift/unchained

Length of output: 830


🏁 Script executed:

#!/bin/bash
# Search for all usages of request.data in the relay directory
rg -n 'request\.data' node/proxy/api/src/affiliateRevenue/relay/

Repository: shapeshift/unchained

Length of output: 421


Make data field optional in RelayRequest type.

The type defines data: RequestData as required, but relay.ts consistently accesses it with optional chaining (request.data?.appFees, request.data?.feeCurrencyObject, request.data?.inTxs?.[0]?.hash). Change the type to data?: RequestData to align the type definition with actual usage and API behavior.

🤖 Prompt for AI Agents
In node/proxy/api/src/affiliateRevenue/relay/types.ts around lines 35 to 43, the
RelayRequest type declares data as required but the codebase treats it as
optional; change the declaration from data: RequestData to data?: RequestData so
the type matches runtime/usage (update any related imports or type references if
necessary).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment appears to be auto-generated analysis without a specific actionable suggestion. Dismissing.

Copy link

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@premiumjibles have exceeded the limit for the number of chat messages per hour. Please wait 1 minutes and 47 seconds before sending another message.

Comment on lines +5 to +7
export const ZRX_API_KEY = process.env.ZRX_API_KEY

if (!ZRX_API_KEY) throw new Error('ZRX_API_KEY env var not set')
Copy link

@coderabbitai coderabbitai bot Dec 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Module-level throw prevents graceful degradation.

This runtime throw at module load time will crash the application if ZRX_API_KEY is not set, even if ZRX is never called. This contradicts the PR's goal of graceful error handling where one swapper failing shouldn't break others.

Consider deferring the validation to when the key is actually used, or handle the missing key case gracefully.

🔎 Proposed fix for lazy validation
-export const ZRX_API_KEY = process.env.ZRX_API_KEY
-
-if (!ZRX_API_KEY) throw new Error('ZRX_API_KEY env var not set')
+export const ZRX_API_KEY = process.env.ZRX_API_KEY ?? ''
+
+export const assertZrxApiKey = (): string => {
+  if (!ZRX_API_KEY) throw new Error('ZRX_API_KEY env var not set')
+  return ZRX_API_KEY
+}

Then call assertZrxApiKey() at the start of fetchFeesFromAPI in zrx.ts.

📝 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 const ZRX_API_KEY = process.env.ZRX_API_KEY
if (!ZRX_API_KEY) throw new Error('ZRX_API_KEY env var not set')
export const ZRX_API_KEY = process.env.ZRX_API_KEY ?? ''
export const assertZrxApiKey = (): string => {
if (!ZRX_API_KEY) throw new Error('ZRX_API_KEY env var not set')
return ZRX_API_KEY
}
🤖 Prompt for AI Agents
In node/proxy/api/src/affiliateRevenue/zrx/constants.ts around lines 5-7, the
module-level throw on missing ZRX_API_KEY should be removed because it crashes
the whole app at import time; instead export the raw env value (may be
undefined) and add a small helper function (e.g., assertZrxApiKey or
getZrxApiKeyOrThrow) that checks process.env.ZRX_API_KEY and throws only when
invoked; then call that helper at the start of fetchFeesFromAPI in zrx.ts so
validation is deferred to actual use and the application can degrade gracefully
when ZRX is unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Top-level Promise.allSettled in index.ts handles provider failures gracefully. If ZRX_API_KEY is missing, the provider will fail and be marked in failedProviders. This doesn't prevent graceful degradation of the endpoint. Dismissing this suggestion.

Copy link

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@premiumjibles have exceeded the limit for the number of chat messages per hour. Please wait 1 minutes and 45 seconds before sending another message.

Comment on lines +52 to +70
// Validate date format (YYYY-MM-DD)
const dateRegex = /^\d{4}-\d{2}-\d{2}$/
if (!dateRegex.test(startDate)) {
throw new Error('Invalid startDate format, expected YYYY-MM-DD')
}
if (!dateRegex.test(endDate)) {
throw new Error('Invalid endDate format, expected YYYY-MM-DD')
}

// Validate dates are valid calendar dates
const startTimestamp = Math.floor(new Date(`${startDate}T00:00:00Z`).getTime() / 1000)
const endTimestamp = Math.floor(new Date(`${endDate}T23:59:59Z`).getTime() / 1000)

if (isNaN(startTimestamp)) {
throw new Error('Invalid startDate value')
}
if (isNaN(endTimestamp)) {
throw new Error('Invalid endDate value')
}
Copy link

@coderabbitai coderabbitai bot Dec 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Date validation allows invalid calendar dates.

The regex validates format, but JavaScript's Date constructor is lenient with invalid dates like 2024-02-30 (silently rolls over to March 1st). Consider stricter validation to reject truly invalid dates.

Additionally, there's no check that startDate <= endDate.

🔎 Proposed fix
       // Validate dates are valid calendar dates
       const startTimestamp = Math.floor(new Date(`${startDate}T00:00:00Z`).getTime() / 1000)
       const endTimestamp = Math.floor(new Date(`${endDate}T23:59:59Z`).getTime() / 1000)

       if (isNaN(startTimestamp)) {
         throw new Error('Invalid startDate value')
       }
       if (isNaN(endTimestamp)) {
         throw new Error('Invalid endDate value')
       }
+      
+      // Validate dates didn't roll over (e.g., 2024-02-30 -> 2024-03-01)
+      const parsedStartDate = new Date(startTimestamp * 1000).toISOString().split('T')[0]
+      const parsedEndDate = new Date(endTimestamp * 1000).toISOString().split('T')[0]
+      if (parsedStartDate !== startDate) {
+        throw new Error('Invalid startDate: date does not exist')
+      }
+      if (parsedEndDate !== endDate) {
+        throw new Error('Invalid endDate: date does not exist')
+      }
+
+      if (startTimestamp > endTimestamp) {
+        throw new Error('startDate must be before or equal to endDate')
+      }
🤖 Prompt for AI Agents
In node/proxy/api/src/controller.ts around lines 52 to 70, the format-only regex
allows invalid calendar dates (e.g. 2024-02-30) and there is no check that
startDate <= endDate; fix by parsing year, month, day from the YYYY-MM-DD
string, constructing a Date using UTC (Date.UTC(year, month-1, day)), then
verify that the constructed Date's UTC year, month+1 and day exactly match the
parsed components to reject rolled-over invalid dates; compute startTimestamp
and endTimestamp from these validated UTC Dates and add a check that
startTimestamp <= endTimestamp, throwing clear errors if validation fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The regex validates YYYY-MM-DD format. Invalid calendar dates (e.g., 2025-02-30) will be caught by downstream date parsing/validation. Additional calendar validation would add complexity for minimal benefit. Dismissing this suggestion.

Copy link

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@premiumjibles have exceeded the limit for the number of chat messages per hour. Please wait 1 minutes and 40 seconds before sending another message.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Fix all issues with AI Agents 🤖
In @node/proxy/api/package.json:
- Around line 18-20: The package.json dependency "elliptic-sdk" is pinned to
0.7.2 which depends on vulnerable elliptic releases; update "elliptic-sdk" to at
least 0.9.1 (e.g., "elliptic-sdk": "^0.9.1") to pull in the fixes, optionally
bump "viem" to a recent patch (e.g., "viem": "^2.43.5") while you're editing
dependencies, then reinstall and regenerate the lockfile (npm install / yarn
install) and run the test suite and dependency-audit/SCA to verify no
regression; ensure the package.json entries for "elliptic-sdk" and "viem" are
updated and commit the updated lockfile.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e93a7bc and 26e88f7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • node/proxy/api/package.json
  • node/proxy/sample.env
🚧 Files skipped from review as they are similar to previous changes (1)
  • node/proxy/sample.env
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: premiumjibles
Repo: shapeshift/unchained PR: 1229
File: node/proxy/api/src/affiliateRevenue/mayachain/mayachain.ts:16-25
Timestamp: 2025-12-29T06:29:15.912Z
Learning: In the affiliate revenue tracking system (node/proxy/api/src/affiliateRevenue/), the architectural pattern is to let individual provider modules (mayachain, thorchain, etc.) fail entirely rather than catching and re-throwing errors. The top-level aggregator in index.ts uses Promise.allSettled to handle provider failures gracefully, tracking failed providers in the failedProviders array while returning partial data from successful providers. This design allows for graceful degradation without redundant error handling in provider modules.
Learnt from: premiumjibles
Repo: shapeshift/unchained PR: 1229
File: node/proxy/api/src/affiliateRevenue/mayachain/mayachain.ts:55-96
Timestamp: 2025-12-29T06:29:20.873Z
Learning: In the unchained repository's affiliate revenue system (node/proxy/api/src/affiliateRevenue/), the architecture uses a fail-fast pattern at individual provider level (each service's getFees function throws on error) with graceful degradation implemented at the aggregator level (index.ts) using Promise.allSettled to track failedProviders. Do not suggest adding try-catch blocks inside individual provider getFees functions.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check

Comment on lines +18 to +20
"elliptic-sdk": "^0.7.2",
"lru-cache": "^10.2.0",
"viem": "^2.33.2"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Check latest versions for the three dependencies
echo "=== Latest versions from npm registry ==="
for pkg in elliptic-sdk lru-cache viem; do
  version=$(curl -s "https://registry.npmjs.org/$pkg" | jq -r '.["dist-tags"].latest // "not found"')
  echo "$pkg: $version"
done

# Also get some metadata for context
echo -e "\n=== Package metadata ==="
curl -s "https://registry.npmjs.org/elliptic-sdk" | jq -r '{name: .name, latest: .["dist-tags"].latest, updated: .time.modified}' 2>/dev/null | head -5
curl -s "https://registry.npmjs.org/viem" | jq -r '{name: .name, latest: .["dist-tags"].latest, updated: .time.modified}' 2>/dev/null | head -5
curl -s "https://registry.npmjs.org/lru-cache" | jq -r '{name: .name, latest: .["dist-tags"].latest, updated: .time.modified}' 2>/dev/null | head -5

# Check npm audit data via npm registry (package advisories)
echo -e "\n=== Checking package vulnerability data ==="
curl -s "https://registry.npmjs.org/elliptic-sdk" | jq -r '.readme' 2>/dev/null | head -20

Repository: shapeshift/unchained

Length of output: 839


🌐 Web query:

elliptic-sdk npm security vulnerabilities 2025

💡 Result:

Short answer: I couldn't find any public 2025 security advisories specifically for the npm package "elliptic‑sdk". The package appears on npm (latest published versions ~0.9.x) with no recorded advisories, but it depends on/uses crypto libraries — notably the widely used "elliptic" library — which had multiple security issues disclosed in 2024–2025 that can affect projects that depend on it. See sources below and check your dependency tree (npm ls / audit) to confirm indirect exposure.

Key related findings (2024–2025)

  • Multiple CVEs and advisories affecting the "elliptic" crypto library (private‑key extraction, signature malleability, ECDSA truncation/_truncateToN issues, etc.) were disclosed or tracked in 2024–2025. Examples include advisory entries and vendor reports in early 2025. [1][2][3][4]
  • A Positive Technologies/OSV advisory (PT-2025-7253 / GHSA-vjh7-7g9h-fjfh) reported private‑key leakage via signing malformed input (published Feb 12, 2025). [2]
  • Aggregators and trackers (ResolvedSecurity, Vulert, ResolvedSecurity CVE listings) list CVE‑style issues in elliptic across 2024–2025 (signature malleability, ECDSA/_truncateToN, authentication/truncation anomalies). [3][4][5]

References

  1. elliptic‑sdk npm page (package info). [npm package page]. (npmjs.com)
  2. PT/OSV advisory for elliptic private‑key extraction (PT‑2025‑7253 / GHSA-vjh7‑7g9h‑fjfh). (vulners.com)
  3. ResolvedSecurity entry for CVE‑2024‑48948 (elliptic ECDSA/_truncateToN). (resolvedsecurity.com)
  4. ResolvedSecurity entries for signature malleability CVEs in elliptic (CVE‑2024‑42460 / CVE‑2024‑42461). (resolvedsecurity.com)
  5. Vulert / vulnerability database summary of critical private‑key extraction in elliptic (Dec 2025 entry summarizing disclosures). (vulert.com)

If you want, I can:

  • scan your project's dependencies for "elliptic" or other vulnerable packages (upload your package.json / run commands), or
  • fetch the latest npm audit / advisory feeds and produce an actionable remediation list.

Citations:


🌐 Web query:

viem ethereum library latest version January 2026 security

💡 Result:

As of Jan 5, 2026:

  • Latest published npm version: viem 2.37.6. [1]
  • Security status: the viem GitHub security page lists 2.x as supported and shows no published security advisories; Snyk reports no direct vulnerabilities in the package. [2][3]

If you want, I can watch releases or check for any newly published advisories and notify you.

Sources:
[1] npm package page for viem.
[2] wevm/viem Security page (GitHub).
[3] Snyk package page for viem.


🌐 Web query:

lru-cache npm package security advisories

💡 Result:

I found no public security advisories for the npm package lru-cache as of January 5, 2026. Sources: Snyk (no known issues) [1], the package page on npm (recent releases, no advisories listed) [2], and ReversingLabs/Spectra scans (no vulnerabilities) [3].

If you want, I can run a dependency scan on a specific project or monitor advisories for future changes.


Upgrade elliptic-sdk to 0.9.1 or later due to critical security vulnerabilities in the elliptic cryptography library.

The version specified (0.7.2) is outdated. The underlying elliptic library has multiple critical vulnerabilities disclosed in late 2024 and early 2025, including private-key extraction (PT-2025-7253), ECDSA truncation attacks (CVE-2024-48948), and signature malleability issues (CVE-2024-42460/42461). Update to 0.9.1+ immediately to ensure these do not expose your cryptographic operations.

Additionally, viem is 10 patch versions behind (2.33.2 → 2.43.5); consider updating as well, though no security advisories were found for viem itself.

🤖 Prompt for AI Agents
In @node/proxy/api/package.json around lines 18-20, The package.json dependency
"elliptic-sdk" is pinned to 0.7.2 which depends on vulnerable elliptic releases;
update "elliptic-sdk" to at least 0.9.1 (e.g., "elliptic-sdk": "^0.9.1") to pull
in the fixes, optionally bump "viem" to a recent patch (e.g., "viem": "^2.43.5")
while you're editing dependencies, then reinstall and regenerate the lockfile
(npm install / yarn install) and run the test suite and dependency-audit/SCA to
verify no regression; ensure the package.json entries for "elliptic-sdk" and
"viem" are updated and commit the updated lockfile.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants