Skip to content

feat: allow quotes that take longer than 5 seconds to keep going if we get nothing else - #10372

Merged
premiumjibles merged 3 commits into
developfrom
10371_let_them_live
Aug 27, 2025
Merged

feat: allow quotes that take longer than 5 seconds to keep going if we get nothing else#10372
premiumjibles merged 3 commits into
developfrom
10371_let_them_live

Conversation

@premiumjibles

@premiumjibles premiumjibles commented Aug 27, 2025

Copy link
Copy Markdown
Contributor

Description

Let's quotes through in the swapper even if they take longer than 5 seconds if we have no other quotes

Issue (if applicable)

closes #10371

Risk

Medium-high risk, code is fairly surgical and should only kick in on the edge case where there's a timeout and no quote results but this is still important code so marking as medium-high but it's potentially high.

High Risk PRs Require 2 approvals

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Test a variety of swap pairs. Ones with plenty of swappers available and ones with only a few.
  • I found it easiest to test this on swaps that only have thorchain available as it's fairly slow. E.g. Optimism -> DOGE
  • You should basically never end up in a situation where you get no quotes AND in the unavailable quotes section you see that some swappers just timed out

Engineering

Easier to test this if you monkey patch BULK_FETCH_RATE_TIMEOUT_MS to be lower

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

Easiest to test this on quotes that only have thor swaps. But Thor was down at the time of testing so I lowered the timeout all the way down to 500ms. Which on my internet would make all quotes fail. Notice it still works because no quotes came through and it's resorting to no timeout.

https://jam.dev/c/7ab7124a-f0e0-4073-8b64-36e9230e0456

Summary by CodeRabbit

  • New Features

    • Exposes a fallback path for rate fetching so timed-out providers can still return quotes.
    • Improved timeout handling to surface original results when available.
  • Bug Fixes

    • Fewer missing quotes from timeouts; more consistent quote availability via automatic fallback usage.
  • Refactor

    • Reworked bulk rate processing to integrate fallback data while preserving overall behavior.
  • Breaking Changes

    • Rate result objects now include an optional fallback field in the public response.

@premiumjibles
premiumjibles requested a review from a team as a code owner August 27, 2025 00:56
@coderabbitai

coderabbitai Bot commented Aug 27, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds timeoutMonadicWithOriginal and threads an optional fallback Promise through rate results; swapper code uses the timed/original pair to return primary or fallback quotes, and the API consumes fallbacks when all primary results are missing due to timeouts. Types updated to include fallback.

Changes

