Skip to content

Comments

Feat/pro 3203/lifi sdk implementation#298

Merged
RanaBug merged 5 commits intostagingfrom
feat/PRO-3203/lifi-sdk-implementation
May 8, 2025
Merged

Feat/pro 3203/lifi sdk implementation#298
RanaBug merged 5 commits intostagingfrom
feat/PRO-3203/lifi-sdk-implementation

Conversation

@RanaBug
Copy link
Collaborator

@RanaBug RanaBug commented May 7, 2025

Description

  • Lifi SDK implementation in the Exchange App

How Has This Been Tested?

  • Existing Unit Tests and Manual Testing

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Summary by CodeRabbit

  • New Features

    • Integrated LiFi SDK and Etherspot transaction kit for enhanced swap and cross-chain functionality.
    • Added support for retrieving and displaying token prices within token selection and swap flows.
  • Bug Fixes

    • Improved logic for removing individual transactions from a transaction batch.
  • Refactor

    • Unified swap offer handling to use LiFi SDK for all swap types.
    • Simplified and updated hooks to streamline fetching offers and preparing transactions.
    • Removed unused or redundant code related to previous swap asset fetching logic.
    • Cleaned URL parameters after setting receive token to improve user experience.
  • Tests

    • Enhanced test mocks for LiFi SDK and related hooks to ensure more realistic and complete test coverage.
    • Updated expected test data to include token price where relevant.
  • Chores

    • Added new dependencies: @etherspot/modular-sdk and @lifi/sdk.
    • Updated type definitions to support new swap and transaction structures.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 7, 2025

Walkthrough

This update integrates the LiFi SDK into the exchange application, refactoring swap offer retrieval and transaction preparation to use LiFi's APIs. It removes legacy Etherspot swap logic, updates token and offer types, and ensures price data is propagated throughout token selection and swap flows. Supporting test and type changes are included, along with dependency additions.

Changes

File(s) Change Summary
package.json Added @etherspot/modular-sdk and @lifi/sdk as dependencies.
src/apps/the-exchange/hooks/useOffer.tsx Refactored to use LiFi SDK for fetching swap offers and preparing transactions, removed Etherspot swap logic, added allowance checks, and exposed new methods for best offer and step transactions.
src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx Unified swap execution logic to use LiFi-based transactions, removed cross-chain offer preparation, and updated wallet address retrieval.
src/apps/the-exchange/components/EnterAmount/EnterAmount.tsx Updated to call useOffer without arguments, reflecting new hook signature.
src/apps/the-exchange/components/SwapReceiveCard/SwapReceiveCard.tsx
src/apps/token-atlas/components/TokensSlider/TokensSlider.tsx
Added price property to token selection logic and Redux dispatch payloads.
src/services/tokensData.ts Filtered API results to include only tokens/assets and added price property to token objects.
src/apps/token-atlas/types/types.tsx Added optional price property to SelectedTokenType.
src/apps/the-exchange/utils/types.tsx Updated SwapOffer to use only LiFi Route, added StepTransaction and StepType types, and adjusted imports.
src/apps/the-exchange/index.tsx Integrated Etherspot and LiFi SDK configuration, handling provider and chain switching logic.
src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx Added logic to remove a single transaction from a batch by chain, using new helper and batch state management.
src/apps/the-exchange/components/ExchangeAction/test/ExchangeAction.test.tsx
src/apps/the-exchange/components/EnterAmount/test/EnterAmount.test.tsx
src/apps/the-exchange/components/CardsSwap/test/CardSwap.test.tsx
Added and extended mocks for @lifi/sdk and related hooks/utilities, updated mock offer data for tests.
src/apps/token-atlas/components/TokensSlider/test/TokenSlider.test.tsx Updated test expectations to include price property in selected token assertions.
src/apps/the-exchange/hooks/usePillarSwapAssets.tsx Deleted unused hook for fetching Pillar Swap assets.

Sequence Diagram(s)