Cohort / File(s) Summary of Changes
Timeout utilities
packages/utils/src/timeout.ts
Added timeoutMonadicWithOriginal which returns { timed, original }: timed races the input monadic promise against a timeout error, original preserves the untouched promise.
Swapper core: rate fetching
packages/swapper/src/swapper.ts
Replaced prior timeout path with timeoutMonadicWithOriginal; destructures { timed, original }, awaits timed for the quote and attaches fallback (from original) to returned RateResult alongside swapperName.
Types for rate results
packages/swapper/src/types.ts
Extended RateResult with optional fallback?: Promise<Result<TradeRate[], SwapErrorRight>> so callers can await late results when needed.
API aggregation and fallback usage
src/state/apis/swapper/swapperApi.ts
Collects unprocessed swapper results, detects when all primary quotes are absent and some timed out, then uses fallback for timed-out swappers to produce quotes instead of discarding late results; aggregates quotes by swapper name.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor UI
  participant API as swapperApi.getTradeRates
  participant Swapper as Swapper.getTradeRates
  participant Utils as timeoutMonadicWithOriginal

  UI->>API: Request batch trade rates
  loop per swapper
    API->>Swapper: getTradeRates()
    Swapper->>Utils: timeoutMonadicWithOriginal(promise, timeoutMs, TimeoutError)
    Utils-->>Swapper: { timed, original }
    Swapper-->>API: RateResult { Ok/Err, swapperName, fallback?: original }
  end

  API->>API: Inspect unprocessed results
  alt all primary results missing && any timed-out
    API->>API: Await fallback for timed-out swappers
    API->>API: Process late quotes from fallback
  else
    API->>API: Process quotes from timed results
  end

  API-->>UI: Aggregated quotes by swapperName
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
Don’t disregard quotes after 5s if none are found (#10371)

Possibly related PRs

Suggested labels

high risk

Suggested reviewers

  • NeOMakinG
  • gomesalexandre

Poem

I waited five ticks—then five more, ears bright,
A rabbit kept the lantern through the night. 🐇
When clocks would drop the quote into the dark,
My fallback hop retrieved the missing spark. ✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10371_let_them_live

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
🪧 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@premiumjibles
premiumjibles marked this pull request as draft August 27, 2025 00:56
Comment thread packages/utils/src/timeout.ts Outdated
Comment thread src/state/apis/swapper/swapperApi.ts
Comment thread src/state/apis/swapper/swapperApi.ts
@premiumjibles
premiumjibles marked this pull request as ready for review August 27, 2025 01:04
@premiumjibles premiumjibles changed the title feat: Allow quotes that take longer than 5 seconds to keep going if we get nothing else feat: allow quotes that take longer than 5 seconds to keep going if we get nothing else Aug 27, 2025
Comment thread packages/swapper/src/swapper.ts Outdated
@premiumjibles
premiumjibles marked this pull request as draft August 27, 2025 01:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/utils/src/timeout.ts (1)

34-50: Document invariants for fallback (non-cancelable, expected not to reject)

Add TSDoc clarifying that fallback is the original non-cancelable promise and is expected to resolve to a monadic Result (never reject). This matches the intent noted earlier.

 export const timeoutMonadicWithFallback = <Left, Right>(
+  /**
+   * Races `promise` against a timeout, returning:
+   * - `result`: the raced Promise<Result<Ok, Err>> that Err-times out after `timeoutMs`
+   * - `fallback`: the original, non-cancelable `promise` for late consumption (must resolve to Result and not reject)
+   *
+   * Note: consumers should either await `fallback` when needed or attach a no-op catch upstream to avoid unhandled rejections
+   * if a non-monadic implementation accidentally rejects.
+   */
   promise: Promise<Result<Left, Right>>,
   timeoutMs: number,
   timeoutRight: Right,
 ): { result: Promise<Result<Left, Right>>; fallback: Promise<Result<Left, Right>> } => {
src/state/apis/swapper/swapperApi.ts (1)

153-167: Two-phase fetch/process makes the fallback decision possible

Splitting into unprocessedSwapperResults then processing is a pragmatic trade-off; measured overhead is negligible.

🧹 Nitpick comments (5)
packages/utils/src/timeout.ts (1)

34-50: Reduce duplication: build on timeoutMonadic instead of re-implementing the race

Reuse the existing timeoutMonadic for the result branch to keep behavior consistent and DRY.

Apply:

 export const timeoutMonadicWithFallback = <Left, Right>(
   promise: Promise<Result<Left, Right>>,
   timeoutMs: number,
   timeoutRight: Right,
 ): { result: Promise<Result<Left, Right>>; fallback: Promise<Result<Left, Right>> } => {
-  return {
-    result: Promise.race([
-      promise,
-      new Promise<Result<Left, Right>>(resolve =>
-        setTimeout(() => {
-          resolve(Err(timeoutRight) as Result<Left, Right>)
-        }, timeoutMs),
-      ),
-    ]),
-    fallback: promise,
-  }
+  return {
+    result: timeoutMonadic<Left, Right>(promise, timeoutMs, timeoutRight),
+    fallback: promise,
+  }
 }
packages/swapper/src/swapper.ts (2)

62-69: Guard against potential unhandled rejections on the fallback path

If any swapper accidentally rejects (anti-pattern), the unawaited fallback can trigger an unhandled rejection. Attach a no-op catch to suppress noise while preserving the original promise semantics for downstream consumers.

-    const { result, fallback } = timeoutMonadicWithFallback<TradeRate[], SwapErrorRight>(
+    const { result, fallback } = timeoutMonadicWithFallback<TradeRate[], SwapErrorRight>(
       swapper.getTradeRate(getTradeRateInput, deps),
       quoteTimeoutMs,
       makeSwapErrorRight({
         code: TradeQuoteError.Timeout,
         message: `quote timed out after ${quoteTimeoutMs / 1000}s`,
       }),
     )
+    // Ensure no unhandled rejection if fallback isn't consumed downstream
+    void fallback.catch(() => undefined)

71-76: Name the variable for what it is (rateResult), not quote

Minor clarity tweak to avoid confusing rate vs quote terminology.

-    const quote = await result
+    const rateResult = await result

     return {
-      ...quote,
+      ...rateResult,
       fallback,
       swapperName,
     }
packages/swapper/src/types.ts (1)

615-618: Clarify fallback semantics on RateResult

Add a short doc to ensure future consumers understand when and how to consume fallback.

 export type RateResult = Result<TradeRate[], SwapErrorRight> & {
   swapperName: SwapperName
-  fallback?: Promise<Result<TradeRate[], SwapErrorRight>>
+  /**
+   * Original, non-cancelable promise for late rates when initial fetch timed out.
+   * Expected to resolve to a monadic Result (do not reject).
+   * Consumers should only await when no other quotes are available.
+   */
+  fallback?: Promise<Result<TradeRate[], SwapErrorRight>>
 }
src/state/apis/swapper/swapperApi.ts (1)

183-197: Fallback await path is correct; consider making the predicate a named helper for readability

No functional change; just readability if you touch this again.

-            const rateResultWithFallback =
-              noQuotes && hasTimeoutQuote && isTimeout && rateResult?.fallback
-                ? { ...(await rateResult.fallback), swapperName }
-                : rateResult
+            const shouldUseFallback =
+              noQuotes && hasTimeoutQuote && isTimeout && Boolean(rateResult?.fallback)
+            const rateResultWithFallback = shouldUseFallback
+              ? { ...(await rateResult!.fallback!), swapperName }
+              : rateResult
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 20179e9 and c00f851.

📒 Files selected for processing (4)
  • packages/swapper/src/swapper.ts (3 hunks)
  • packages/swapper/src/types.ts (1 hunks)
  • packages/utils/src/timeout.ts (1 hunks)
  • src/state/apis/swapper/swapperApi.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
packages/swapper/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)

packages/swapper/**/*.ts: Use TypeScript with explicit types (e.g., SupportedChainIds) in all swapper-related files.
Use camelCase for variables and functions, PascalCase for types and interfaces, and kebab-case for filenames in swapper-related files.

Files:

  • packages/swapper/src/types.ts
  • packages/swapper/src/swapper.ts
packages/swapper/src/{constants,types}.ts

📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)

Register new swappers in packages/swapper/src/constants.ts and add them to the SwapperName enum in packages/swapper/src/types.ts.

Files:

  • packages/swapper/src/types.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • packages/swapper/src/types.ts
  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
**/swapper/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/swapper/**/*.{ts,tsx}: AVOID throwing within swapper API implementations; return Err() instead. UI layers may still throw (caught by React error boundaries).
ALWAYS use makeSwapErrorRight for swapper errors
ALWAYS use TradeQuoteError enum for error codes in swapper errors
ALWAYS provide detailed error information in swapper errors

Files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • packages/swapper/src/types.ts
  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • packages/swapper/src/types.ts
  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use timeoutMonadic for API calls
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use TradeQuoteError enum for error codes in swapper errors

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) in all swapper-related files.

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/{constants,types}.ts : Register new swappers in packages/swapper/src/constants.ts and add them to the SwapperName enum in packages/swapper/src/types.ts.

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Avoid side effects in swap logic within swapper implementation files.

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use makeSwapErrorRight for swapper errors

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Include comments explaining swap logic in swapper implementation files.