sequenceDiagram
    participant UI as User Interface
    participant EnterAmount as EnterAmount Component
    participant useOffer as useOffer Hook
    participant LiFiSDK as LiFi SDK
    participant ExchangeAction as ExchangeAction Component

    UI->>EnterAmount: User enters swap details
    EnterAmount->>useOffer: getBestOffer(params)
    useOffer->>LiFiSDK: getRoutes(params)
    LiFiSDK-->>useOffer: Returns available routes
    useOffer-->>EnterAmount: Returns best offer

    UI->>ExchangeAction: User confirms swap
    ExchangeAction->>useOffer: getStepTransactions(route, account)
    useOffer->>LiFiSDK: getStepTransaction for each step
    useOffer-->>ExchangeAction: Returns step transactions
    ExchangeAction->>Etherspot: Add transactions to batch and send
Loading

Possibly related PRs

Suggested reviewers

  • IAmKio
  • vignesha22

Poem

A bunny hops with SDKs anew,
LiFi and Etherspot—what a view!
Tokens now with prices gleam,
Swaps and steps a streamlined dream.
Old logic gone, new flows begin,
With every hop, more swaps to win!
🐇✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

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

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented May 7, 2025

Deploying x with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9531023
Status: ✅  Deploy successful!
Preview URL: https://f9c28ea8.x-e62.pages.dev
Branch Preview URL: https://feat-pro-3203-lifi-sdk-imple.x-e62.pages.dev

View logs

@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3203/lifi-sdk-implementation) May 7, 2025 16:32 Inactive
@RanaBug RanaBug self-assigned this May 7, 2025
@RanaBug RanaBug marked this pull request as ready for review May 7, 2025 16:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (5)
src/apps/the-exchange/components/SwapReceiveCard/SwapReceiveCard.tsx (1)

83-87: Good URL cleaning implementation

Cleaning the URL parameters after they've been processed is a good practice to prevent unintended reapplication if users refresh the page.

Consider adding a brief comment explaining the purpose of this URL cleaning for future maintainers:

  // clean the URL after the token has been set
+ // This prevents reapplication of parameters if user refreshes the page
  const url = new URL(window.location.href);
  url.searchParams.delete('asset');
  url.searchParams.delete('blockchain');
  window.history.replaceState({}, '', url.toString());
src/apps/the-exchange/index.tsx (1)

34-53: Secure configuration of LiFi SDK.

The LiFi SDK is configured correctly with proper integrator name, EVM provider, and API key. The implementation of switchChain is particularly well-done, creating a new wallet client with the correct chain configuration.

Consider adding error handling for the case when a chainId is not found in the supported chains list.

 switchChain: async (chainId) =>
   // Switch chain by creating a new wallet client
   createWalletClient({
     account: (provider as WalletClient).account,
     chain: supportedChains.find(
       (chain) => chain.id === chainId
-    ) as Chain,
+    ) as Chain || (() => {
+      console.error(`Chain with ID ${chainId} not supported`);
+      throw new Error(`Chain with ID ${chainId} not supported`);
+    })(),
     transport: http(),
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
   }) as any,
src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (1)

146-168: Clever workaround for removing individual transactions from batch.

The implementation creates a custom solution to remove a single transaction from a batch by removing all chain transactions and re-adding all except the one to remove.

While this works, it could be optimized to avoid unnecessary state updates:

 const removeOneTransaction = (transactionId: string, chainId: number) => {
-  // All transactions for this chain
-  const chainTransactions = globalTransactionsBatch.filter(
-    (tx) => tx.chainId === chainId
-  );
-  // Remove all transactions from UI state
-  chainTransactions.forEach((tx) => {
-    removeFromBatch(tx.id as string);
-  });
-
-  // Wait for state update
-  setTimeout(() => {
-    // Adding back all transactions except the one we wanted to remove
-    chainTransactions.forEach((tx) => {
-      if (tx.id !== transactionId) {
-        addToBatch(tx);
-      }
-    });
-  }, 0);
+  // Get all transactions for this chain except the one to remove
+  const chainTransactionsToKeep = globalTransactionsBatch.filter(
+    (tx) => tx.chainId === chainId && tx.id !== transactionId
+  );
+  
+  // Remove the specific transaction directly
+  removeFromBatch(transactionId);
+  
+  // If the transaction removal changes batch structure in ways that require rebuild,
+  // only then perform the full rebuild
+  if (chainTransactionsToKeep.length > 0 && needsRebuild(transactionId, chainId)) {
+    // Remove all remaining transactions for this chain
+    chainTransactionsToKeep.forEach((tx) => {
+      removeFromBatch(tx.id as string);
+    });
+    
+    // Re-add all transactions to keep
+    setTimeout(() => {
+      chainTransactionsToKeep.forEach((tx) => {
+        addToBatch(tx);
+      });
+    }, 0);
+  }
 };

Note: The needsRebuild function would need to be implemented based on your specific requirements for when a full batch rebuild is necessary.

src/apps/the-exchange/hooks/useOffer.tsx (2)

79-109: Enhance error logging in isAllowanceSet

The error message in the catch block is generic. Consider adding more context to help with debugging.

- console.error('Failed to check token allowance:', error);
+ console.error(`Failed to check token allowance for token ${tokenAddress} on chain ${chainId}:`, error);

128-141: Simplify the allowance check logic

The complex condition for checking if the token has enough allowance could be refactored for better readability.

- const isEnoughAllowance = isAllowance
-   ? formatUnits(isAllowance, step.action.fromToken.decimals) >=
-     formatUnits(
-       BigInt(step.action.fromAmount),
-       step.action.fromToken.decimals
-     )
-   : undefined;
-
- // Here we are checking if this is not a native/gas token and if the allowance
- // is not set, then we manually add an approve transaction
- if (
-   !isZeroAddress(step.action.fromToken.address) &&
-   !isEnoughAllowance
- ) {
+ // If token is not native and needs approval (no allowance or insufficient allowance)
+ const needsApproval = !isZeroAddress(step.action.fromToken.address) && (
+   !isAllowance || 
+   formatUnits(isAllowance, step.action.fromToken.decimals) < 
+   formatUnits(BigInt(step.action.fromAmount), step.action.fromToken.decimals)
+ );
+
+ if (needsApproval) {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a7fa2fe and a3cc810.

⛔ Files ignored due to path filters (5)
  • package-lock.json is excluded by !**/package-lock.json
  • src/apps/pillarx-app/components/MediaGridCollection/tests/__snapshots__/DisplayCollectionImage.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/PointsTile/test/__snapshots__/PointsTile.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokensWithMarketDataTile/test/__snapshots__/TokensWithMarketDataTile.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (16)
  • package.json (1 hunks)
  • src/apps/the-exchange/components/CardsSwap/test/CardSwap.test.tsx (1 hunks)
  • src/apps/the-exchange/components/EnterAmount/EnterAmount.tsx (1 hunks)
  • src/apps/the-exchange/components/EnterAmount/test/EnterAmount.test.tsx (1 hunks)
  • src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx (4 hunks)
  • src/apps/the-exchange/components/ExchangeAction/test/ExchangeAction.test.tsx (3 hunks)
  • src/apps/the-exchange/components/SwapReceiveCard/SwapReceiveCard.tsx (1 hunks)
  • src/apps/the-exchange/hooks/useOffer.tsx (2 hunks)
  • src/apps/the-exchange/hooks/usePillarSwapAssets.tsx (0 hunks)
  • src/apps/the-exchange/index.tsx (2 hunks)
  • src/apps/the-exchange/utils/types.tsx (2 hunks)
  • src/apps/token-atlas/components/TokensSlider/TokensSlider.tsx (1 hunks)
  • src/apps/token-atlas/components/TokensSlider/test/TokenSlider.test.tsx (1 hunks)
  • src/apps/token-atlas/types/types.tsx (1 hunks)
  • src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (3 hunks)
  • src/services/tokensData.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/apps/the-exchange/hooks/usePillarSwapAssets.tsx
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx (1)
src/services/tokensData.ts (1)
  • chainNameToChainIdTokensData (237-258)
src/apps/the-exchange/index.tsx (2)
src/apps/the-exchange/hooks/useReducerHooks.tsx (1)
  • useAppSelector (6-6)
src/utils/blockchain.ts (1)
  • supportedChains (139-148)
src/apps/the-exchange/components/ExchangeAction/test/ExchangeAction.test.tsx (1)
src/apps/the-exchange/utils/types.tsx (1)
  • SwapOffer (23-26)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (27)
src/apps/token-atlas/types/types.tsx (1)

22-22: Good addition of price property to SelectedTokenType

The addition of the optional price property to the SelectedTokenType interface is appropriate and aligns with the Lifi SDK integration. Using the optional modifier ensures backward compatibility.

src/apps/token-atlas/components/TokensSlider/TokensSlider.tsx (1)

126-126: LGTM - Price property handling looks good

The implementation correctly handles the token price, with a proper fallback to 0 when the price data is unavailable.

src/apps/token-atlas/components/TokensSlider/test/TokenSlider.test.tsx (1)

137-137: Good test update for price property

The test has been properly updated to include the price property with the default value, maintaining test consistency with the implementation changes.

src/apps/the-exchange/components/SwapReceiveCard/SwapReceiveCard.tsx (1)

79-79: LGTM - Consistent price propagation

The price property from the selected token is properly included in the payload, maintaining consistency with the other components in the price data flow.

src/services/tokensData.ts (1)

281-343: Good implementation of token price propagation.

The changes correctly filter API responses to only include 'token' or 'asset' types before processing, and add the price property from the original item to the token objects. This properly aligns with the LiFi SDK integration requirements, ensuring that price data is available throughout the token selection and swap flows.

The implementation maintains all the existing token filtering logic while adding the necessary price data in a clean, non-disruptive way.

package.json (1)

22-25: New dependencies added for LiFi integration

The addition of @etherspot/modular-sdk and @lifi/sdk supports the implementation of the LiFi SDK in the exchange app as described in the PR objectives.

src/apps/the-exchange/components/EnterAmount/test/EnterAmount.test.tsx (1)

73-78: Well-structured LiFi SDK mock for tests

The mock correctly simulates the LiFi SDK's core methods that would be used in the application, allowing tests to run without making actual API calls.

src/apps/the-exchange/components/CardsSwap/test/CardSwap.test.tsx (1)

137-142: Consistent LiFi SDK mocking across test files

This mock matches the implementation in other test files, ensuring consistent test behavior across components that utilize the LiFi SDK.

src/apps/the-exchange/components/EnterAmount/EnterAmount.tsx (2)

102-132: Verify all needed parameters are passed to getBestOffer

The implementation correctly creates the params object with all necessary details for the LiFi SDK transaction, including token addresses, chain IDs, and decimals from both source and destination tokens.


65-65:

Details

❌ Incorrect review comment

Updated useOffer hook signature

The parameter has been removed from the useOffer hook call, reflecting the refactored implementation that likely now sources chain information directly from Redux state.


🏁 Script executed:

#!/bin/bash
# Verifying the updated useOffer hook signature
# Let's check how the useOffer hook is defined now

# Look for the useOffer hook definition
rg -A 10 "export default function useOffer" src/apps/the-exchange/hooks/

Length of output: 74


I couldn’t locate the useOffer definition with the initial pattern. Let’s search more broadly across the repo for how it’s declared:

This will help us verify the new hook signature.


🏁 Script executed:

#!/bin/bash
# Broad search for useOffer declaration across the repo
rg -n "function useOffer" -C 3 src
rg -n "const useOffer" -C 3 src
rg -n "export .*useOffer" -C 3 src

Length of output: 852


Let’s inspect the useOffer implementation to confirm it now sources chain info internally:


🏁 Script executed:

#!/bin/bash
# Check for Redux selectors or internal chain resolution in useOffer
rg -n "useSelector" -C 3 src/apps/the-exchange/hooks/useOffer.tsx
rg -n "useAppSelector" -C 3 src/apps/the-exchange/hooks/useOffer.tsx
# See where getNetworkViem is called
rg -n "getNetworkViem" -C 3 src/apps/the-exchange/hooks/useOffer.tsx
# Search for any direct “chain” references
rg -n "chain" -C 4 src/apps/the-exchange/hooks/useOffer.tsx

Length of output: 3137


Updated useOffer hook signature
The useOffer hook no longer accepts any arguments. It now returns helper methods (e.g. getBestOffer, isAllowanceSet) that each expect a chainId (and other params) when you call them.

• Ensure all calls to getBestOffer({ … }) and isAllowanceSet({ … }) pass the correct chainId in their argument objects.
• No Redux selectors are used inside useOffer; chain IDs are provided per-call rather than pulled from state.

Likely an incorrect or invalid review comment.

src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx (4)

2-2: Good refactoring to use the LiFi SDK integration.

The addition of useWalletAddress from the Etherspot transaction kit and updating the hook usage to access getStepTransactions from useOffer sets up the component properly for the new LiFi SDK integration.

Also applies to: 17-17, 53-54


93-96: LGTM: Transaction preparation using LiFi SDK.

The implementation correctly retrieves step transactions for the current offer, passing the wallet address in the right format with TypeScript type safety.


98-117: Handle empty or undefined step transactions before the loop.

The code assumes stepTransactions will be an array when entering the loop at line 100, but there's no explicit check that it's non-empty beyond the if (stepTransactions) check.

Add an additional check before the loop to ensure stepTransactions is non-empty:

 if (stepTransactions) {
+  if (stepTransactions.length === 0) {
+    setErrorMessage('No transactions to process. Please try again.');
+    setIsAddingToBatch(false);
+    return;
+  }
   // eslint-disable-next-line no-plusplus
   for (let i = 0; i < stepTransactions.length; ++i) {

101-102: Verify properties on step transactions.

The implementation correctly extracts value, data, and to from step transactions. Consider using optional chaining for safer access to potentially undefined properties.

Also applies to: 108-109, 115-116

src/apps/the-exchange/index.tsx (1)

2-4: Good integration of Etherspot and LiFi.

The imports of necessary modules from Etherspot transaction kit and LiFi SDK are appropriate for the SDK integration.

Also applies to: 26-26

src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (2)

42-46: LGTM: Enhanced batch management hooks.

The addition of addToBatch alongside other functions from useGlobalTransactionsBatch provides a complete set of batch management capabilities.


225-229: Good update to use the new removal function.

The replacement of the direct removeFromBatch call with the new removeOneTransaction function correctly implements the more robust transaction removal approach.

src/apps/the-exchange/utils/types.tsx (4)

2-3: LGTM: Updated imports for the LiFi SDK integration.

The change from @lifi/types to @lifi/sdk for the Route type and addition of Hex from viem are appropriate for the SDK integration.


25-25: Good type narrowing for offer property.

Restricting the offer property to only the Route type from LiFi SDK improves type safety by removing the previous union type with ExchangeOffer.


33-42: Well-defined transaction type structure.

The StepTransaction type clearly defines the structure needed for blockchain transactions, with appropriate optional properties.


44-44: Good enumeration of step types.

The StepType union type provides a clear enumeration of all possible step categories, which will help with type checking throughout the application.

src/apps/the-exchange/components/ExchangeAction/test/ExchangeAction.test.tsx (3)

53-86: Greatly improved mock data structure!

The detailed mockBestOffer object now accurately represents the LiFi SDK's Route structure, providing a more realistic testing scenario. The inclusion of comprehensive fields like token details, price information, and the insurance object will make tests more robust.

🧰 Tools
🪛 Biome (1.9.4)

[error] 52-86: Do not export from a test file.

(lint/suspicious/noExportsInTest)


99-104: Good addition of required mocks

These mock implementations for useEtherspotUtils and useWalletAddress provide the necessary stubs for testing the component with the LiFi integration.


114-119: LiFi SDK mock implementation looks good

The mock for the LiFi SDK correctly stubs out the asynchronous methods that would be used in the component, ensuring tests can run in isolation from external dependencies.

src/apps/the-exchange/hooks/useOffer.tsx (3)

1-8: LGTM! Great SDK integration

The import of LiFi SDK components looks good - you're importing only the specific functions and types needed for this implementation.


10-16: Good use of viem library

The switch to using viem for blockchain interactions is a good choice, as it provides a more modern and type-safe API compared to alternatives.


118-120:

Details

❌ Incorrect review comment

Address ESLint disabled rules

Multiple ESLint rules are disabled in the code, which may indicate potential issues with the code structure. The no-restricted-syntax rule for the for-of loop and no-await-in-loop suggest that there might be a better way to structure this code.

Consider refactoring to use Promise.all() for parallel execution of steps that don't depend on each other:

// Example approach (conceptual)
const stepPromises = await Promise.all(
  route.steps.map(async (step) => {
    const transactions = [];
    const isAllowance = await isAllowanceSet({...});
    
    // Add approval transaction if needed
    if (needsApproval(step, isAllowance)) {
      transactions.push(createApprovalTransaction(step));
    }
    
    // Add swap transaction
    const updatedStep = await getStepTransaction(prepareStep(step, fromAccount));
    if (updatedStep.transactionRequest) {
      transactions.push(createSwapTransaction(updatedStep));
    }
    
    return transactions;
  })
);

return stepPromises.flat();

Is sequential processing of steps necessary for LiFi swaps? Let's verify:


🌐 Web query:

Does LiFi SDK require steps to be processed sequentially or can they be processed in parallel?

💡 Result:

Based on the LI.FI SDK documentation, steps within a route must be executed sequentially rather than in parallel. When executing a route, each step depends on the outcome of the previous one, making sequential execution necessary for the process to work correctly[6].

The documentation specifically states: "Each step should be executed sequentially, as each step depends on the outcome of the previous one"[6]. This sequential requirement exists because later steps in a cross-chain transfer or swap operation typically rely on the successful completion of earlier steps, ensuring the integrity of the entire transaction flow.

It's important to note that while the steps themselves must be executed in sequence, LI.FI as a technology does support certain parallel capabilities in other contexts. For example, when using the getStepTransaction function to prepare transaction data for execution, developers need to handle each step one after another in the correct order[6].

In contrast, quote objects are returned with transaction data already included, so they don't require the additional getStepTransaction call and can be executed immediately, though still in the proper sequence[6].

This sequential approach ensures reliability in cross-chain operations, especially when bridging between different blockchain networks where transaction confirmation on one chain may be a prerequisite for operations on another chain.

Citations:


Sequential execution is required – suppressing ESLint rules is intentional

The LiFi SDK documentation specifies that each step in a route must be executed one after another, as each step depends on the outcome of the previous one. Therefore, using await inside a loop and disabling no-restricted-syntax/no-await-in-loop here is appropriate. To make this clear to future readers, you can consolidate and annotate the disables:

// LiFi SDK requires sequential execution of steps
// eslint-disable-next-line no-restricted-syntax, no-await-in-loop
for (const step of route.steps) {
  // …
}

Likely an incorrect or invalid review comment.

@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3203/lifi-sdk-implementation) May 8, 2025 09:31 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
src/apps/the-exchange/hooks/useOffer.tsx (4)

73-79: Improve error handling in getBestOffer

The current implementation returns an empty object cast as SwapOffer when an error occurs. This could lead to runtime errors if the consuming code expects all SwapOffer properties to be present.

Consider returning a more explicit error indication or defined default values:

- return {} as SwapOffer;
+ return {
+   tokenAmountToReceive: 0,
+   offer: {
+     id: '',
+     fromChainId: fromChainId,
+     toChainId: toChainId,
+     fromAmount: '0',
+     toAmount: '0',
+     fromToken: { address: fromTokenAddress, chainId: fromChainId, decimals: fromTokenDecimals, symbol: '', name: '' },
+     toToken: { address: toTokenAddress, chainId: toChainId, decimals: toTokenDecimals, symbol: '', name: '' },
+     steps: []
+   }
+ };

148-180: Use imported erc20Abi instead of hardcoding the ABI

You're importing erc20Abi but not using it for the approval transaction. Using the imported ABI would be more maintainable.

- const calldata = encodeFunctionData({
-   abi: [
-     {
-       inputs: [
-         {
-           internalType: 'address',
-           name: 'spender',
-           type: 'address',
-         },
-         {
-           internalType: 'uint256',
-           name: 'value',
-           type: 'uint256',
-         },
-       ],
-       name: 'approve',
-       outputs: [
-         {
-           internalType: 'bool',
-           name: '',
-           type: 'bool',
-         },
-       ],
-       stateMutability: 'nonpayable',
-       type: 'function',
-     },
-   ],
-   functionName: 'approve',
-   args: [
-     step.estimate.approvalAddress as `0x${string}`,
-     BigInt(step.estimate.fromAmount),
-   ],
+ const calldata = encodeFunctionData({
+   abi: erc20Abi,
+   functionName: 'approve',
+   args: [
+     step.estimate.approvalAddress as `0x${string}`,
+     BigInt(step.estimate.fromAmount),
+   ],

213-224: Add guards for optional transaction parameters

When extracting values from updatedStep.transactionRequest, there's no check if properties like gasLimit or gasPrice are defined. This could lead to runtime errors if they're undefined.

- const { to, data, value, gasLimit, gasPrice, chainId, type } =
-   updatedStep.transactionRequest;
-
- stepTransactions.push({
-   to,
-   data: data as `0x${string}`,
-   value: BigInt(`${value}`),
-   gasLimit: BigInt(`${gasLimit}`),
-   gasPrice: BigInt(`${gasPrice}`),
-   chainId,
-   type,
- });
+ const { to, data, value, gasLimit, gasPrice, chainId, type } =
+   updatedStep.transactionRequest;
+
+ stepTransactions.push({
+   to,
+   data: data as `0x${string}`,
+   value: value ? BigInt(`${value}`) : BigInt(0),
+   ...(gasLimit && { gasLimit: BigInt(`${gasLimit}`) }),
+   ...(gasPrice && { gasPrice: BigInt(`${gasPrice}`) }),
+   chainId,
+   ...(type && { type }),
+ });

226-228: Improve error handling in getStepTransactions

The catch block only logs errors but doesn't provide any indication to the caller that something went wrong. Consider adding more context and returning some information about the failure.

  } catch (error) {
    console.error('Failed to get step transactions:', error);
+   // Consider adding some error state to the return value
+   // or throwing a more specific error with context
  }
🧹 Nitpick comments (2)
src/apps/the-exchange/hooks/useOffer.tsx (2)

39-52: Consider making bridge filter options configurable

The bridge deny list is currently hardcoded. Making these options configurable would provide more flexibility and potentially better swap results in different scenarios.

 const routesRequest: RoutesRequest = {
   fromChainId,
   toChainId,
   fromTokenAddress,
   toTokenAddress,
   fromAmount: `${parseUnits(`${fromAmount}`, fromTokenDecimals)}`,
   options: {
     bridges: {
-      deny: ['across', 'multichain', 'hyphen', 'hop'],
+      deny: bridgesDenyList || ['across', 'multichain', 'hyphen', 'hop'],
     },
   },
 };

124-139: Consider optimizing sequential async operations in the loop

The current implementation has sequential async calls within a loop, which can be slow for routes with many steps. Consider using Promise.all to parallelize when possible.

-      // eslint-disable-next-line no-restricted-syntax
-      for (const step of route.steps) {
-        // eslint-disable-next-line no-await-in-loop
-        const isAllowance = await isAllowanceSet({
-          owner: fromAccount,
-          spender: step.estimate.approvalAddress,
-          tokenAddress: step.action.fromToken.address,
-          chainId: step.action.fromChainId,
-        });
+      // Prepare allowance check requests for all steps
+      const allowancePromises = route.steps.map(step => 
+        isAllowanceSet({
+          owner: fromAccount,
+          spender: step.estimate.approvalAddress,
+          tokenAddress: step.action.fromToken.address,
+          chainId: step.action.fromChainId,
+        })
+      );
+      
+      // Execute all allowance checks in parallel
+      const allowances = await Promise.all(allowancePromises);
+      
+      // Process each step with its corresponding allowance result
+      for (let i = 0; i < route.steps.length; i++) {
+        const step = route.steps[i];
+        const isAllowance = allowances[i];

Note: This optimization may need to be adapted based on your specific requirements. The subsequent transaction processing would still need to be sequential since each transaction might depend on the previous one.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a3cc810 and 9531023.

⛔ Files ignored due to path filters (2)
  • src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokensWithMarketDataTile/test/__snapshots__/TokensWithMarketDataTile.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx (4 hunks)
  • src/apps/the-exchange/hooks/useOffer.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/apps/the-exchange/components/ExchangeAction/ExchangeAction.tsx
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
  • GitHub Check: Cloudflare Pages

Copy link
Collaborator

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

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

Just a note but it's not a show stopper, LGTM

@RanaBug RanaBug merged commit 7adb48b into staging May 8, 2025
7 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 26, 2025
3 tasks
@coderabbitai coderabbitai bot mentioned this pull request Sep 16, 2025
3 tasks
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.

2 participants