Applied to files:

  • packages/swapper/src/types.ts
  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use Result<T, E> pattern for error handling in swappers and APIs

Applied to files:

  • packages/swapper/src/types.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use timeoutMonadic for API calls

Applied to files:

  • packages/utils/src/timeout.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : Missing timeout handling is an anti-pattern

Applied to files:

  • packages/utils/src/timeout.ts
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
PR: shapeshift/web#10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Leverage shared utilities (e.g., executeEvmTransaction, checkEvmSwapStatus) in swapper implementations when applicable.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS provide detailed error information in swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
  • packages/swapper/src/swapper.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : All swappers must conform to the Swapper and SwapperApi interfaces defined in packages/swapper/src/types.ts.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/index.ts : Export unique functions/types from packages/swapper/src/index.ts if needed.

Applied to files:

  • packages/swapper/src/swapper.ts
🧬 Code graph analysis (2)
src/state/apis/swapper/swapperApi.ts (2)
src/state/apis/swapper/types.ts (1)
  • TradeQuoteError (39-39)
src/state/apis/swapper/helpers/swapperApiHelpers.ts (1)
  • processQuoteResultWithRatios (56-86)
packages/swapper/src/swapper.ts (2)
packages/utils/src/timeout.ts (1)
  • timeoutMonadicWithFallback (34-50)
packages/swapper/src/types.ts (2)
  • TradeRate (450-454)
  • SwapErrorRight (82-88)
🔇 Additional comments (4)
packages/swapper/src/swapper.ts (1)

31-41: Monadic timeout + i18n-ready error code looks good

Timeout handling uses monadic Result and TradeQuoteError.Timeout with context in the message. Aligned with error-handling guidelines.

src/state/apis/swapper/swapperApi.ts (3)

4-4: Importing TradeQuoteError here is appropriate

Keeps error-code checks centralized and avoids stringly-typed comparisons.


199-203: Processing with ratios on the (possibly) fallback-augmented result is spot on

This feeds downstream quote creation uniformly regardless of timeout fallback.


169-175: No direct Ok([]) in any swapper—empty/no-route always Err

A search across all packages/swapper/src/swappers for literal Ok([]) returns no matches, and every swapping implementation either:

  • Returns Err(...) on missing routes or failures (e.g. network errors, no-route found), or
  • Builds an array by pushing at least one element before returning Ok(...)

Thus an Ok([]) case cannot arise, and the fallback logic in noQuotes will not be inadvertently skipped.

@premiumjibles
premiumjibles marked this pull request as ready for review August 27, 2025 01:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/utils/src/timeout.ts (1)

34-50: Clarify generics/naming and document contract.

  • The Right parameter name paired with Err(timeoutRight) is counterintuitive. Consider <Ok, ErrT> with timeoutErr: ErrT, or add TSDoc clarifying “Right = error”.
  • Add a brief TSDoc stating the input promise is expected to resolve to Result (not reject). If callers may pass rejecting promises, note that unhandled rejections can occur when the timeout wins.

Here’s a naming/doc pass:

-export const timeoutMonadicWithFallback = <Left, Right>(
-  promise: Promise<Result<Left, Right>>,
-  timeoutMs: number,
-  timeoutRight: Right,
-): { result: Promise<Result<Left, Right>>; fallback: Promise<Result<Left, Right>> } => {
+/**
+ * Races a monadic Result promise against a timeout. On timeout, returns Err(timeoutErr).
+ * Also returns the original promise as `fallback` for optional late consumption.
+ * NOTE: Promise is expected not to reject; it should resolve to Result<Ok, ErrT>.
+ */
+export const timeoutMonadicWithFallback = <Ok, ErrT>(
+  promise: Promise<Result<Ok, ErrT>>,
+  timeoutMs: number,
+  timeoutErr: ErrT,
+): { result: Promise<Result<Ok, ErrT>>; fallback: Promise<Result<Ok, ErrT>> } => {
   return {
     result: Promise.race([
       promise,
-      new Promise<Result<Left, Right>>(resolve =>
+      new Promise<Result<Ok, ErrT>>(resolve =>
         setTimeout(() => {
-          resolve(Err(timeoutRight) as Result<Left, Right>)
+          resolve(Err(timeoutErr) as Result<Ok, ErrT>)
         }, timeoutMs),
       ),
     ]),
     fallback: promise,
   }
 }
src/state/apis/swapper/swapperApi.ts (2)

183-198: Return shape inconsistency; prefer consistent payload to simplify consumers.

Returning { data: {} } from the inner mapper diverges from the { swapperName, quotes } shape and forces downstream guards. Return { swapperName, quotes: [] } instead for uniformity.

- if (promiseResult.status !== 'fulfilled') return { data: {} }
+ if (promiseResult.status !== 'fulfilled') return { swapperName: undefined as unknown as SwapperName, quotes: [] }
  const { swapperName, rateResult } = promiseResult.value
  ...
- if (rateResultWithFallback === undefined) {
-   return { data: {} }
- }
+ if (rateResultWithFallback === undefined) {
+   return { swapperName, quotes: [] }
+ }

Optionally rename promiseResultsettledResult for clarity.


199-203: Processing with fallback-fed RateResult is correct. Consider avoiding second allSettled for minor perf/clarity.

You can map over unprocessedSwapperResults and await Promise.all(...) since the inner mapper already handles per-item errors. Net effect is simpler control flow.

If desired, I can provide a small refactor PR.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 c00f851 and 3be96fa.

📒 Files selected for processing (4)
  • packages/swapper/src/swapper.ts (3 hunks)
  • packages/swapper/src/types.ts (1 hunks)
  • packages/utils/src/timeout.ts (1 hunks)
  • src/state/apis/swapper/swapperApi.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/swapper/src/types.ts
  • packages/swapper/src/swapper.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • packages/utils/src/timeout.ts
  • src/state/apis/swapper/swapperApi.ts
**/swapper/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/swapper/**/*.{ts,tsx}: AVOID throwing within swapper API implementations; return Err() instead. UI layers may still throw (caught by React error boundaries).
ALWAYS use makeSwapErrorRight for swapper errors
ALWAYS use TradeQuoteError enum for error codes in swapper errors
ALWAYS provide detailed error information in swapper errors

Files:

  • src/state/apis/swapper/swapperApi.ts
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use timeoutMonadic for API calls
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use timeoutMonadic for API calls

Applied to files:

  • packages/utils/src/timeout.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : Missing timeout handling is an anti-pattern

Applied to files:

  • packages/utils/src/timeout.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use TradeQuoteError enum for error codes in swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Avoid side effects in swap logic within swapper implementation files.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Include comments explaining swap logic in swapper implementation files.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
PR: shapeshift/web#10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use makeSwapErrorRight for swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS provide detailed error information in swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Leverage shared utilities (e.g., executeEvmTransaction, checkEvmSwapStatus) in swapper implementations when applicable.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) in all swapper-related files.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/{constants,types}.ts : Register new swappers in packages/swapper/src/constants.ts and add them to the SwapperName enum in packages/swapper/src/types.ts.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Validate inputs and log errors for debugging in swapper implementations.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
🧬 Code graph analysis (1)
src/state/apis/swapper/swapperApi.ts (2)
src/state/apis/swapper/types.ts (1)
  • TradeQuoteError (39-39)
src/state/apis/swapper/helpers/swapperApiHelpers.ts (1)
  • processQuoteResultWithRatios (56-86)
⏰ 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: Install and Cache
🔇 Additional comments (4)
packages/utils/src/timeout.ts (1)

34-50: Solid utility addition; matches monadic timeout behavior while exposing a fallback.

The shape { result, fallback } is appropriate and minimally invasive.

src/state/apis/swapper/swapperApi.ts (3)

4-4: Correct import for Timeout detection.

Using TradeQuoteError to discriminate timeouts is the right approach.


153-168: Two-phase fetch (gather → process) enables clean fallback semantics.

Collecting raw results before processing makes the “no quotes + has timeouts” check possible with negligible overhead.


176-182: Timeout detection LGTM.

Accurately scopes fallback to when at least one timeout occurred.

Comment thread src/state/apis/swapper/swapperApi.ts

@0xApotheosis 0xApotheosis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One nitpick on naming, and possibly one coderabbit comment to action - otherwise looking good. Modified BULK_FETCH_RATE_TIMEOUT_MS to test the way results are handled, looking good.

Comment thread packages/utils/src/timeout.ts Outdated
Comment thread src/state/apis/swapper/swapperApi.ts
@premiumjibles

premiumjibles commented Aug 27, 2025

Copy link
Copy Markdown
Contributor Author

@0xApotheosis actioned both here. Agree the renaming is clearer, i've never been a huge fan of "left" and "right" naming 😆 . 5322561

@premiumjibles
premiumjibles enabled auto-merge (squash) August 27, 2025 21:38
@premiumjibles
premiumjibles merged commit ccd36f9 into develop Aug 27, 2025
3 of 4 checks passed
@premiumjibles
premiumjibles deleted the 10371_let_them_live branch August 27, 2025 21:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/state/apis/swapper/swapperApi.ts (1)

169-176: Fix confirmed: Ok([]) now counts as “no quotes”.

This closes the fallback suppression edge case. Nice.

🧹 Nitpick comments (2)
src/state/apis/swapper/swapperApi.ts (2)

4-4: Ensure TradeQuoteError is a runtime enum (not a type) and avoid name collision.

We use TradeQuoteError.Timeout as a runtime value below. Please confirm @shapeshiftoss/swapper exports it as an enum/value. If there’s any collision with local TradeQuoteError types, consider aliasing to make intent explicit.

Example alias (only if needed):

-import { getTradeQuotes, getTradeRates, TradeQuoteError } from '@shapeshiftoss/swapper'
+import { getTradeQuotes, getTradeRates, TradeQuoteError as SwapperTradeQuoteError } from '@shapeshiftoss/swapper'

And then use SwapperTradeQuoteError.Timeout at the call sites.


184-195: Avoid unbounded waits on fallback; guard with try/catch.

Awaiting the original (fallback) promise can hang indefinitely, stalling RTK Query resolution when all swappers time out. Add a try/catch so a failing fallback doesn’t turn this branch into a rejected promise, and consider capping the fallback wait (e.g., 20–30s) to prevent indefinite hangs.

Apply this minimal safety net within the current block:

-            const isTimeout =
-              rateResult?.isErr() && rateResult.unwrapErr().code === TradeQuoteError.Timeout
-            const rateResultWithFallback =
-              noQuotes && hasTimeoutQuote && isTimeout && rateResult?.fallback
-                ? { ...(await rateResult.fallback), swapperName }
-                : rateResult
+            const isTimeout =
+              rateResult?.isErr() && rateResult.unwrapErr().code === TradeQuoteError.Timeout
+            let rateResultWithFallback = rateResult
+            if (noQuotes && hasTimeoutQuote && isTimeout && rateResult?.fallback) {
+              try {
+                rateResultWithFallback = { ...(await rateResult.fallback), swapperName }
+              } catch (_e) {
+                // keep original timed-out result; proceed without fallback
+              }
+            }

Optional (outside this hunk): wrap rateResult.fallback with a longer-but-finite timeout to avoid indefinite hangs (e.g., FALLBACK_RATE_TIMEOUT_MS = 30000) using your existing timeout helper.

Also applies to: 200-203

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 5dfe5ea and f153b55.

📒 Files selected for processing (3)
  • packages/swapper/src/swapper.ts (3 hunks)
  • packages/utils/src/timeout.ts (1 hunks)
  • src/state/apis/swapper/swapperApi.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/utils/src/timeout.ts
  • packages/swapper/src/swapper.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • src/state/apis/swapper/swapperApi.ts
**/swapper/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/swapper/**/*.{ts,tsx}: AVOID throwing within swapper API implementations; return Err() instead. UI layers may still throw (caught by React error boundaries).
ALWAYS use makeSwapErrorRight for swapper errors
ALWAYS use TradeQuoteError enum for error codes in swapper errors
ALWAYS provide detailed error information in swapper errors

Files:

  • src/state/apis/swapper/swapperApi.ts
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • src/state/apis/swapper/swapperApi.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • src/state/apis/swapper/swapperApi.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/*.{ts,tsx} : ALWAYS use timeoutMonadic for API calls
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use TradeQuoteError enum for error codes in swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Avoid side effects in swap logic within swapper implementation files.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
PR: shapeshift/web#10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Include comments explaining swap logic in swapper implementation files.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use makeSwapErrorRight for swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS provide detailed error information in swapper errors

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Leverage shared utilities (e.g., executeEvmTransaction, checkEvmSwapStatus) in swapper implementations when applicable.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : AVOID throwing within swapper API implementations; return Err() instead. UI layers may still throw (caught by React error boundaries).

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Verify chain ID filtering in filterAssetIdsBySellable and filterBuyAssetsBySellAssetId methods.

Applied to files:

  • src/state/apis/swapper/swapperApi.ts
🧬 Code graph analysis (1)
src/state/apis/swapper/swapperApi.ts (2)
src/state/apis/swapper/types.ts (1)
  • TradeQuoteError (39-39)
src/state/apis/swapper/helpers/swapperApiHelpers.ts (1)
  • processQuoteResultWithRatios (56-86)
⏰ 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: Call / Static
🔇 Additional comments (2)
src/state/apis/swapper/swapperApi.ts (2)

153-167: Good split: fetch all rates first, then process.

Using Promise.allSettled to stage results before processing is clear and keeps concurrency. LGTM.


177-183: Timeout detection logic is sound.

Checks for Timeout on fulfilled results only; that’s appropriate here.

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.

Make quote request not time out if we don't find any quotes

2 participants